SOAPUI: Read http log with groovy script - groovy

is there any way to read http log for specific test step?
In my http log there are several response-requests messages for current test step.
The following code gives me only first request/last response, but I need to take value from
second response.
log.info context.expand('${getHashValue#Request}')
log.info context.expand('${getHashValue#Response}')
Any ideas?
Thanks.
UPD:

Below code can get any kind of soap ui logs
def logArea = com.eviware.soapui.SoapUI.logMonitor.getLogArea( "http log" )
//error log can be replaced with jetty log, script log, SoapUI log, error log,memory log, wsrm log
if( logArea !=null )
{
def model = logArea.model
if( model.size > 0 )
for( c in 0..(model.size-1) )
{
def value= model.getElementAt(c).toString()
if(value.contains("ETag")) // here you can mention if you want to extract anything particular from the logs
{
log.info "value = " + value
}
}
}
this code can be even little modified to save soap ui logs in a file
credits :- https://webservice-testing.blogspot.in/2012/04/capture-soapui-logs-to-file.html

Related

How do I get the Assertion success or fail message through an email in JMeter?

I'm trying to get the Assertion results through an email.
There are several endpoints(requests) and associated assertions in my test plan.
Below is the Groovy code I'm using in JSR223 PreProcessor. In My SMTP Sampler, I've been using ${body} to get the results from the script.
But in email prints null when all the Assertions are passing and print exceptions when those are failing.
I need to get below through email.
Success message when there are all the assertions are passing
Fail message with the failure request name when they
import org.apache.jmeter.assertions.AssertionResult;
AssertionResult[] results = prev.getAssertionResults();
StringBuilder body = new StringBuilder();
for (AssertionResult result : results) {
body.append(result.getFailureMessage());
body.append(System.getProperty("line.separator"));
}
vars.put("body", body.toString());
JSR223 PreProcessor is being executed before each Sampler in its scope
prev stands for previous Sampler Result
Assuming above 2 points it is absolutely expected that when JSR223 PreProcessor is being executed before the first Sampler in your test the previous result doesn't exist yet, you just need to add another condition to check whether it is null or not.
import org.apache.jmeter.assertions.AssertionResult
if (prev != null) { // ensure that we have the previous sampler result
AssertionResult[] results = prev.getAssertionResults();
StringBuilder body = new StringBuilder();
for (AssertionResult result : results) {
body.append(result.getFailureMessage());
body.append(System.getProperty("line.separator"));
}
vars.put("body", body.toString());
}

How to run script assertion while running the test step?

I am new to groovy script and soap UI. i added script assertion to a test step. how ever when i run the test case, script assertions are not running. i have to manually run it to verify my response is correct.
can anyone help me on this please?
My groovy script test assertion:
import groovy.json.JsonSlurper
//grab response
def response = messageExchange.response.responseContent
//Convert to JsonSluper to access data
def list = new JsonSlurper().parseText(response)
//check delegates are in one session per timeslot
for (i = 0; i < list.size(); i++) {
// find all items for this delegate in this timeslot
def itemsForThisDelegateInThisTimeslot = list.findAll {element -> element.delegateId == list[i].delegateId && element.agendaItemId== list[i].agendaItemId}
log.info(list[i].delegateId)
// there should not be more than 1
if(itemsForThisDelegateInThisTimeslot.size() > 1) {
log.info(list[i].delegateId + "Delegate already assigned to a workshop at same time");
//Assert fail in execution
throw new Error ('Fail')
}
}
Firstly, there are no assertions in this Script Assertion. Look up Groovy assert.
If you're 'asserting' that the script is Pass or Fail, you need something like...
assert (response.contains('Something from the response'));
or
assert (someBooleanVar == true);
If it passes, the step goes Green. If it fails, it goes Red.
IMHO, it looks you're throwing an exception when the step fails. I would not use an exception in this way. An exception is there to catch and report code issues. Not a test failure.
Regarding exceptions, look up Groovy Try and Catch.
As for this running (or not) when you run a test case. I suspect it is running, but as you're not asserting anything, you can't see the result.
Ever noticed the Script Log tab at the bottom of the screen? All of your log.info statements will be in here when the test step runs. I'd suggest clearing this log (right-click in the Script Log window...), and then running the test case again and have a look in the Script Log for some of your logging messages.

Batch up requests in Groovy?

