SOAPUI Assertion script writing twice to file - groovy

I am writing a groovy script where I am extracting text from a response and writing it to an output file on my system. The problem I encounter is when I run the groovy script that calls the test. The script assertions runs and logs the text twice to the file.
It seems to write to the file just before it leaves the assertion.
I have tried the following:
...
...
if (context.alreadyWritten == null || !context.alreadyWritten) {
inputFile.append (testString+ "\n")
log.info testString
} else {
log.info ('Already written!')
}
I have set the flag (context.alreadyWritten) to false in groovy before I execute the test step.
SOAPUI version : 5.3.0
I see there was an issue previous with Smartbear when appending to file in an assertion script. However the workaround was advised to resolve this:
if (context.alreadyWritten == null || !context.alreadyWritten) {
}
Which does not resolve my issue
When I log the result using log.info I see only one instance of the message been logged.
Any ideas.
Thanks

If you are using Script Assertion, try below:
//Define the file name, change as needed
def fileName = '/path/to/file.xml'
//check if you got the response
if (context.response) {
log.info 'Response available and not empty'
def file = new File(fileName)
if (!context?.alreadySaved) {
file.write(context.response)
context.alreadySaved = true
log.info 'response written to file'
} else {
log.info 'Response already written'
}
} else {
log.info 'there is no response to save'
}

Related

How does scripted Jenkins Pipeline with Groovy work

stage('deploy') {
steps {
script {
import java.net.URL;
import java.net.URLConnection;
def serviceURL = ""
if (env.BRANCH_NAME == "master") {
serviceURL="http://myserver:8100/jira/rest/plugins/1.0"
}
if (env.BRANCH_NAME == "develop") {
serviceURL = "http://myserver:8100/jira/rest/plugins/1.0"
}
if(env.BRANCH_NAME.startsWith("release")
{
serviceURL="http://myserver:8100/jira/rest/plugins/1.0"
}
// Request to get token
URL myURL = new URL(serviceURL+"?"+"os_authType=basic");
HttpURLConnection myURLConnection = (HttpURLConnection)myURL.openConnection();
}
This is an extract of my jenkinsfile. It is written in Groovy .
Right now I get this error:
WorkflowScript: 66: expecting ')', found 'URL' # line 66, column 17.
It is complaining about this line:
URL myURL = new URL(serviceURL+"?"+"os_authType=basic");
I do not know why. But one thing I was wondering now.
How does it actually work with imports. I mean normally you have to do
import java.net.URL
How would it actually work with extern libraries which are not part of Java SDK.
Normally you would put them on the classpath. How would that work with jenkinsfile scripted pipeline. So I wonder when you can actually use jenkinsfile with groovy or when to better
create an own project and create job for it and then add it in the jenkinsfile.
You don't have to import java.net.*, groovy imports them by default. https://groovy-lang.org/structure.html#_default_imports.
Your problem is a result of a missing ) in the line:
if(env.BRANCH_NAME.startsWith("release")
it should be
if(env.BRANCH_NAME.startsWith("release"))
The whole script should look like so in idiomatic Groovy:
stage('deploy') {
steps {
script {
String serviceURL
switch(env.BRANCH_NAME)
case 'master':
case 'develop':
serviceURL = "http://myserver:8100/jira/rest/plugins/1.0"
break
case ~/^release.*$/:
serviceURL = "http://myserver:8100/jira/rest/plugins/1.0"
break
default:
throw new Exception( 'Unknown' )
}
// Request to get token
"${serviceURL}?os_authType=basic".toURL().openConnection().with{
if( 200 != responseCode ) return
outputStream.withWriter{ it << jsonInputString }
}
}
}
}
Here the withWriter{} takes care about stream flushing and closing.

Reading an environment variable set by a test in Jenkins pipeline

Not found any reference to this particular question.
I am looking to find a way to achieve something like this in a Jenkins pipeline which runs our acceptance tests using Protractor and Cucumber.js:
steps {
container('selenium') {
script {
try {
{
//run tests
}
}
catch (err) {
if (env.testFailed == 'true') {
println "A test failure exists - build status updated to failure"
currentBuild.result = 'FAILURE'
error "Test(s) have failed"
}
else {
println "No test failures exist - build status updated to success"
currentBuild.result = 'SUCCESS'
}
}
}
}
}
This would fail the build if the env var of testFailed is 'true'. The reason for this is we are encountering bugs with Protractor-Cucumber framework where if a failed test retries and passes the exit code of the stage is still 1.
So in the After hook of each test I am setting the env var using node.js to true if the Scenario status is failed:
if (scenario.result.status === Status.FAILED) {
process.env.testFailed = 'true';
}
if (scenario.result.status === Status.PASSED) {
process.env.testFailed = 'false';
}
The problem I have found is that the Jenkins pipeline fails to read the env var value in the code block of the catch section. It is always null.
Any ideas?
1) change the After hook to write the true/false flag to a file in sync.
2) read the file in catch block
catch(err) {
testFailed = sh(script:'cat result.flag.txt', returnStdout: true).trim()
if(testFailed == 'true') {
...
}
}
Another option if there is total/passed/failed case number in output of npm test
lines = []
try {
lines = sh(script:'npm test', returnStdout: true).readLines();
}
catch(err) {
size = lines.size()
// parse the last 20 lines to extract fail/pass/total number
for(int i=size-20;i<size;i++) {
line[i]
}
}
WHY IT DOESN'T WORK NOW?
I see that you're running your tests in a container. When you set an environment variable, it's reflected on the scope of your container not the Jenkins master server
WHAT YOU COULD TRY TO DO
This actually depends on how you run the tests, but this should be an option
// run tests here
// you should have a variable for your container
def exit_code = sh(script: "sudo docker inspect ${container.id} --format='{{.State.ExitCode}}'", returnStdout: true)
sh "exit ${exit_code}"
This actually also depends how you start the tests inside the container,
So if you update your answer with this information I could help you

