I have an 'Execute Groovy script' build step in Jenkins. This step consists of two files - a client file called createWorkspaces.groovy and a bean file called WorkspaceBean.groovy. Both live in the same location in the job workspace.
Previously running Jenkins 1.554 this ran without issues, but after upgrading to 1.594 I am getting the following error:
/jenkins/workspace/testjob/scripts/groovy/createWorkspaces.groovy: 75: unable to resolve class WorkspaceBean
# line 75, column 21.
def workspace = new WorkspaceBean()
^
1 error
I have approved the scripts in the new script approval function and I have also added the location of the files to the class path parameter in the job step as well as the location of the jenkins-core.jar file.
Any ideas why this has stopped working?
This appears to be a bug in the groovy plugin. Adding paths to the Class path field within the plugin configuration does not change the class path.
This does not work:
Adding a CLASSPATH variable via the 'Inject environment variables into the build process' plugin does work.
This works:
Try to load your jars dynamically. This is the final working solution I found. This sample is for copy network folder to local machine.
def file = new File("jcifs-1.3.18.jar")
this.class.classLoader.rootLoader.addURL(file.toURI().toURL())
def auth_server = Class.forName("jcifs.smb.NtlmPasswordAuthentication").newInstance("domain", "username", "password")
def auth_local = Class.forName("jcifs.smb.NtlmPasswordAuthentication").newInstance(null, "local_user", "password")
def source_url = args[0]
def dest_url = args[1]
def auth = auth_server
//prepare source file
if(!source_url.startsWith("\\\\"))
{
source_url = "\\\\localhost\\"+ source_url.substring(0, 1) + "\$" + source_url.substring(1, source_url.length());
auth = auth_local
}
source_url = "smb:"+source_url.replace("\\","/");
def source = Class.forName("jcifs.smb.SmbFile").newInstance(source_url,auth_server)
//prepare destination file
if(!dest_url.startsWith("\\\\"))
{
dest_url = "\\\\localhost\\"+ dest_url.substring(0, 1) + "\$" +dest_url.substring(2, dest_url.length());
auth = auth_local
}
dest_url = "smb:"+dest_url.replace("\\","/");
def dest = Class.forName("jcifs.smb.SmbFile").newInstance(dest_url,auth_local)
source.copyTo(dest)
Related
I am running a test case and I want the code to automatically load the respective .json file .
Right now I am hardcoding the file ,but I want it loaded when the respective test class runs ,so looking to make it generic.
def setupSpec() {
config = (Map) new
JsonSlurper().parse(getClass().getResourceAsStream("wps.build.json"))
config.build = "Wps build ${new Date()}"
caps = bsLocal.defaultCaps
caps.setCapability("build", config.build)
caps.setCapability("browserstack.console", "info")
attempts = config.environments.size()
}```
This is the structure
https://imgur.com/g7a2B3n
I want to know what is the correct way of setting up a folder directory within SOAPUI. Should I use setup scripts within each testcase or testsuite level or should they be setup within a groovy script step whenever required?
Currently I decided to use the groovy script method only because if I use it in a setup script, it means I have to run the setup script first to get the folder directory before I can run the test case that contains a script assertion.
Below is an example of my folder directory set up in a groovy script (called test script):
def date = new Date()
def folderTime = date.format("yyyy-MM-dd HH-mm-ss")
//Create a folder directory for the responses
RootResultFolder = dataFolder + "\\Log Smoke Test Data" + "\\xxx" + "\\xxx - " + folderTime + "\\"
CreateResultFolder = new File(RootResultFolder)
CreateResultFolder.mkdir()
...
context.setProperty( "RootResultFolder", RootResultFolder )
Below is my script assertion within a test step that uses the above folder directory:
def date = new Date().format("yyyy-MM-dd")
def time = new Date().format("HH.mm.ss")
def dataFolder = context.getProperty("RootResultFolder")
def fileName = xxx+ ".txt"
def rootFolder = dataFolder + fileName
def logFile = new File(rootFolder)
logFile.write "TEXT: " + xxx + "\n\n" +
JsonOutput.prettyPrint
Thank you
I suggest you place them relative to project with the following code
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
// define location relative to SOAPUI project.
String projectPath = groovyUtils.projectPath + "/destination/"
context.setProperty( "RootResultFolder", projectPath)
How can I use groovy to keep the content of SQL Queries in SoapUI in sync with an external editor?
The solution might look like this:
Groovy script to export all the queries of a SoapUI TestSuite or
TestStep into SQL file(s).
Edit and save SQL with external editor.
Groovy script to update the queries in SoapUI based on changed
files.
Initial issues:
How do I access the query of a teststep? It is not there as a
porperty, is it?
Is there a way to run steps 1 and 3 on a project file (XML) instead
from within a test itself (as setUp/tearDown scripts)?
Motivation
SQL Query input fields of JDBC test steps
very small and
does not provide any code formatting like indenting, re-wrapping, or upper-casing of SQL keywords (there is just syntax highlighting).
This is IMHO very cumbersome when writing a query that contains more than a couple of where clauses or even joins.
Side note: If somebody could point me to some functionality (builtin, plugin?) to format the SQL code directly in SoapUI (not pro!), I would gladly pass on groovy scripts.
These are my groovy-scripts that I have implemented in the form of Groovy test steps (they might also be setUp/tearDown scripts, but I prefer separate test steps that are clearly visible and where I can easily toggle their activity):
Export all the JDBC/SQL queries of a SoapUI test case into SQL file(s). This might be the final step of the testcase.
def testCase = testRunner.testCase
def testSuite = testCase.testSuite
def project = testSuite.project
// Remove .xml extension from filename
String pathToProjectDir = project.path.replaceAll(~/\.\w+$/, '')
File projectDir = new File(pathToProjectDir)
File suiteDir = new File(projectDir, testSuite.name)
File caseDir = new File(suiteDir, testCase.name)
caseDir.mkdirs()
assert caseDir.exists()
assert caseDir.isDirectory()
log.info "Exporting to '${caseDir}'."
testCase.getTestStepsOfType(com.eviware.soapui.impl.wsdl.teststeps.JdbcRequestTestStep)
.each{testStep ->
String filename = "${testStep.name}.sql"
File file = new File(caseDir, filename)
file.text = testStep.query
log.info "'${filename}' written."
}
log.info "Files written."
Edit and save SQL with external editor.
Update the queries in SoapUI based on changed files. Missing or empty files are ignored in order not to break too much in the existing project.
def testCase = testRunner.testCase
def testSuite = testCase.testSuite
def project = testSuite.project
// Remove .xml extension from filename
String pathToProjectDir = project.path.replaceAll(~/\.\w+$/, '')
File projectDir = new File(pathToProjectDir)
File suiteDir = new File(projectDir, testSuite.name)
File caseDir = new File(suiteDir, testCase.name)
assert caseDir.exists()
assert caseDir.isDirectory()
log.info "Importing from '${caseDir}'."
testCase.getTestStepsOfType(com.eviware.soapui.impl.wsdl.teststeps.JdbcRequestTestStep)
.each{testStep ->
String filename = "${testStep.name}.sql"
File file = new File(caseDir, filename)
if (file.exists()) {
if (file.text) {
testStep.query = file.text
log.info "'${filename}'"
} else {
log.warn "Ignoring '${filename}'"
}
} else {
log.warn "'${filename}' does not exist."
}
}
log.info "Files imported."
The files are placed in the following directory structure:
Starting from the SoapUI project file path/to/project.xml itself, a tree is (created and) populated with one SQL file per JDBC test step:
path/to/project/${name of TestSuite}/${name of TestCase}/${name of TestStep}.sql
I want to fetch Total TestCase PASS and FAIL count for a build using groovy script. I am using Junit test results. I am using Multiconfiguration project , so is there any way to find this information on a per configuration basis?
If you use the plugin https://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin, you can access the Jenkins TestResultAction directly from the build ie.
import hudson.model.*
def build = manager.build
int total = build.getTestResultAction().getTotalCount()
int failed = build.getTestResultAction().getFailCount()
int skipped = build.getTestResultAction().getSkipCount()
// can also be accessed like build.testResultAction.failCount
manager.listener.logger.println('Total: ' + total)
manager.listener.logger.println('Failed: ' + failed)
manager.listener.logger.println('Skipped: ' + skipped)
manager.listener.logger.println('Passed: ' + (total - failed - skipped))
API for additional TestResultAction methods/properties http://javadoc.jenkins-ci.org/hudson/tasks/test/AbstractTestResultAction.html
If you want to access a matrix build from another job, you can do something like:
def job = Jenkins.instance.getItemByFullName('MyJobName/MyAxisName=MyAxisValue');
def build = job.getLastBuild()
...
For Pipeline (Workflow) Job Type, the logic is slightly different from AlexS' answer that works for most other job types:
build.getActions(hudson.tasks.junit.TestResultAction).each {action ->
action.getTotalCount()
action.getFailCount()
action.getSkipCount()
}
(See http://hudson-ci.org/javadoc/hudson/tasks/junit/TestResultAction.html)
Pipeline jobs don't have a getTestResultAction() method.
I use this logic to disambiguate:
if (build.respondsTo('getTestResultAction')) {
//normal logic, see answer by AlexS
} else {
// pipeline logic above
}
I think you might be able to do it with something like this:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
File fXmlFile = new File("junit-tests.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
println("Total : " + doc.getDocumentElement().getAttribute("tests"))
println("Failed : " +doc.getDocumentElement().getAttribute("failures"))
println("Errors : " +doc.getDocumentElement().getAttribute("errors"))
I also harvest junit xml test results and use Groovy post-build plugin https://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin to check pass/fail/skip counts. Make sure the order of your post-build actions has harvest junit xml before the groovy post-build script.
This example script shows how to get test result, set build description with result counts and also version info from a VERSION.txt file AND how to change overall build result to UNSTABLE in case all tests were skipped.
def currentBuild = Thread.currentThread().executable
// must be run groovy post-build action AFTER harvest junit xml
testResult1 = currentBuild.testResultAction
currentBuild.setDescription(currentBuild.getDescription() + "\n pass:"+testResult1.result.passCount.toString()+", fail:"+testResult1.result.failCount.toString()+", skip:"+testResult1.result.skipCount.toString())
// if no pass, no fail all skip then set result to unstable
if (testResult1.result.passCount == 0 && testResult1.result.failCount == 0 && testResult1.result.skipCount > 0) {
currentBuild.result = hudson.model.Result.UNSTABLE
}
currentBuild.setDescription(currentBuild.getDescription() + "\n" + currentBuild.result.toString())
def ws = manager.build.workspace.getRemote()
myFile = new File(ws + "/VERSION.txt")
desc = myFile.readLines()
currentBuild.setDescription(currentBuild.getDescription() + "\n" + desc)
I need to copy a file in Groovy and saw some ways to achieve it on the web:
1
new AntBuilder().copy( file:"$sourceFile.canonicalPath",
tofile:"$destFile.canonicalPath")
2
command = ["sh", "-c", "cp src/*.txt dst/"]
Runtime.getRuntime().exec((String[]) command.toArray())
3
destination.withDataOutputStream { os->
source.withDataInputStream { is->
os << is
}
}
4
import java.nio.file.Files
import java.nio.file.Paths
Files.copy(Paths.get(a), Paths.get(b))
The 4th way seems cleanest to me as I am not sure how good is it to use AntBuilder and how heavy it is, I saw some people reporting issues with Groovy version change.
2nd way is OS dependent, 3rd might not be efficient.
Is there something in Groovy to just copy files like in the 4th statement or should I just use Java for it?
If you have Java 7, I would definitely go with
Path source = ...
Path target = ...
Files.copy(source, target)
With the java.nio.file.Path class, it can work with symbolic and hard links. From java.nio.file.Files:
This class consists exclusively of static methods that operate on
files, directories, or other types of files. In most cases, the
methods defined here will delegate to the associated file system
provider to perform the file operations.
Just as references:
Copy files from one folder to another with Groovy
http://groovyconsole.appspot.com/view.groovy?id=8001
My second option would be the ant task with AntBuilder.
If you are doing this in code, just use something like:
new File('copy.bin').bytes = new File('orig.bin').bytes
If this is for build-related code, this would also work, or use the Ant builder.
Note, if you are sure the files are textual you can use .text rather than .bytes.
If it is a text file, I would go with:
def src = new File('src.txt')
def dst = new File('dst.txt')
dst << src.text
I prefer this way:
def file = new File("old.file")
def newFile = new File("new.file")
Files.copy(file.toPath(), newFile.toPath())
To append to existing file :
def src = new File('src.txt')
def dest = new File('dest.txt')
dest << src.text
To overwrite if file exists :
def src = new File('src.txt')
def dest = new File('dest.txt')
dest.write(src.text)
I'm using AntBuilder for such tasks. It's simple, consistent, 'battle-proven' and fun.
2nd approach is too OS-specific (Linux-only in your case)
3rd it too low-level and it eats up more resources. It's useful if you need to transform the file on the way: change encoding for example
4th looks overcomplicated to me... NIO package is relatively new in JDK.
In the end of the day, I'd go for 1st option. There you can switch from copy to scp task, without re-developing the script almost from scratch
This is the way using platform independent groovy script. If anyone has questions please ask in the comments.
def file = new File("java/jcifs-1.3.18.jar")
this.class.classLoader.rootLoader.addURL(file.toURI().toURL())
def auth_server = Class.forName("jcifs.smb.NtlmPasswordAuthentication").newInstance("domain", "username", "password")
def auth_local = Class.forName("jcifs.smb.NtlmPasswordAuthentication").newInstance(null, "local_username", "local_password")
def source_url = args[0]
def dest_url = args[1]
def auth = auth_server
//prepare source file
if(!source_url.startsWith("\\\\"))
{
source_url = "\\\\localhost\\"+ source_url.substring(0, 1) + "\$" + source_url.substring(1, source_url.length());
auth = auth_local
}
source_url = "smb:"+source_url.replace("\\","/");
println("Copying from Source -> " + source_url);
println("Connecting to Source..");
def source = Class.forName("jcifs.smb.SmbFile").newInstance(source_url,auth)
println(source.canRead());
// Reset the authentication to default
auth = auth_server
//prepare destination file
if(!dest_url.startsWith("\\\\"))
{
dest_url = "\\\\localhost\\"+ dest_url.substring(0, 1) + "\$" +dest_url.substring(2, dest_url.length());
auth = auth_local
}
def dest = null
dest_url = "smb:"+dest_url.replace("\\","/");
println("Copying To Destination-> " + dest_url);
println("Connecting to Destination..");
dest = Class.forName("jcifs.smb.SmbFile").newInstance(dest_url,auth)
println(dest.canWrite());
if (dest.exists()){
println("Destination folder already exists");
}
source.copyTo(dest);
For copying files in Jenkins Groovy
For Linux:
try {
echo 'Copying the files to the required location'
sh '''cd /install/opt/
cp /install/opt/ssl.ks /var/local/system/'''
echo 'File is copied successfully'
}
catch(Exception e) {
error 'Copying file was unsuccessful'
}
**For Windows:**
try {
echo 'Copying the files to the required location'
bat '''#echo off
copy C:\\Program Files\\install\\opt\\ssl.ks C:\\ProgramData\\install\\opt'''
echo 'File is copied successfully'
}
catch(Exception e) {
error 'Copying file was unsuccessful'
}