I'm new to Groovy and am a bit lost on how to batch up requests so they can be submitted to a server as a batch, instead of individually, as I currently have:
class Handler {
private String jobId
// [...]
void submit() {
// [...]
// client is a single instance of Client used by all Handlers
jobId = client.add(args)
}
}
class Client {
//...
String add(String args) {
response = postJson(args)
return parseIdFromJson(response)
}
}
As it is now, something calls Client.add(), which POSTs to a REST API and returns a parsed result.
The issue I have is that the add() method is called maybe thousands of times in quick succession, and it would be much more efficient to collect all the args passed in to add(), wait until there's a moment when the add() calls stop coming in, and then POST to the REST API a single time for that batch, sending all the args in one go.
Is this possible? Potentially, add() can return a fake id immediately, as long as the batching occurs, the submit happens, and Client can later know the lookup between fake id and the ID coming from the REST API (which will return IDs in the order corresponding to the args sent to it).
As mentioned in the comments, this might be a good case for gpars which is excellent at these kinds of scenarios.
This really is less about groovy and more about asynchronous programming in java and on the jvm in general.
If you want to stick with the java concurrent idioms I threw together a code snippet you could use as a potential starting point. This has not been tested and edge cases have not been considered. I wrote this up for fun and since this is asynchronous programming and I haven't spent the appropriate time thinking about it, I suspect there are holes in there big enough to drive a tank through.
That being said, here is some code which makes an attempt at batching up the requests:
import java.util.concurrent.*
import java.util.concurrent.locks.*
// test code
def client = new Client()
client.start()
def futureResponses = []
1000.times {
futureResponses << client.add(it as String)
}
client.stop()
futureResponses.each { futureResponse ->
// resolve future...will wait if the batch has not completed yet
def response = futureResponse.get()
println "received response with index ${response.responseIndex}"
}
// end of test code
class FutureResponse extends CompletableFuture<String> {
String args
}
class Client {
int minMillisLullToSubmitBatch = 100
int maxBatchSizeBeforeSubmit = 100
int millisBetweenChecks = 10
long lastAddTime = Long.MAX_VALUE
def batch = []
def lock = new ReentrantLock()
boolean running = true
def start() {
running = true
Thread.start {
while (running) {
checkForSubmission()
sleep millisBetweenChecks
}
}
}
def stop() {
running = false
checkForSubmission()
}
def withLock(Closure c) {
try {
lock.lock()
c.call()
} finally {
lock.unlock()
}
}
FutureResponse add(String args) {
def future = new FutureResponse(args: args)
withLock {
batch << future
lastAddTime = System.currentTimeMillis()
}
future
}
def checkForSubmission() {
withLock {
if (System.currentTimeMillis() - lastAddTime > minMillisLullToSubmitBatch ||
batch.size() > maxBatchSizeBeforeSubmit) {
submitBatch()
}
}
}
def submitBatch() {
// here you would need to put the combined args on a format
// suitable for the endpoint you are calling. In this
// example we are just creating a list containing the args
def combinedArgs = batch.collect { it.args }
// further there needs to be a way to map one specific set of
// args in the combined args to a specific response. If the
// endpoint responds with the same order as the args we submitted
// were in, then that can be used otherwise something else like
// an id in the response etc would need to be figured out. Here
// we just assume responses are returned in the order args were submitted
List<String> combinedResponses = postJson(combinedArgs)
combinedResponses.indexed().each { index, response ->
// here the FutureResponse gets a value, can be retrieved with
// futureResponse.get()
batch[index].complete(response)
}
// clear the batch
batch = []
}
// bogus method to fake post
def postJson(combinedArgs) {
println "posting json with batch size: ${combinedArgs.size()}"
combinedArgs.collect { [responseIndex: it] }
}
}
A few notes:
something needs to be able to react to the fact that there were no calls to add for a while. This implies a separate monitoring thread and is what the start and stop methods manage.
if we have an infinite sequence of adds without pauses, you might run out of resources. Therefore the code has a max batch size where it will submit the batch even if there is no lull in the calls to add.
the code uses a lock to make sure (or try to, as mentioned above, I have not considered all potential issues here) we stay thread safe during batch submissions etc
assuming the general idea here is sound, you are left with implementing the logic in submitBatch where the main problem is dealing with mapping specific args to specific responses
CompletableFuture is a java 8 class. This can be solved using other constructs in earlier releases, but I happened to be on java 8.
I more or less wrote this without executing or testing, I'm sure there are some mistakes in there.
as can be seen in the printout below, the "maxBatchSizeBeforeSubmit" setting is more a recommendation that an actual max. Since the monitoring thread sleeps for some time and then wakes up to check how we are doing, the threads calling the add method might have accumulated any number of requests in the batch. All we are guaranteed is that every millisBetweenChecks we will wake up and check how we are doing and if the criteria for submitting a batch has been reached, then the batch will be submitted.
If you are unfamiliar with java Futures and locks, I would recommend you read up on them.
If you save the above code in a groovy script code.groovy and run it:
~> groovy code.groovy
posting json with batch size: 153
posting json with batch size: 234
posting json with batch size: 243
posting json with batch size: 370
received response with index 0
received response with index 1
received response with index 2
...
received response with index 998
received response with index 999
~>
it should work and print out the "responses" received from our fake json submissions.

