How to use closures of Jenkins Job DSL Plugin within groovy classes - groovy

I'm new to Job DSL Plugin and even Groovy.
Given the following script:
class MyClass {
def create() {
folder('test') {
}
}
}
new MyClass().create()
I'm getting the following error:
javaposse.jobdsl.dsl.DslScriptException: (script, line 3) No signature of method: MyClass.folder() is applicable for argument types: (java.lang.String, MyClass$_create_closure1) values: [test, MyClass$_create_closure1#62591600]
Possible solutions: find(), collect()
Ok, clear. Groovy does not find a method called "folder" in my class. But this isn't a method. It is a Job DSL command. How can I use them within my classes?

You need to pass the script reference into your class, see the Job DSL wiki.
class MyClass {
def create(def dslFactory) {
dslFactory.folder('test') {
}
}
}
new MyClass().create(this)

Related

Calling a method in another method in groovy

I have some methods in a module (groovy Spock framework. The methods all shared a common pattern. I want to make a method for this common pattern, then call on it from the mentioned methods.
two of the methods which shared the same pattern are: (I show just two of them here but they are more).
void setPayloadIndexRetention(String payloadIndexRetention) {
if (payloadIndexRetention==null){
payloadIndexRetention='30 days(default)'
}
arielRetention.find('input', class: contains('dijitArrowButtonInner')).click()
arielRetentionmenu.find('td', text: payloadIndexRetention).click()
sleep(5000)
}
arielRetention and payloadIndexRetention are defined in the module content as:
arielRetention { $('table', id: 'ARIEL_FREE_TEXT_RETENTION') }
arielRetentionmenu { $('table', id: 'ARIEL_FREE_TEXT_RETENTION_menu') }
if (privacyProtocol==null){
privacyProtocol='DES'
}
snmpPrivacyProtocol.find('input', class: contains('dijitArrowButtonInner')).click()
snmpPrivacyProtocolmenu.find('td', text: privacyProtocol).click()
sleep(5000)
}
snmpPrivacyProtocol and snmpPrivacyProtocolmenu are:
snmpPrivacyProtocol { $('table', id: 'SNMP_V3_DEC_PROTO') }
snmpPrivacyProtocolmenu { $('table', id: 'SNMP_V3_DEC_PROTO_menu') }
I made another method that includes the shared pattern:
void setParameter (String parameter, String defaultValue, def navigator1, def navigator2){
if (parameter==null){
parameter=defaultValue
}
navigator1.find('input', class: contains('dijitArrowButtonInner')).click()
navigator2.find('td', text: parameter).click()
}
When I call setParameter on the setPayloadIndexRetention method, and run my test I get the following error:
geb.error.RequiredPageContentNotPresent: The required page content 'geb.qradar.gebpages.SystemSettingsPage -> settings: geb.qradar.gebmodules.SystemSettingsModule -> arielRetentionmenu: geb.navigator.DefaultNavigator' is not present
Does anyone have any idea where am I making a mistake?
I also use Navigator instead of `def as parameter type, the issue was still there.

What is the use of a static initialization block in Groovy?

What is the use of the static initialization block in Groovy. Why does Geb use it? If the use of it is the same as in Java, then how can you initialize non-declared fields in a situtation like this?
class ManualsMenuModule extends Module {
static content = {
toggle { $("div.menu a.manuals") }
linksContainer { $("#manuals-menu") }
links { linksContainer.find("a") }
}
void open() {
toggle.click()
waitFor { !linksContainer.hasClass("animating") }
}
}
Some answers to your questions are provided in the section about the content DSL of the Geb manual.
The DSL is implemented using Groovy's methodMissing() mechanism and modification of the delegate of the closure assigned to the static content field. If you are interested in digging deeper then you can always look at the implementation in PageContentTemplateBuilder.
I'm not expert on Geb, I can only explain the groovy meaning of the code.
1st off, it's not the static initialization block like in java. In those lines static content = {...} you are assigning to a static variable a Closure instance which is evaluated and executed LATER (hence, lazy).
The closure represents a (part of) a Geb's Groovy Builder which is called by Geb framework to register/perform some tasks.
There's no Java counterpart to achieve the same, and that's the reason why groovy-based frameworks are so nice to use for testing purposes and they follow the general rule of thumb:
test code should be more abstract then the code under test
UPDATE:
This line:
toggle { $("div.menu a.manuals") }
can be rewritten like
toggle( { $("div.menu a.manuals") } )
or
def a = { $("div.menu a.manuals") }
toggle a
so it's a method invocation and not an assignment. In groovy you can omit the brackets in some cases.

How to "include" common methods in groovys

I have developed a number of groovys used as plugins by Serviio.
Many of the methods used by these plugins are common, but when changes are made, each plugin needs to be updated. Therefore I want to "include" those methods in each plugin from a tools.groovy. I have tried 2 different approaches suggested in other posts.
I tried using
evaluate(new File("C:\\Program Files\\Serviio\\plugins\\tools.groovy"))
at the start of each plugin where tools.groovy just has
class Tools{method1{return}method2{return}}
but when executing the plugin I get
Caught: groovy.lang.MissingMethodException: No signature of method: Tools.main() is applicable for argument types: () values: []
If I then add
void main(args) { }
to class Tools, the error goes away but that Tools.main is run instead of the plugin.main and I get no output.
My second approach as suggested was to use
def script = new GroovyScriptEngine( '.' ).with {
loadScriptByName( 'C:\\Program Files\\Serviio\\plugins\\tools.groovy' )
}
this.metaClass.mixin script
This however gives the error
unexpected token: this # line 55, column 2.
this.metaClass.mixin script
Any suggestions on how to make either of these solutions work would be appreciated.
Did you try defining a common base script and giving it as a compiler configuration.
http://groovy.codehaus.org/Embedding+Groovy
From the groovy documentation...
class ScriptBaseTest {
#Test
void extend_groovy_script() {
def compiler = new CompilerConfiguration()
compiler.setScriptBaseClass("ScriptBaseTestScript")
def shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)
assertEquals shell.evaluate("foo()"), "this is foo"
}
}
abstract class ScriptBaseTestScript extends Script {
def foo() {
"this is foo"
}
}

Can't pass closures in groovy

I am trying to run a basic example for the Geb library (http://www.gebish.org/manual/current/intro.html#introduction). Here is the code:
import geb.Browser
Browser.drive {
go "http://google.com/ncr"
// make sure we actually got to the page
assert title == "Google"
// enter wikipedia into the search field
$("input", name: "q").value("wikipedia")
// wait for the change to results page to happen
// (google updates the page dynamically without a new request)
waitFor { title.endsWith("Google Search") }
// is the first link to wikipedia?
def firstLink = $("li.g", 0).find("a.l")
assert firstLink.text() == "Wikipedia"
// click the link
firstLink.click()
// wait for Google's javascript to redirect to Wikipedia
waitFor { title == "Wikipedia" }
}
When I try to run this (using Eclipse's groovy support) I get the following exception:
Caught: groovy.lang.MissingMethodException: No signature of method: static geb.Browser.drive() is applicable for argument types: (ExampleScript$_run_closure1) values: [ExampleScript$_run_closure1#2a62610b]
Possible solutions: drive(groovy.lang.Closure), drive(geb.Browser, groovy.lang.Closure), drive(geb.Configuration, groovy.lang.Closure), drive(java.util.Map, groovy.lang.Closure), print(java.lang.Object), print(java.io.PrintWriter)
groovy.lang.MissingMethodException: No signature of method: static geb.Browser.drive() is applicable for argument types: (ExampleScript$_run_closure1) values: [ExampleScript$_run_closure1#2a62610b]
Possible solutions: drive(groovy.lang.Closure), drive(geb.Browser, groovy.lang.Closure), drive(geb.Configuration, groovy.lang.Closure), drive(java.util.Map, groovy.lang.Closure), print(java.lang.Object), print(java.io.PrintWriter)
at ExampleScript.run(ExampleScript.groovy:21)
I think this is saying that the closure I am passing to the static Browser.drive method is not type compatible with groovy.lang.Closure, but I don't know why. Simple groovy hello world scripts work fine but passing a closure to a method always returns a similar error.
Plagiarized from: http://groovy.codehaus.org/Differences+from+Java
Java programmers are used to semicolons terminating statements and not having closures. Also there are instance initializers in class definitions. So you might see something like:
class Trial {
private final Thing thing = new Thing ( ) ;
{ thing.doSomething ( ) ; }
}
Many Groovy programmers eschew the use of semicolons as distracting and redundant (though others use them all the time - it's a matter of coding style). A situation that leads to difficulties is writing the above in Groovy as:
class Trial {
private final thing = new Thing ( )
{ thing.doSomething ( ) }
}
This will throw a MissingMethodException!

how to detect caller instance in SoapUI groovy script?

A SoapUI project can run random script upon load.
Load Script is invoked with log and project variables.
In my shared lib I have method - addAsserts() that traverses the whole project and adds schema compliance assertions to SOAP test steps. In my Load Script I call shared method
addAsserts(this)
passing 'this' as a parameter and set closure.delegate to it inside addAsserts method to make 'project' variable accessible within the closure scope
addAsserts method is defined in sharedUtil.groovy:
static def addAsserts(that){
def closure={
project.testSuites.each { testSuiteName, testSuiteObject ->
testSuiteObject.testCases.each { testCaseName, testCaseObject ->
testCaseObject.testSteps.each { testStepName, testStepObject ->
if ("class com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep" == testStepObject.getClass().toString() ) {
log.info "adding 'Schema Compliance' assertion to ${testSuiteName}/${testCaseName}/${testStepName}"
testStepObject.addAssertion('Schema Compliance')
}
}
}
}
}//closure
closure.delegate=that // <--- i would like NOT to pass 'that' as parameter
// but rather detect in runtime with some kind of
// getCallerInstance() method
return closure.call()
}
QUESTION:
Is it possible to detect caller instance in runtime with some kind of getCallerInstance() method ?
No, I don't believe this is possible. Wasn't in Java either (you can find out the name/method of the calling class using some horrible stacktrace hacking, but not the instance of the class itself)
Edit...
It might be possible with a Category (but I am not experienced with SoapUI, so I don't know if this technique would fit)
Say we have a class Example defined like so:
class Example {
String name
}
We can then write a class very similar to your example code, which in this case will set the delegate of the closure, and the closure will print out the name property of the delegate (as we have set the resolve strategy to DELEGATE_ONLY)
class AssetAddingCategory {
static def addAsserts( that ) {
def closure = {
"Name of object: $name"
}
closure.delegate = that
closure.resolveStrategy = Closure.DELEGATE_ONLY
closure.call()
}
}
Later on in our code, it is then possible to do:
def tim = new Example( name:'tim' )
use( AssetAddingCategory ) {
println tim.addAsserts()
}
And this will print out
Name of object: tim

Resources