How to use Spock from the Command Line - groovy

I am writing a set of groovy scripts to be used as part of a Jenkins Pipeline Library. Currently I am using plain old JUnit to test them but would like to switch to Spock. I simply run the tests from the command line by invoking the following groovy script.
import groovy.util.AllTestSuite
import junit.textui.TestRunner
System.setProperty(AllTestSuite.SYSPROP_TEST_DIR, "./tests")
System.setProperty(AllTestSuite.SYSPROP_TEST_PATTERN, "**/*Test.groovy")
TestRunner.run(AllTestSuite.suite())
I am trying to figure what the equivalent script would be to run Spock specifications. My first attempt was to switch the SYSPROP_TEST_PATTERN to "**/*Spec.groovy. I have one ...Spec.groovy file written and sitting under ./tests that looks like this:
#Grab(group='org.spockframework', module='spock-core', version='1.0-groovy-2.3')
import spock.lang.*
class UtilsSpec extends Specification {
def "Just testing"() {
expect:
1 + 1 == 2
}
}
When I invoke my groovy script though I get:
java.lang.RuntimeException: Don't know how to treat
/SourcCode/jenkins/pipeline-utils/tests/JustTestingSpec.groovy as a
JUnit test
That makes sense. I need to be using Sputnik but I've looked at the Spock and Sputnik source, and the Spock example project but these all assume you are using maven or gradle. I can't figured out the right way to invoke Sputnik directly. Any ideas?

Even though what you ask is possible and BalRog has already suggested a solution, in the long run it is better if you just use Gradle or Maven to run your tests from command line.
All Jenkins tutorials you will encounter will talk about Maven and/or Gradle and thus it would make much more sense to use a build system than custom scripts.

Related

Can I create 'shared library' in Jenkins Pipeline in other language than Groovy?

I have python script which does a REST command and processes the result. I want this script to be used by different Jenkins Pipelines, one way I found through Jenkins official documentation is to use 'Shared library' and that examples(also others example which I found online) they use the Groovy.
My question is, is it possible to create a shared lib in other language than Groovy? For ex. python?
Short answer is no. All Jenkins Pipeline execution (right now) is specialized Groovy that is executed with the Pipeline: Groovy plugin that uses the Groovy CPS library to perform the compilation and runtime transformations. The Jenkins Pipeline ecosystem is very heavily tied to Groovy. That may change in the future, but is not what worth the effort right now.
What you can do, if you really want to use Python code in a Shared Library, is to put it in the resources/ folder of the library and then load and execute it with pipeline steps. Your use case for why you want to use Python is not stated (or what problem you are trying to solve), so below is a contrived example:
In your Shared Library: resources/com/mkobit/sharedlib/my_file.py
#!/usr/bin/env python
print("Hello")
Shared Library Groovy global variable: vars/mkobitVar.groovy
def runMyPython() {
final pythonContent = libraryResource('com/mkobit/sharedlib/my_file.py')
// There are definitely better ways to do this without having to write to the consumer's workspace
writeFile(file: 'my_file.py', text: pythonContent)
sh('chmod +x my_file.py && ./my_file.py')
}
In a consumer
#Library('mkobitLib') _
node('python') {
mkobitVar.runMyPython()
}

Groovy Imports Taking Several Seconds

