JMeter Assertion : Error when comparing variables - groovy

I am trying to assert my API response data with a value I obtained from my Database.
My code fails to compare my variables unless I add toString() to both my variable. Is there any way around it or is toString() mandatory?
The code in question is :
Boolean comparision = false;
for (int i; i < vars.getObject("dbData").size(); i++) {
if (vars.getObject("dbData").get(i).get("DbData").toString().equals(${codeid_API}.toString()))
{
comparision = true;
}
}
${codeid_API} is the variable where I stored my API response data.
(vars.getObject("dbData").get(i).get("DbData") gets the value from my DB.

You can use Objects.equals instead
Objects.equals(vars.getObject("dbData").get(i).get("DbData"), ${codeid_API});
Returns true if the arguments are equal to each other and false otherwise.
For integer you can compare using == and use as int for casting
if (vars.getObject("dbData").get(i).get("DbData") as int == vars.get("codeid_API") as int );

Don't inline JMeter variables in form of ${codeid_API} into Groovy scripts, in case of enabled compiled scripts caching it will be resolved only once and it might break your script logic.
Consider replacing it with vars.get('codeid_API) instead where vars is the shorthand for JMeterVariables class instance
Quote from JSR223 Sampler documentation:
JMeter processes function and variable references before passing the script field to the interpreter, so the references will only be resolved once. Variable and function references in script files will be passed verbatim to the interpreter, which is likely to cause a syntax error. In order to use runtime variables, please use the appropriate props methods, e.g.
props.get("START.HMS");
props.put("PROP1","1234");
More information: Debugging JDBC Sampler Results in JMeter

Related

How to set a puppet class variable from within a hiera_hash each loop?

hiera data
ae::namespace_by_fqdn_pattern:
'((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((client))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com': '/test/blah/regression/client'
'((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((server))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com': '/test/blah/regression/server'
class
class ae {
$namespace = hiera('ae::namespace')
$target_host_patterns = hiera('ae::target_host_patterns')
hiera_hash('ae::namespace_by_fqdn_pattern').each |String $pattern, String $ns| {
if $facts['networking']['fqdn'].match($pattern) {
$ae::namespace = "${ns}"
}
}
<snip>
... yields
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Illegal attempt to assign to 'ae::enforcerd_namespace'. Cannot assign to variables in other namespaces (file: /etc/puppetlabs/code/environments/ar/modules/ae/manifests/init.pp, line: 21, column: 13) on node dfw-ubuntu1604-client02.pp-devcos.us-central1.gcp.dev.blah.com
... anyone here know how to do this correctly? trying to conditionally override that $ae::namespace variable but i'm too puppet-ignorant to know how to get it working : (
the loop and the pattern matching bits work. just can't figure out how to correctly set that class variable from within the hiera_hash().each loop.
How to set a puppet class variable from within a hiera_hash each loop?
You cannot. The associated block of an each() call establishes a local scope for each iteration. Variable assignments within apply to that local scope, and therefore last only for the duration of one execution of the block. You cannot anyway assign a new value to a variable during its lifetime, so even if you could assign to a class variable from within an each() call, it would be difficult to use that capability (and your approach would not work).
There are several ways you could approach the problem without modifying the form of the data. You could leverage the filter() function, for example, but my personal recommendation would be to use the reduce() function, something like this:
$namespace = lookup('ae::target_host_patterns').reduce(lookup('ae::namespace')) |$ns, $entry| {
$facts['networking']['fqdn'].match($entry[0]) ? { true => $entry[1], default => $ns }
}
That does pretty much exactly what your original code seems to be trying to do, except that the selected namespace is returned by the reduce() call, to be assigned to a variable by code at class scope, instead of the lambda trying to assign it directly. Note also that it takes care not only of testing the patterns but of assigning the default namespace when none of the patterns match, as it needs to do because you can only assign to the namespace variable once.
so the solution i landed on was to change the hiera data to:
ae::namespace : '/test/blah/regression'
ae::namespace_patterns: ['((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((client))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com', '((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((server))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com']
ae::namespace_by_pattern:
'((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((client))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com': '/test/paypal/regression/client'
'((^dfw-oel6)|(^dfw-oel7)|(^dfw-ubuntu1604))-((server))([0-9]{2}).pp-devcos-ae.us-central1.gcp.dev.blah.com': '/test/paypal/regression/server'
then the class code to:
$pattern = hiera_hash('ae::namespace_patterns').filter |$pattern| {
$facts['networking']['fqdn'] =~ $pattern
}
if length($pattern) {
$namespace = hiera('ae::namespace_by_pattern')[$pattern[0]]
} else {
$namespace = hiera('ae::namespace')
}
definitely still open to better answers. just what my own hacking produced as workable so far through much trial and error.

Is it possible to get the name of variable in Groovy?

I would like to know if it is possible to retrieve the name of a variable.
For example if I have a method:
def printSomething(def something){
//instead of having the literal String something, I want to be able to use the name of the variable that was passed
println('something is: ' + something)
}
If I call this method as follows:
def ordinary = 58
printSomething(ordinary)
I want to get:
ordinary is 58
On the other hand if I call this method like this:
def extraOrdinary = 67
printSomething(extraOrdinary)
I want to get:
extraOrdinary is 67
Edit
I need the variable name because I have this snippet of code which runs before each TestSuite in Katalon Studio, basically it gives you the flexibility of passing GlobalVariables using a katalon.features file. The idea is from: kazurayam/KatalonPropertiesDemo
#BeforeTestSuite
def sampleBeforeTestSuite(TestSuiteContext testSuiteContext) {
KatalonProperties props = new KatalonProperties()
// get appropriate value for GlobalVariable.hostname loaded from katalon.properties files
WebUI.comment(">>> GlobalVariable.G_Url default value: \'${GlobalVariable.G_Url}\'");
//gets the internal value of GlobalVariable.G_Url, if it's empty then use the one from katalon.features file
String preferedHostname = props.getProperty('GlobalVariable.G_Url')
if (preferedHostname != null) {
GlobalVariable.G_Url = preferedHostname;
WebUI.comment(">>> GlobalVariable.G_Url new value: \'${preferedHostname}\'");
} else {
WebUI.comment(">>> GlobalVariable.G_Url stays unchanged");
}
//doing the same for other variables is a lot of duplicate code
}
Now this only handles 1 variable value, if I do this for say 20 variables, that is a lot of duplicate code, so I wanted to create a helper function:
def setProperty(KatalonProperties props, GlobalVariable var){
WebUI.comment(">>> " + var.getName()" + default value: \'${var}\'");
//gets the internal value of var, if it's null then use the one from katalon.features file
GlobalVariable preferedVar = props.getProperty(var.getName())
if (preferedVar != null) {
var = preferedVar;
WebUI.comment(">>> " + var.getName() + " new value: \'${preferedVar}\'");
} else {
WebUI.comment(">>> " + var.getName() + " stays unchanged");
}
}
Here I just put var.getName() to explain what I am looking for, that is just a method I assume.
Yes, this is possible with ASTTransformations or with Macros (Groovy 2.5+).
I currently don't have a proper dev environment, but here are some pointers:
Not that both options are not trivial, are not what I would recommend a Groovy novice and you'll have to do some research. If I remember correctly either option requires a separate build/project from your calling code to work reliable. Also either of them might give you obscure and hard to debug compile time errors, for example when your code expects a variable as parameter but a literal or a method call is passed. So: there be dragons. That being said: I have worked a lot with these things and they can be really fun ;)
Groovy Documentation for Macros
If you are on Groovy 2.5+ you can use Macros. For your use-case take a look at the #Macro methods section. Your Method will have two parameters: MacroContext macroContext, MethodCallExpression callExpression the latter being the interesting one. The MethodCallExpression has the getArguments()-Methods, which allows you to access the Abstract Syntax Tree Nodes that where passed to the method as parameter. In your case that should be a VariableExpression which has the getName() method to give you the name that you're looking for.
Developing AST transformations
This is the more complicated version. You'll still get to the same VariableExpression as with the Macro-Method, but it'll be tedious to get there as you'll have to identify the correct MethodCallExpression yourself. You start from a ClassNode and work your way to the VariableExpression yourself. I would recommend to use a local transformation and create an Annotation. But identifying the correct MethodCallExpression is not trivial.
no. it's not possible.
however think about using map as a parameter and passing name and value of the property:
def printSomething(Map m){
println m
}
printSomething(ordinary:58)
printSomething(extraOrdinary:67)
printSomething(ordinary:11,extraOrdinary:22)
this will output
[ordinary:58]
[extraOrdinary:67]
[ordinary:11, extraOrdinary:22]

Parameterizing Objects in spock

I have a problem with parameterizations of list of object by using spock where block. It seems the ListInput value is not taking from the where clause and always coming null value. I have verified the same feature for string and other primitive types and it is working fine.
Does Spock support parameterizations objects ? If yes what is the issue here .
def "check Param Of List of Objects"()
{
expect:
def a= hasflag(ListInput);
a== flag
where:
ListInput | flag
BOList1 | true
BOList2 | false
}
Here the type of BOList1 is an java ArrayList contains the object
You haven't really provided enough information for a definitive answer but I'll try to help.
The where block isn't exactly just a block of code, it's more like a number of parameters passed to a method. It can do a lot, but sometimes you need to pass your code a little differently.
Of note:
- Void methods aren't allowed (but you can get around this using .with{} )
- An iterative parameter cannot also be a derived parameter (constructed from other parameters)
- If you're referencing class level variables (defined within the class but outside this test) they need to be given the #Shared annotation for your tests to have access.
Given more information about where your lists are coming from will help me give better advice.
Final tip; explicitly typecast your parameters to see if that gives you anymore information
def "check Param Of List of Objects"(ArrayList listInput, boolean flag) {
expect:
flag == hasflag(ListInput);
where:
listInput | flag
BOList1 | true
BOList2 | false
}

Jenkins boolean parameter is always true in groovy

I have a Jenkins job that calls a groovy script and the groovy script uses Jenkins parameters to do it's work. I can retrieve all the parameters without a problem except for a boolean parameter. The boolean parameter is a checkbox in Jenkins
I read the jenkins parameter into Groovy as follows:
boolean libraryBranch = config.get('library_branch_feature');
Now when I print the 'libraryBranch' variable
out.println "-- Library branch feature?: " + libraryBranch.toString();
I get the following printed line:
-- Library branch feature ?: true
So it doesn't matter if the boolean Jenkins parameter is selected or not I always have a boolean value 'true' in Groovy. All other (string) parameters inside the same job are read without a problem.
Can someone help me with this issue?
EDIT
Ok I've decided to try and retrieve the code in a couple of other ways and tyring to find a good solution:
Boolean libraryBranch = build.buildVariableResolver.resolve("library_branch_feature");
String libraryBranchString = build.buildVariableResolver.resolve("library_branch_feature").toString();
Boolean libraryBranchStringAsBoolean = build.buildVariableResolver.resolve("library_branch_feature") as Boolean;
The above variables are then printed:
out.println "-- Library branch feature?: " + libraryBranch;
out.println "-- Library branch feature to String: " + libraryBranch.toString();
out.println "-- Library branch feature to String: " + libraryBranch.toString();
out.println "-- Library branch feature as String: " + libraryBranchString;
out.println "-- Library branch feature String as Boolean: " + libraryBranchStringAsBoolean;
The output of the above prints are posted below:
-- Library branch feature?: true
-- Library branch feature to String: true
-- Library branch feature to String: true
-- Library branch feature as String: false
-- Library branch feature String as Boolean: true
So the only way thus far to have the boolean value read correctly as a false is by not turning it into a boolean at all but just reading it as a string and use it as a string.
I would rather use it as a boolean though so any suggestions on the matter is still appreciated.
The answer is to read the Jenkins parameter as String and then convert it to a boolean using the method .toBoolean(); So my libraryBranch is now set as follows:
boolean libraryBranch = build.buildVariableResolver.resolve("library_branch_feature").toString().toBoolean();
Just out of curiosity, I tried the following:
Set the variable 'testmode' as a boolean in the pipeline setup.
Start the job, with testmode set false (unchecked).
In the pipeline script, run the following code immediately upon entry:
testmode=testmode.toBoolean()
if (testmode==false) { print "testmode tests true"}else{print "testmode tests false"}
you will see the result 'testmode tests false'.
To verify my claim that the 'boolean' variable testmode is ACTUALLY a string when it comes in, I tried:
testmode=testmode.toBoolean()
testmode=testmode.toBoolean()
and it blew up on the 2nd 'toBoolean'. I'll spare you the error message...
So, I claim that testmode comes in as the string "false" instead of as a boolean (whether because of promotion, demotion, forcing, whatever).
So, if its a boolean parameter, and you really wanted to treat it like a boolean and not have to say 'if (booleanvar=="true")', then convert it to a boolean as above and you're done.
The question and the answers are a bit dated. The modern method to
consume a boolean parameter is to use the params. global values. params
properly exposes Boolean parameters such that the following both work and
require no string/boolean conversions.
if (params.library_branch_feature) {
// truth logic here
}
// or
if (params.library_branch_feature != false) {
// truth logic here
}
From the Pipeline Syntax for params.:
Exposes all parameters defined in the build as a read-only map with variously typed values. Example:
if (params.BOOLEAN_PARAM_NAME) {doSomething()}
or to supply a nontrivial default value:
if (params.getOrDefault('BOOLEAN_PARAM_NAME', true)) {doSomething()}
NOTE:
It may not make sense that a boolean parameter can have NO value,
but '.getOrDefault()' is useful to set default values for string parameters.
I encountered the same problem with reading java Properties - retrieved boolean values are always true. So, say I have a settings file with property debugging=false. This test will fail:
class ConfigurationTest extends GroovyTestCase {
void testProcessConfiguration() {
Properties properties=new Properties()
FileReader fileReader=new FileReader('settings')
properties.load(fileReader)
boolean debug=properties.getOrDefault('debugging',false)
assert !debug
fileReader.close()
}
}
But if you make it properties.getOrDefault('debugging',false).toString().toBoolean() it will return correct value. Probably this is because of coercion?

Can I redefine String#length?

I'd like to re-implement a method of a Java class. For example, for "hi".length() to return 4. (How) Can I do that?
I know using SomeClass.metaClass I can get a reference to an existing method and define new (or overriding) method, but I can't seem to be able to do that for existing Java methods.
Using Groovy, you can replace any method (even those of final classes) with your own implementation. Method replacement in Groovy uses the meta-object protocol, not inheritance.
Here's the example you requested, i.e. how to make String.length() always return 4
// Redefine the method
String.metaClass.invokeMethod = { name, args ->
def metaMethod = delegate.metaClass.getMetaMethod(name, args)
def result = metaMethod.invoke(delegate, args)
name == 'length' ? 4 : result
}
// Test it
assert "i_do_not_have_4_chars".length() == 4
Seems like it could be possible by abusing String metaClass. But the attempt I've done so far in groovy console didn't led to the expected result :
def oldLength = String.metaClass.length
String.metaClass.length = { ->
return oldLength+10;
}
println "hi".length()
outputs the sad 2
I think you could take a look at Proxy MetaClass or Delegating metaClass.
If you did redefine it, it would only work in Groovy code. Groovy can't change the way Java code executes.
In Groovy, "hi".length() is roughly equivalent to this Java:
stringMetaClass.invokeMethod("hi","length");
Because Groovy doesn't actually call length directly, metaClass tricks work in Groovy code. But Java doesn't know about MetaClasses, so there is no way to make this work.
Although this question is very old I like to point out another way (at least for newer Groovy versions) .
The length() method in java.lang.String is implemented from java.lang.CharSequence interface. In order to reimplement the method using the String-metaClass you need to "override" the method in the metaClass of the interface first.
CharSequence.metaClass.length = { -> -1}
String.metaClass.length = { -> 4 }
assert "i_do_not_have_4_chars".length() == 4
The solution using String.metaClass.invokeMethod changes the behaviour of all String-methods and is problematic. For instance, simply invoking "asdf".size() leads to an exception on my setup.

Resources