Formatting SQL queries in SoapUI JDBC test steps - groovy

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

Related

Groovy script for hitting the same request with different value for multiple times

I am new to SOAP UI (using SOAP UI free version). I have a SOAP request XML and I need to run the same request multiple times passing different value for one tag each time. Can anyone please help me with the Groovy script that can be used here.
You can use the below sample to do the same. place all your test condition on local and fetch and run one-by-one
import com.eviware.soapui.support.XmlHolder;
import groovy.io.FileType;
import java.nio.file.Files;
import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context );
// Folder location , where input files are present, can be change or replace with new location. but same location has to be given here.
def sInputXMLpath = "C:\\TestFilesFolder\\RequestFiles\\"
// Test suites name : can be change or replace with new name. but same location has to be given here.
def sTestSet = testRunner.testCase.testSuite.project.testSuites["Demo"]
//if you have mutliple test cases, please change the index..... it will start with 0..( being first test case )
def sTestCase = sTestSet.getTestCaseAt(0)
log.info "TestCase.name : " + sTestCase.name
def iCountTestSteps = sTestCase.getTestStepCount()
log.info "Total Test Count of Test Steps in your TestSuite : " + iCountTestSteps
def i = 1
new File(sInputXMLpath).eachFile
{
def sInputFileName = it.name[0..-1]
log.info "Processing the file " + sInputFileName
log.info "**********************************************************************"
log.info "Test Number_"+ i +"_is Executing"
log.info "**********************************************************************"
log.info "Request of InputFileName : " + sInputFileName + " Is Executing "
def sTrimName = sInputFileName
sInputFileName = sTrimName.replaceAll(".xml","")
sInputFileContent = it.getText('UTF-8')
sTestCase.getTestStepAt(0).getProperty("Request").setValue(sInputFileContent);
//log.info "Request content : " + sTestCase.getTestStepAt(0).getProperty("Request").getValue()
testRunner.runTestStepByName("TestStepforRequest")
log.info "Info :TestStepforRequest get Called "
i++
}
In SoapUI speak, this is a data-driven test. SoapUI Pro version has really good support for this, but it is not enabled in the free version.
This is a rather common question on Stack Overflow, see this post which also includes a link to a page which describes how you can 'bend' the free version to run data-driven tests.
If you're not tied to SopaUI, you might want to try Postman. The free version of Postman has data-driven tests out of the box. See this link from the Postman site about using data files for testing.

Load the build.json file of the specific project automatically without hardcoding

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

Jenkins Build Test Case pass fail count using groovy script

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)

SoapUI + Groovy + Get 3 test data from 3 different environment respectively

In SoapUI, We have 3 different environment and 3 different test data property files.
So my problems are:
How to set 3 different end points in SoapUI?
How to get test data as per the environment using Groovy?
I try to answer your questions
1.- How to set 3 different end points in SoapUI.
Set your test steps URL with a property like:
http://${#Project#endpoint}
And add the endpoint property in your test data file.
2.- How to get test data as per the environment using Groovy.
If you have a typical property file with key=value you can use the code shown below:
// read property file
def properties = new java.util.Properties();
properties.load( new java.io.FileInputStream( "/tmp/sample.properties" ));
proj = testRunner.testCase.testSuite.project;
def names = [];
names = properties.propertyNames();
while( names.hasMoreElements() )
{
def name = names.nextElement();
log.info name + " " + properties.getProperty(name);
proj.setPropertyValue(name, properties.getProperty(name)) ;
}
With this you save all properties in the project level, if you prefer to save in testCase or testSuite use testRunner.testCase or testRunner.testCase.testSuite instead of testRunner.testCase.testSuite.project.
Hope this helps,

How to copy files in Groovy

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'
}

Resources