Replace a method with parameters by a closure in metaclass - grails

I have two class:
class Foo {
String doSomething(String a, String b) {
return 'Not Working'
}
}
class Bar {
String methodIWannaTest() {
return new Foo().doSomething('val1', 'val2')
}
}
And I want to replace 'doSomething' in a test but it dosent work
class BarTests {
#Test
void testMethodIWannaTest() {
Foo.metaClass.doSomething {String a, String b -> return 'Working'}
assert new Bar().methodIWannaTest() == 'Working' //THIS TEST FAIL, return 'Not Working'
}
}
*I know the test doesn't really make sens, it's just to show my point
What do I do wrong ? Is it possible to do it without using 'mockFor' ?

I would suggest you to start the test afresh. Baby Steps is what I follow. :)
Create a new grails app.
Create both Foo and Bar inside src/groovy under a package.
Create unit test case from command prompt. Put the desired test code.
Execute grails test-app
[Grails v2.2.0]

Another alternative is to use Groovy MockFor.
def mock = MockFor(Foo)
mock.demand.doSomething = {String a, String b -> return 'Working'}
mock.use {
assert new Bar().methodIWannaTest() == 'Working'
}
A downside is that there was a bug, making unit tests not clear the mock. This is fixed for 2.2.3.

I found the problem:
First, in my exemple, I forgot the '=' when defining the closure
Foo.metaClass.doSomething {String a, String b -> return 'Working'}
should be
Foo.metaClass.doSomething = {String a, String b -> return 'Working'}
While searching I also found that you cannot replace a method with optionnal parameters by a closure. Probably a bug

I tried this on GGTS 3.2.0 and got the following results.
Copied all the code and ran on Grails 2.2.2: everything worked correctly. However, then I commented out Foo.metaClass.doSomething = {String a, String b -> return 'Working'} line and, surprisingly, the test was still passing successfully. I did more changes and the metaClass just seemed to get "cached" between tests: changes had no effect.
Then I thought if it is possible that Grails were running in interactive mode. Went to Preferences > Groovy > Grails > Grails Launch and found a checkbox 'Keep external Grails running' ticked. Its tooltip even has the following words: 'Warning: experimental feature!'. Unticking that checkbox did the trick and the metaClass no longer got cached between test runs. I am still wondering why an exprimental feature would be turned on by default...

Related

Jenkins Shared Library Recursive Function Calls

