Groovy DSL non-deterministic behavior - groovy

I'm using groovyConsole to see the generated class code of the following two Groovy scripts:
process test{
output:
file 'output.txt' into b, c
"""
echo hello
"""
}
Here is its generated code:
And here is the second script that differs from the previous one - this one uses parentheses in file() method invocation:
process test{
output:
file('output.txt') into b, c
"""
echo hello
"""
}
And this is generated code from the second script:
As you can see, process is no longer a function but a variable. It confuses me because I would expect that in both cases process should be seen as a function call. Is this an expected behavior? Do I miss something?

Related

how to share data between groovy files?

I have one common groovy file that contains few const variables and functions...
and I also have more groovy files with pipelineJob that use the variables and functions from the common file
what is the best way to import all the data from the common file to the other files?
I have not tested this with Jenkins, but if Jenkins executes the Groovy script as if by invoking groovy -cp .... myScript.groovy it should work:
utils.groovy:
// notice there's no "def", otherwise the def would be local only
name = 'Joe'
class MyUtils {
static String greeting(String name) {
"Hello $name"
}
}
src/main.groovy
def shell = new GroovyShell(getBinding())
shell.evaluate(new File('utils.groovy'))
println MyUtils.greeting(name)
Running it:
$ groovy src/Main.groovy
Hello Joe
Because the Script base class by default also has an evaluate method, your can actually just call that instead of using a GroovyShell and the result should be identical:
src/main.groovy
evaluate(new File('utils.groovy'))
println MyUtils.greeting(name)
If it doesn't work it's because the Script base class has been changed , probably... the first approach should work in all cases.

Why do I get "Multiple markers at this line: Groovy expecting EOF found 'for'"?