groovy script not working in nifi executescript processor

I'm trying to execute something via executescript processor; a groovy code inside. In the code I'm trying to create a scala script which is to be executed on spark in a further processor.
// Get flow file
def flowFile = session.get()
if (!flowFile) return
// Create output directory
def userInputDir = flowFile.getAttribute("user.input.path")
def finalFolder = new File(userInputDir + "/" + innerDir)
try
{
if (!finalFolder.exists()) finalFolder.mkdirs()
// Write script
file = "spark.sqlContext.setConf(\"hive.exec.dynamic.partition\", \"true\")\n"
file = file + "spark.sqlContext.setConf(\"hive.exec.dynamic.partition.mode\", \"nonstrict\")\n"
file = file + "import org.apache.spark.sql._"
file = file + "\n"
file = file + "import java.io._"
file = file + "\n"
}
.
.
.
The rest other steps are adding some other spark specific commands to the script variable. Script is huge so skipping the full code paste.
Finally, closing with a catch
// Output file path
flowFile = session.putAttribute(flowFile, "generatedScript", scalaFile.getCanonicalPath())
session.transfer(flowFile, REL_SUCCESS)
}
catch(Exception e)
{
log.info("File: {}\n", finalFolder.file)
session.transfer(flowFile, REL_FAILURE)
}
The processor is not even beginning to start the groovy script execution and it fails with the error:
groovy.lang.MissingPropertyException: No such property: script for calss: javal.io.File
By the statement 'not even beginning to start' means that the previous queue is not empty and the processor throws the error. I'm guessing it's a syntax issue but I don't find any syntactical problems related in the script. I also tried running the script in local machine's groovy shell and have the same error there as well, but no syntax issue.
Googling the error got me the suggestion to include the imports in the script but even after including the relevant imports the error is the same.
Any clues?
You're referring to a variable "innerDir" which is not defined anywhere. Are you expecting the user to add a user-defined property to ExecuteScript called innerDir? If so, the innerDir variable in the script is a PropertyValue object, so you'd need to call getValue() on it to get the actual value of the property:
innerDir.value
Also you refer to scalaFile.getCanonicalPath() but scalaFile is not defined above, and getCanonicalPath() won't give you the contents of the script, is that what you meant?
I reworked the partial script above to assume that innerDir is a user-defined property and you write the contents of the file variable to a File pointed to by scalaFile; also I made it more Groovy by using heredoc instead of appending to the file variable:
// Get flow file
def flowFile = session.get()
if (!flowFile) return
// Create output directory
def userInputDir = flowFile.getAttribute("user.input.path")
def finalFolder = new File(userInputDir + "/" + innerDir?.value ?: '')
try
{
if (!finalFolder.exists()) finalFolder.mkdirs()
// Write script
file =
"""
spark.sqlContext.setConf("hive.exec.dynamic.partition", "true")
spark.sqlContext.setConf("hive.exec.dynamic.partition.mode", "nonstrict")
import org.apache.spark.sql._
import java.io._
"""
scalaFile = new File(finalFolder, 'script.scala')
scalaFile.withWriter {w -> w.write(file)}
// Output file path
flowFile = session.putAttribute(flowFile, "generatedScript", scalaFile.canonicalPath)
session.transfer(flowFile, REL_SUCCESS)
}
catch(Exception e) {
log.info("File: {}\n", finalFolder.file)
session.transfer(flowFile, REL_FAILURE)
}

Automatically downloading Groovy console logs from Soap UI