How to stop testcase execution if request fails in soapui using script assertion?

If the soap request has a failure means Status != "HTTP/1.1 200 OK" , testCase should stop and no further steps should run
There is a way to do this in groovy, but i do not want an extra test step to be added in testcase
def headers = testRunner.testCase.getTestStepByName("RequestName").httpRequest.response.responseHeaders['#status#']
if (!headers.contains("HTTP/1.1 200 OK"))
{
testRunner.fail("" + headers + "Flow failed")
testRunner.fail("No futher testSteps will be run inside the current case")
}
Please note i cannot change below settings due to some other groovy code restriction
The reason for not changing above option i have a testcase where there are 10 steps. 1 is request and other 9 steps validate various things. So if i check the "Abort on error" option and step 3 fails. then none of the steps from 4 to 10 runs. So please provide a solution considering not using "abort" option
So could you please provide a solution for script assertion without ticking this option."Abort on error"
Since testRunner.fail is not available inside script assertion and also normal assertion (assert 0==1) does not stop testcase unless we tick the above setting. i am stuck with this limitations
You have access to testRunner through the context variable available in a script assertion, so why not something like:
def httpResponseHeader = messageExchange.responseHeaders
def headers = httpResponseHeader["#status#"]
log.info("Status: " + headers)
if (!headers.contains("HTTP/1.1 200 OK")) {
context.testRunner.fail("" + headers + "Flow failed")
context.testRunner.fail("No futher testSteps will be run inside the current case")
}
Thanks #craigcaulifield, your answer has helped me a lot.
Good to know that testRunner is available even in script assertion in a tricky way
Now using script assertion we can stop a testCase if request fails.
However when we run request alone not as part of testcase an error comes
cannot invoke method fail() on null object
This error comes because
context.testRunner.fail()
testRunner is only available during test Case execution and not individual testStep execution
So to overcome here is the code which can take care of both situation
def responseHeaders=messageExchange.responseHeaders
def status=responseHeaders["#status#"]
// Checking if status is successfully fetched i.e. Response is not empty
if(status!=null)
{
if(!status.contains("HTTP/1.1 200 OK"))
{
// context.testRunner is only available when the request is run as a part of testCase and not individually
if(context.testRunner!=null)
{
// marking the case fail so further steps are not run
context.testRunner.fail()
}
assert false, "Request did not returned successful status. Expected = [HTTP/1.1 200 OK] but Actual = " + status
}
}
else
{
if(context.testRunner!=null)
{
context.testRunner.fail()
}
assert false, "Request did not returned any response or empty response"
}

How to run testcase and testsuite using Groovy in soapui?

i have some projects in soapui.
i want to execute testsuites and testcases of these projects.
i tried with this groovy code:
//get test case from other project or from the same one
project = testRunner.getTestCase().getTestSuite().getProject().getWorkspace().getProjectByName("Project1")
testSuite = project.getTestSuiteByName("TestSuite 1 - Login");
testCase = testSuite.getTestCaseByName("TestCase 1-Login");
Thread.sleep(3000)
testSuite2 = project.getTestSuiteByName("TestSuite3 - Report");
testCase2 = testSuite.getTestCaseByName("TestCase1 - Report");
// run test case
runner = testCase.run(new com.eviware.soapui.support.types.StringToObjectMap(), false);
Thread.sleep(3000)
runner2 = testCase2.run(new com.eviware.soapui.support.types.StringToObjectMap(), false);
When i run this groovy code, i have the following error message:
java.lang.NullPointer.Exception
cannot invoke method run() on null object for the last line
runner2 = testCase2.run(new com.eviware.soapui.support.types.StringToObjectMap(), false);
If i remove the last line it's working well.
Any help please.
Thank you
I know this is super late to answer this question, but i will answer this so that it can help help seeking for help.
instead of Thread.sleep(3000), just use:
runner.waitUntilFinished()
Now it will wait until execution of step 1 get finished. Then it will start executing Step 2.
The only thing I can think of is that you're calling the wrong testcase on the step2, I tested the same with other test cases I have and it's happening the same If I put a wrong name for the test case I want to execute.
// TO RUN A TEST SUITEs ALL get APIs, getting testSuite handle from current //test_Case
// TO POST COMMENT I HAVE ADDED underscore char BELOW
// u need to import here
def my_TestSuite = testRunner.testCase.testSuite
log.info(my_TestSuite.name)
for (my_TestCase in my_TestSuite.get_TestCaseList())
{
for (testStep in myTestCase.get_TestStepList())
{
if( testStep instanceof WsdlTestRequestStep || testStep instanceof RestTestRequestStep ) {
def http_Verb = (testStep.getTestRequest().getMethod())
String apiType = http_Verb.toString()
if (apiType == "GET"){
log.info(myTestCase.name)
}
}
}
}

Resources