The Error in the Question was generated by the following code
package ian.eg.learn
class ReadXMLfile {
def customers = new XmlSlurper().parse(new File("C:\\Users\\IBM_ADMIN
\\Documents\\customers.xml"))
for (customer in customers.corporate.customer){
println "${customer.#name} works for ${customer.#company}"
}
}
I am using a regular "for" and I don't see why the compiler is having a problem
I don't know what version of Groovy you're using so the exact error message could vary, but you cannot just write statements like that anywhere in your class, so the compiler expects something else in place of your for statement.
Example:
class Xxx {
println("yoo")
}
Gives:
unexpected token: println # line 2, column 3.
println("yoo")
^
You need to move that code in a method, or an init block... anywhere but not directly in class body.

Class definition within groovy script

Is it possible to create class definitions within a groovy script?
I have a simple script example
class HelloWorld {
def name
def greet() {
"Hello ${name}"
}
}
def helloWorld = new HelloWorld()
helloWorld.name = "Groovy"
println helloWorld.greet()
but I get error like this
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script1.groovy: 1: Class definition not expected here. Please define the class at an appropriate place or perhaps try using a block/Closure instead. at line: 1 column: 1. File: Script1.groovy # line 1, column 1.
class HelloWorld {
^
1 error
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:309) ~[groovy-all-2.4.3.jar:2.4.3]
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:943) ~[groovy-all-2.4.3.jar:2.4.3]
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:590) ~[groovy-all-2.4.3.jar:2.4.3]
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:566) ~[groovy-all-2.4.3.jar:2.4.3]
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:543) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:297) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:267) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyShell.parseClass(GroovyShell.java:692) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyShell.parse(GroovyShell.java:704) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyShell.parse(GroovyShell.java:740) ~[groovy-all-2.4.3.jar:2.4.3]
at groovy.lang.GroovyShell.parse(GroovyShell.java:731) ~[groovy-all-2.4.3.jar:2.4.3
This code works fine. You can see for yourself here.
Yes, in general it's normal to create class definitions within a script.
I'm not able to reproduce your error, and you don't say how you're running this code. I'm guessing you're trying to use a Groovy script to configure some product (Mule has this feature, for instance). Your problem would seem to be specific to the thing you're trying to configure.
If I try to run the script in groovysh I get "Unknown property" when it tries to define the helloWorld variable using def.
In groovyconsole it works fine, as Dónal says.
If I take your code and put it in a file called HelloWorld.groovy and run that from the command line:
groovy HelloWorld.groovy
then I get
C:\Users\ndh\HelloWorld.groovy: 1: Invalid duplicate class definition of class HelloWorld : The source C:\Users\ndh\HelloWorld.groovy contains at least two definitions of the class HelloWorld.
One of the classes is an explicit generated class using the class statement, the other is a class generated from the script body based on the file name. Solutions are to change the file name or to change the class name.
# line 1, column 1.
class HelloWorld {
^
1 error
Changing the name of the file to notHelloWorld.groovy works:
c:\Users\ndh>groovy notHelloWorld.groovy
Hello Groovy
but this is not your problem because the stacktrace shows your filename to be Script1.
When I write a script I put the main logic at the top and put helper functions and class definitions toward the bottom. That's just how I organize the code for readability, though.

SoapUI & Groovy - How to get properties from different TestCases using Run testCase

Sorry in advance. I am sure this is not a new question but I swear I've been looking for days and have tried several solutions but no one fits exactly what I need. I hope you guys can help me...
My problem:
I have a main script which sends bash commands to our server:
TestSuite: Tools;
TestCase: sendBashCommands;
TestStep: groovycript;
This test script is called by several test cases using "Run testCase". Each test case have a different bash command:
TestSuite: ServerInfo
TestCase: getServerVersion
Property: BashCommand="cat smt | grep Version"
TestStep: Run sendBashCommands
TestCase: getServerMessage
Property: BashCommand="cat smt | grep Message"
TestStep: Run sendBashCommands
...
On my sendBashCommands.groovyScript I have already tried the following:
//def bashCmd= context.expand( '${#BashCommand}' );
//it returns empty;
//def bashCmd= testRunner.testCase.getPropertyValue( "BashCommand" );
//it returns null;
//def bashCmd= context.getTestCase().getPropertyValue( "BashCommand" );
//it returns null;
def bashCmd = context.expand('${#TestCase#BashCommand}');
//it also returns empty;
Currently I use a solution which works with project properties but what I actually need is working with these properties on the level of the test case which is calling the sendBashCommand script. Is that possible? How could I do it?
I think you are doing it for maintenance purpose...
As per your approach, the result has to come as null or empty. Because your groovyscript cannot get the properties of other testcases directly. If you call a getProperty() Method directly, then it will refer to the current testStep's property. So the following approach could help you.
put the following code in your individual test cases, "getServerVersion" etc.
def currentProject = testRunner.testCase.testSuite.project
// the following is to store the names of the test suite and the test cases from which you want to call your main script
currentProject.setPropertyValue("TestSuiteName",testRunner.testCase.getTestSuite().getLabel().toString())
currentProject.setPropertyValue("TestCaseName", testRunner.getTestCase().getLabel().toString())
// call sendBashCommands here -> run sendBashCommands
put this code in your main groovy script (sendBashCommands.groovyscript)
def currentProject = testRunner.testCase.testSuite.project
def callingTestCase = currentProject.testSuites[currentProject.getPropertyValue("TestSuiteName")].testCases[currentProject.getPropertyValue("TestCaseName")]
def bashCmd = callingTestCase.getPropertyValue( "BashCommand" )
// to verify
log.info bashCmd
The project is common to all the test suites, so you have to use project property in any case, i.e., for your requirement :)
Enjoy :)

Calling groovy method from script

I'm writing a program in groovy, I want it to run a script with dynamically changing variables. The script is supposed to execute a method with its variables. This method is located in the program that runs the script.
The script would contain something like this:
// getAttribute is a method in my main program, the program which also runs the script
value = getValue("java.lang:type=OperatingSystem", "FreePhysicalMemorySize")
// do something with the value
if (value > 9000) { output = "ERROR" }
// the same thing maybe a few more times
value = getValue(...
I want to keep it as simple as possible.
I was working with these examples: http://groovy.codehaus.org/Embedding+Groovy
I already tried to use the GroovyScriptEngine, but it seems like the script only accepts Strings as input values. It would be great if I could hand over method pointers.
Just trying to hand over an integer like this:
def roots = 'PATH\\script.groovy'
def groscreng = new GroovyScriptEngine(roots)
def binding = new Binding()
def input = 42
binding.setVariable("input", input)
groscreng.run("script.groovy", binding)
println binding.getVariable("output")
With this script.groovy
output = ${input}
results in this error:
Caught: groovy.lang.MissingMethodException: No signature of method: script.$() is applicable for argument types: (script$_run_closure1) values: [script$_run_closure1#fcf50]
Possible solutions: is(java.lang.Object), run(), run(), any(), any(groovy.lang.Closure), use([Ljava.lang.Object;)
Receiving the value in the script as a String like "${input}" works just fine.
I know it has to work somehow and I would appreciate any help or other suggestions!
output = ${input}
isn't valid groovy
Try:
output = input

Resources