I'm completely new to Groovy, so apologize in advance if I'm missing something obvious.
I'm trying to do some simple REST API scripting in Groovy, but first wanted to understand it's performance for requests/JSON parsing vs Python. I wrote the following script - and am seeing that the imports are taking ~7 seconds. Is there any way to 'include' those in the script, so it doesn't take so long on each run?
def now = new Date()
println now.format("yyyyMMdd-HH:mm:ss.SSS", TimeZone.getTimeZone('UTC'))
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7')
#Grab('oauth.signpost:signpost-core:1.2.1.2')
#Grab('oauth.signpost:signpost-commonshttp4:1.2.1.2')
import groovyx.net.http.RESTClient
import static groovyx.net.http.ContentType.*
for (i = 0; i <1; i++) {
def Client = new RESTClient("http://www.mocky.io/v2/59821b4a110000a9103964eb" )
def resp = Client.get(contentType: JSON)
def myResponseObject = resp.getData()
println myResponseObject.items[i].id
}
now = new Date()
println now.format("yyyyMMdd-HH:mm:ss.SSS", TimeZone.getTimeZone('UTC'))
I get this output:
~$ time groovy Requests.groovy
20170802-18:36:24.556
10
20170802-18:36:25.290
real 0m7.173s
user 0m4.986s
sys 0m0.329s
Just the first few lines of Grabs and imports are taking the majority of the runtime , and that's what I'd like to cut down.
It's not the import that takes time, but #Grab annotation which comes from Grape - a Groovy dependency management system. Those 3 lines:
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7')
#Grab('oauth.signpost:signpost-core:1.2.1.2')
#Grab('oauth.signpost:signpost-commonshttp4:1.2.1.2')
define your script dependencies. Those dependencies are 3rd party libraries provided as a JAR files. Some of them may even have their own dependencies which will be also downloaded to satisfy dependency you have defined (e.g. http-builder requires Apache's HTTP client and core lib).
Running this script takes some time (about 1 second on my laptop), because Groovy has to determine all dependencies and add them to the classpath to satisfy all imports. Keep in mind that your script uses a lot more dependencies than those 3 and all of them have to be resolved.
Using Grape is actually a compromise between using 3rd party libraries in the most easiest way and some overhead that is delegated to Groovy. Alternatively you could run your script with:
groovy -classpath ${GROOVY_CLASSPATH} Request.groovy
where ${GROOVY_CLASSPATH} contains paths to all JAR files you need to successfully run the script. And believe me - you will have to add at least 15 libraries instead of those 3 grapes. Then you will be able to remove all #Grab annotations (they are not needed in this case because you will satisfy groovy script with providing all libs in the classpath) and your script will execute in the blink of an eye - there will be no overhead caused by resolving and loading all dependencies.
Another alternative solution is to use Gradle to manage all dependencies and create so called "fat JAR" that contains all mandatory dependencies inside - in this case you will be able to run your program with java command and all imports will be in place without any dependencies resolving mechanism.
Final conclusion. Grape is a powerful Groovy's feature that has it's own limitations. It allows you to handle dependencies-hell pretty easily, but it comes with its own cost. I hope this answer will help you making a good choice.

Get rid of import in Groovy Unit Test in IntelliJ

Is it possible to get rid of from import statements in JUnit tests written in Groovy? I know you could do it in groovy scripts in GroovyShell by changing compiler configuration or import customizer.
I like to do same thing but:
IntelliJ should still provide code highlight and auto complete (I think I could do this
with gdsl file feature of IntelliJ)
I could still use IntelliJ's JUnit window to see which tests failed and which are passed.

Run groovy script from within gradle

What's the best way to create a gradle task, which runs a groovy script? I realize that gradle build files are groovy, so I would think it would be possible to do something like this:
task run << {
Script app = new GroovyShell().parse(new File("examples/foo.groovy"))
// or replace .parse() w/ a .evalulate()?
app.run()
}
I get all kinds of whacky errors when I try this if bar.groovy is using #Grab annotations or even doing simple imports. I want to create a gradle task to handle this, so that I can hopefully reuse the classpath definition.
Would it be better to move the examples directory into the src directory somewhere? What's a best practice?
Or you could do:
new GroovyShell().run(file('somePath'))
You could try using GroovyScriptEngine instead of the GroovyShell. I've used it previously with #Grab annotations. You will need all of groovy on the classpath, the groovy-all.jar will not be enough. I'm guessing Ivy isn't packaged in the groovy-all.jar. Something like this should to the trick:
This script presumes a groovy script at /tmp/HelloWorld.groovy
def pathToFolderOfScript = '/tmp'
def gse = new GroovyScriptEngine([pathToFolderOfScript] as String[])
gse.run('HelloWorld.groovy', new Binding())
http://wayback.archive.org/web/20131006153845/http://docs.codehaus.org/display/GRADLE/Cookbook#Cookbook-runningthingsfromGradle
ant.java(classname: 'com.my.classname', fork: true,
classpath: "${sourceSets.main.runtimeClasspath.asPath}")
I think you probably need to run the script as a new process... e.g.,
["groovy","examples/foo.groovy"].execute()
I would guess that the way Gradle is executed is not via invoking groovy, so the setup that makes #Grab work never happens. It could also be the the version of Groovy that Gradle uses doesn't support #Grab.

How can create a Junit4 Suite with Groovy?

I have
#RunWith(Suite.class)
#Suite.SuiteClasses( [
First.class,Second.class
])
public class MySuite{
}
But eclipse doesn't give me a "Run As Junit4 Test". All the individual test classes work fine with GUnit, the groovy unit test runner built into eclipse.
Any thoughts?
The only way I found to do this was to create a java class with a #Suite.SuiteClasses annotation as usual. You can put in the .class names of the Groovy classes you have for tests and it works well.
Kind of lame if you don't already have some java code to do it this way but I had a mix of Java and Groovy so it wasn't as big a deal.
The other option is to not use Suites at all and to use name patterns to find and run tests. Both ant and maven support this sort of pattern matching. I find it much easier than making sure I keep the suites up to date and Eclipse can just run all tests in a package if I want to do that.
Thanks for the help.
#Suite.SuiteClasses accepts Class[] as its parameter.
You may try:
#RunWith(Suite.class)
#Suite.SuiteClasses([First.class, Second.class] as Class[])
public class MySuite {
}

Resources