I have Soap UI Pro. I am able to download all the system generated reports. I have a groovy script as one of the test steps and I am writing some transaction logs using log.info(). When I execute my test suite, I also want my console logs to be automatically downloaded to my machine. Can someone let me know if this is possible ?
or can I write my log.info() values to the system generated logs ?
There is my script to save the Script log to a file.
def loggerSize = 0
log.info "first log"
log.info "second log"
def logArea = null
logArea = com.eviware.soapui.SoapUI.logMonitor.getLogArea( "Script log" ); // Or HHTP log, Jetty log, Script log; each tab name in log part, can't capture 'Log Output' part ...
def model = null
def logger = ""
if( logArea != null ){
model = logArea.model
if( model.size > loggerSize ){
for(c in loggerSize..(model.size-1)){
logger += model.getElementAt(c).toString() + "##"
}
}
}
return logger

Running SoapUI test cases using testRunner

I am working on a SoapUI project where I need to run my test suite using test runner. I am using external groovy scripting for environment variable. The problem I am facing here is whenever I am running test case from test runner its return Workspace as null, which is used in External groovy. So in external groovy I am getting workspace as null causing error [getProjectByname() cannot be invoked on null]. Below is the
constructor of global script where workspace is used
AvengerAPITestManager(String TestProject, String TestSuite, String TestCase,String TestStep)
{
TestName = "AvengerAPITests";
testProject = SoapUI.getWorkspace().getProjectByName(TestProject);
tSuite = testProject.getTestSuiteByName(TestSuite);
tCase = testProject.getTestSuiteByName(TestSuite).getTestCaseByName(TestCase);
tStepName = TestStep.toString();
tStep=testProject.getTestSuiteByName(TestSuite).getTestCaseByName(TestCase).getTestStepByName (TestStep);
}
Above we have user SoapUI.getWorkspace() which is working fine when trying to run from soapUI but whever I m trying to run from testrunner SoapUI.getWorkspace comes out to be null. I even tried passing workspace like I am passing testproject name still it didnt worked.
I tried something like this also
AvengerAPITestManager(Object workspace,String TestProject, String TestSuite, String TestCase, String TestStep)
{
TestName = "AvengerAPITests";
testProject = workspace.getProjectByName(TestProject);
tSuite = testProject.getTestSuiteByName(TestSuite);
tCase = testProject.getTestSuiteByName(TestSuite).getTestCaseByName(TestCase);
tStepName = TestStep.toString();
tStep = testProject.getTestSuiteByName(TestSuite).getTestCaseByName(TestCase).getTestStepByName(TestStep);
}
In the above code I tries passing Workspace object from the test case as I passed Testcase name and all but still I m getting null for workspace. Please tell me how do I deal with the problem.
Here is usefull working example https://github.com/stokito/soapui-junit
You should place your sample-soapui-project.xml to /src/test/resources folder that will expose it to classpath
If you want to use soap ui in external code, try to directly create new test runner with specific project file:
SoapUITestCaseRunner runner = new SoapUITestCaseRunner();
runner.setProjectFile( "src/dist/sample-soapui-project.xml" );
runner.run();
Or if you want to define test execution more precisely, you can use something like this:
WsdlProject project = new WsdlProject( "src/dist/sample-soapui-project.xml" );
TestSuite testSuite = project.getTestSuiteByName( "Test Suite" );
TestCase testCase = testSuite.getTestCaseByName( "Test Conversions" );
// create empty properties and run synchronously
TestRunner runner = testCase.run( new PropertiesMap(), false );
PS: don't forget to import soap ui classes, that you use in your code and put them to classpath.
PPS: If you need just run test cases outside the soap ui and/or automate this process, why not just use testrunner.sh/.bat for the same thing? (here is description of this way: http://www.soapui.org/Test-Automation/functional-tests.html)
I am not sure if this is going to help anyone out there but here is what I did to fix the problem I was having with workspace as null causing error[getProjectByname() cannot be invoked on null] When i run from cmd
try this:
import com.eviware.soapui.model.project.ProjectFactoryRegistry
import com.eviware.soapui.impl.wsdl.WsdlProjectFactory
import com.eviware.soapui.impl.wsdl.WsdlProject
//get the Util project
def project = null
def workspace = testRunner.testCase.testSuite.project.getWorkspace();
//if running Soapui
if (workspace != null) {
project = workspace.getProjectByName("Your Project")
}
//if running in Jenkins/Hudson
else{
project = new WsdlProject("C:\\...\\....\\....\\-soapui-project.xml");
}
if (project.open && project.name == "Your Project") {
def properties = new com.eviware.soapui.support.types.StringToObjectMap()
def testCase = project.getTestSuiteByName("TestSuite 1").getTestCaseByName("TestCase");
if(testCase == null)
{
throw new RuntimeException("Could not locate testcase 'TestCase'! ");
} else {
// This will run everything in the selected project
runner = testCase.run(new com.eviware.soapui.support.types.StringToObjectMap(), false)
}
}
else {
throw new RuntimeException("Could not find project ' Order Id....' !")
}
The above code will run everything in the selected project.

Resources