I have declarative pipeline and uses jenkins shared library. I am trying to make recursive function call within jenkins shared library.
My shared lib structure is something similar to below :
vars/xyz.groovy
Inside xyz.groovy I have method foo, to whom I call xyz.foo from my pipeline which works.
However recursive call from
foo(){
foo() // says No such DSL method
xyz.foo() //says no signature of method: java.lang.class.foo
}
I am trying to understand how to calls functions within jenkins shared library.
this.methodName is rightway to call function recursively inside shared library. All though method is not a part of class. But using this.foo() worked for me.
I was trying something similar to invoke a recursive function with a method declared in the same file .groovy
At the end, the option #Sagar gave didn't work for me
As a workaround, I created the recursive function in a new file (b.groovy) and invoke it from the original file (a.groovy). it worked like a charm :)
example.
b.groovy
/**
* recursive function to compare semantic version form package.json and tag version, only evaluate x.x.x version
* 0 same version
* 1 package.json version is GREATER than repo tag version
* -1 package.json version is SMALLER than repo tag version
*/
int call(ArrayList versionPackageJsonSplit, ArrayList versionTagRepoSplit, Integer iteration) {
if (versionPackageJsonSplit[iteration].toInteger() == versionTagRepoSplit[iteration].toInteger()) {
if (iteration == 2) {
println 'return 0'
return 0
}
return utility_cdkCompareVersions (versionPackageJsonSplit, versionTagRepoSplit, iteration+1) // --> recursive invocation
} else if (versionPackageJsonSplit[iteration].toInteger() > versionTagRepoSplit[iteration].toInteger()) {
println 'return 1'
return 1
} else if (versionPackageJsonSplit[iteration].toInteger() < versionTagRepoSplit[iteration].toInteger()) {
println 'return -1'
return -1
}
}
a.groovy
.
.
.
compareVersionsResult = b (versionPackageJsonSplit, versionTagRepoSplit, 0)
println compareVersionsResult
.
.
.
.
```
So far the least awful way I've found to do this reliably is to create a top-level wrapper method with a recursive closure inside it:
def recursiveMethod(args) {
Closure rec
rec = { arg ->
if (recursiveCase) {
return rec(…)
}
else {
return baseCase
}
}
return rec(…)
}
The upside is that you can reference method args or method-scoped state variables from within the closure without having to pass them around the recursive stack, so recursive calls may look a little cleaner. The downside is a little extra boilerplate to do the wrapping, and also that the closure args have to be named differently than the method args or Groovy raises an error.

How do you make a feature method conditional

In my Test, I have some feature methods that only need to run in certain situations. My code looks something like this:
class MyTest extends GebReportingSpec{
def "Feature method 1"(){
when:
blah()
then:
doSomeStuff()
}
def "Feature method 2"(){
if(someCondition){
when:
blah()
then:
doSomeMoreStuff()
}
}
def "Feature method 3"(){
when:
blah()
then:
doTheFinalStuff()
}
}
I should note I am using a custom spock extension that allows me to run all feature methods of a spec even if a previous feature method fails.
The thing I just realized and the reason I am making this post, is because "Feature method 2" does not show up in my test results for some reason, but method 1 and 3 do. Even if someCondition is set to true, it does not appear in the build results. so I am wondering why this is, and how I can make this feature method conditional
Spock has special support for conditionally executing features, take a look at #IgnoreIf and #Requires.
#IgnoreIf({ os.windows })
def "I'll run everywhere but on Windows"() { ... }
You can also use static methods in the condition closure, they need to use the qualified version.
class MyTest extends GebReportingSpec {
#Requires({ MyTest.myCondition() })
def "I'll only run if myCondition() returns true"() { ... }
static boolean myCondition() { true }
}
Your test is not appearing in the report as you cant have the given, when, then blocks inside of a conditional.
You should always run the test but allow the test to fail gracefully:
Use the #FailsWith attribute. http://spockframework.org/spock/javadoc/1.0/spock/lang/FailsWith.html
#FailsWith(value = SpockAssertionError, reason = "Feature is not enabled")
def "Feature method 2"(){
when:
blah()
then:
doSomeMoreStuff()
}
Important to note that this test will be reported as passed when it fails with the specified exception. And it will also reported as passed if the feature is enabled and the test actually passed.
To Fix this I simply put a when/then block with a 10 ms sleep before the if statement and now that feature method is being executed

How to print each element of Multi-line String Parameter?

I've Pipeline job in Jenkins (v2.7.1) where I'd like to print each element of Multi-line String parameter (Params) with 3 strings in each line: Foo, Bar, Baz as an input.
So I've tried the following syntax (using split and each):
Params.split("\\r?\\n").each { param ->
println "Param: ${param}"
}
but it fails with:
java.lang.UnsupportedOperationException: Calling public static java.lang.Object
org.codehaus.groovy.runtime.DefaultGroovyMethods.each(java.lang.Object,groovy.lang.Closure) on a CPS-transformed closure is not yet supported (JENKINS-26481); encapsulate in a #NonCPS method, or use Java-style loops
at org.jenkinsci.plugins.workflow.cps.GroovyClassLoaderWhitelist.checkJenkins26481(GroovyClassLoaderWhitelist.java:90)
which suggest to encapsulate in a #NonCPS method, or use Java-style loops.
So I've tried to encapsulate in a #NonCPS method like:
#NonCPS
def printParams() {
Params.split("\\r?\\n").each { param ->
println "Param: ${param}"
}
}
printParams()
but it fails with:
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods println groovy.lang.Closure java.lang.Object
Without the function (as per first example), adding #NonCPS at the beginning it complains about unexpected token.
I also tried Java-style syntax as suggested by using for operator (similar as here):
String[] params = Params.split("\\r?\\n")
for (String param: params) {
println "Param: ${param}"
}
which seems to work in plain Groovy, but it fails in Jenkins with:
java.io.NotSerializableException: java.util.AbstractList$Itr
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
Which syntax I should use to make it work?
The code works fine when disabling a Use Groovy Sandbox option and adding #NonCPS helper method. Alternatively, as suggested by #agg3l, proceed to Jenkins management to permit this method access.
So the working code is (same as the 2nd example):
#NonCPS
def printParams() {
Params.split("\\r?\\n").each { param ->
println "Param: ${param}"
}
}
printParams()
I know it's an old post but this is my way to do it, hopefully help anyone else
params.readLines().each {
println it
if (it) {
// if you want to avoid make operation with empty lines
}
}

Groovy - How to reflect code from another groovy app to find Classes/Properties/Types within

First, I came from a .NET background so please excuse my lack of groovy lingo. Back when I was in a .NET shop, we were using TypeScript with C# to build web apps. In our controllers, we would always receive/respond with DTOs (data xfer objects). This got to be quite the headache every time you create/modify a DTO you had to update the TypeScript interface (the d.ts file) that corresponded to it.
So we created a little app (a simple exe) that loaded the dll from the webapp into it, then reflected over it to find the DTOs (filtering by specific namespaces), and parse through them to find each class name within, their properties, and their properties' data types, generate that information into a string, and finally saved as into a d.ts file.
This app was then configured to run on every build of the website. That way, when you go to run/debug/build the website, it would update your d.ts files automatically - which made working with TypeScript that much easier.
Long story short, how could I achieve this with a Grails Website if I were to write a simple groovy app to generate the d.ts that I want?
-- OR --
How do I get the IDE (ex IntelliJ) to run a groovy file (that is part of the app) that does this generation post-build?
I did find this but still need a way to run on compile:
Groovy property iteration
class Foo {
def feck = "fe"
def arse = "ar"
def drink = "dr"
}
class Foo2 {
def feck = "fe2"
def arse = "ar2"
def drink = "dr2"
}
def f = new Foo()
def f2 = new Foo2()
f2.properties.each { prop, val ->
if(prop in ["metaClass","class"]) return
if(f.hasProperty(prop)) f[prop] = val
}
assert f.feck == "fe2"
assert f.arse == "ar2"
assert f.drink == "dr2"
I've been able to extract the Domain Objects and their persistent fields via the following Gant script:
In scripts/Props.groovy:
import static groovy.json.JsonOutput.*
includeTargets << grailsScript("_GrailsBootstrap")
target(props: "Lists persistent properties for each domain class") {
depends(loadApp)
def propMap = [:].withDefault { [] }
grailsApp.domainClasses.each {
it?.persistentProperties?.each { prop ->
if (prop.hasProperty('name') && prop.name) {
propMap[it.clazz.name] << ["${prop.name}": "${prop.getType()?.name}"]
}
}
}
// do any necessary file I/O here (just printing it now as an example)
println prettyPrint(toJson(propMap))
}
setDefaultTarget(props)
This can be run via the command line like so:
grails props
Which produces output like the following:
{
"com.mycompany.User": [
{ "type": "java.lang.String" },
{ "username": "java.lang.String" },
{ "password": "java.lang.String" }
],
"com.mycompany.Person": [
{ "name": "java.lang.String" },
{ "alive": "java.lang.Boolean" }
]
}
A couple of drawbacks to this approach is that we don't get any transient properties and I'm not exactly sure how to hook this into the _Events.groovy eventCompileEnd event.
Thanks Kevin! Just wanted to mention, in order to get this to run, here are a few steps I had to make sure to do in my case that I thought I would share:
-> Open up the grails BuildConfig.groovy
-> Change tomcat from build to compile like this:
plugins {
compile ":tomcat:[version]"
}
-> Drop your Props.groovy into the scripts folder on the root (noting the path to the grails-app folder for reference)
[application root]/scripts/Props.groovy
[application root]/grails-app
-> Open Terminal
gvm use grails [version]
grails compile
grails Props
Note: I was using Grails 2.3.11 for the project I was running this on.
That gets everything in your script to run successfully for me. Now to modify the println portion to generate Typescript interfaces.
Will post a github link when it is ready so be sure to check back.

Grails integration test mock not cleaned

I've a strange polluting situation between two spock integration tests that I'm not able to resolve. I suppose that I'm doing something wrong but I can't understand what.
The two integration tests are testing different situation of the same controller. In the first one I mock a service while in the second I don't mock.
Here are the significant parts of two tests :
test 1:
// CodeControllerSpec.groovy
...
def controller = new CodeController()
def serviceMock = new MockFor(PollutingService)
serviceMock.demand.search(1) { a, b, c ->
return [id: 1]
}
controller.myService.pollutingService = serviceMock.proxyInstance()
controller.save()
...
then:
serviceMock.verify(controller.myService.pollutingService)
test 2:
// CodeEngineSpec.groovy
...
def controller = new CodeController()
controller.show()
...
then:
...
Controller and services are as following
// CodeController
class CodeController extends RestfulController<Code> {
def myService
def show() {
...
myService.execute()
...
}
}
// MyService
class MyService {
def pollutingService
def execute() {
...
pollutingService.search(a, b, c)
...
}
}
// PollutingService
class PollutingService {
def search(a, b, c) {
...
...
}
}
If I run the two tests one by one, they all pass but, if I run them together, the second one fails with
No more calls to 'search' expected at this point. End of demands.
I'm sure that the mock in the first service is used (I've debugged code line by line) but I don't know why mock is not cleaned after test.
Any suggestion is really welcome.
I'm using grails 2.3.8
First of all, using mocks in integration tests has unpredictable results.
But putting that aside, where is controller.myService in your first test being instantiated? I would have expected that calling controller = new CodeController() would bypass autowiring of controller.myService.

Resources