string comparison does not match but 'contains' does - groovy

I have a strange problem using groovy, I found a workaround but I'm quite not satisfied so maybe someone will be able to help me:
I use ReadyAPI 2.8. In my test cases I have groovy steps.
In one of those, I recover a String from a previous test step and I want to do a particular processing if it matches the string "TJA470". The previous test step gives a string that is the output of a ssh command.
here is the groovy step code :
def hbox_ref = context.expand( '${get current HBox reference#hbox_ref}' )
// this returns me the data as a String
log.info hbox_ref
log.info "\"$hbox_ref\"" // to check if there is no spurious blank
log.info hbox_ref.class
log.info (hbox_ref == "TJA470") => returns false
log.info (hbox_ref.equals("TJA470")) => returns false
log.info (hbox_ref.contains("TJA470")) => returns true
here is the console result :
Fri Sep 20 16:13:17 CEST 2019: INFO: TJA470
Fri Sep 20 16:13:17 CEST 2019: INFO: "TJA470
"
Fri Sep 20 16:13:17 CEST 2019: INFO: class java.lang.String
Fri Sep 20 16:13:17 CEST 2019: INFO: false
Fri Sep 20 16:13:17 CEST 2019: INFO: false
Fri Sep 20 16:13:17 CEST 2019: INFO: true
The straighforward test is == or equals though there are differences, I use those in all the other comparisons of the same type and it works.
As you can see here the most logic cases return false and I really can't work out why.
If I do the same script in a tool like 'groovy playground' it works as expected ! :(
I'm not an expert in groovy at all and there must be something that I missed, but I find it very tricky !
If anyone can help ...
thanks

Thanks to SO I found out the problem :
with copy/pasting the console return in the question, it shows that there is a special character at the end of the text. This is not visible in SOAPUI log output ...
I added the following processing in my script :
def hbox_ref = context.expand( '${get current HBox reference#hbox_ref}' )
hbox_ref = hbox_ref.replaceAll("[^a-zA-Z0-9]+","")
or
hbox_ref = hbox_ref.replaceAll("[^\\w]+","")
this gives
log.info (hbox_ref == "TJA470") => returns true (at last !)
more elegant solution (thanks to SiKing) :
(hbox_ref.trim() == "TJA470")
instead of using replaceAll

Related

SOUP UI Groovy || For loop is looping 50 times where the condition is using this number anywhere

Here I am just taking value(integer) from Properties file and using the same in for loop.
Note : If I use direct number instead of "getTestCasePropertyValue" value it work as expected. Not getting how loop is looping it 50 times.
Groovy script:
def getTestCasePropertyValue = testRunner.testCase.getPropertyValue( "NumOfPayments" )
log.info(getTestCasePropertyValue )
for(i=0; i<=getTestCasePropertyValue; i++)
{
log.info("Test Print"+i)
}
Output:
Fri Mar 06 12:58:47 IST 2020:INFO:2
Fri Mar 06 12:58:47 IST 2020:INFO:Test Print0
Fri Mar 06 12:58:47 IST 2020:INFO:Test Print1
Fri Mar 06 12:58:47 IST 2020:INFO:Test Print2
Fri Mar 06 12:58:47 IST 2020:INFO:Test Print3
...
Fri Mar 06 12:58:47 IST 2020:INFO:Test Print50
Your value from the properties is a String. You will detect problems like this easier, if you use .inspect() to log things.
Also the character '2' is 50 as integer, which then the for loop conditions casts this too.
def getTestCasePropertyValue = "2"
println(getTestCasePropertyValue.inspect())
// → '2'
println(getTestCasePropertyValue as char as int)
// → 50
So best explicitly cast to a number using e.g. .toLong() on the string:
println(getTestCasePropertyValue.toLong().inspect())
// → 2

rerun a test case in ready api using tear down script

I have a test case "Login" which intermittently fails due to login issues.
I would like to implement a tear down script to get the status of the script and rerun if it failed.
Here is what I implemented and it doesn't work as expected.
testRunner.testCase.setPropertyValue("LoginStatus",
testRunner.getStatus().toString())
def loginStatus = context.expand( '${#TestCase#LoginStatus}' )
int retryAttempts = context.expand( '${#Project#RetryAttempts}' ).toInteger()
def myContext = (com.eviware.soapui.support.types.StringToObjectMap)context
while ( loginStatus == "FAIL" && retryAttempts <= 1) {
retryAttempts = retryAttempts+1
log.info "increment retry attempts-" + retryAttempts
testRunner.testCase.testSuite.project.setPropertyValue( "RetryAttempts",
retryAttempts.toString() )
testCase.run(myContext, false)
log.info "after run statement-"+retryAttempts
}
log.info "before final statement"
testRunner.testCase.testSuite.project.setPropertyValue( "RetryAttempts", "0"
)
The script runs 3 times even though it is configured to rerun once. The logs
Fri May 18 13:55:15 EDT 2018:INFO:increment retry attempts-1
Fri May 18 13:55:16 EDT 2018:INFO:increment retry attempts-2
Fri May 18 13:55:16 EDT 2018:INFO:before final statement
Fri May 18 13:55:16 EDT 2018:INFO:after run statement-2
Fri May 18 13:55:16 EDT 2018:INFO:before final statement
Fri May 18 13:55:16 EDT 2018:INFO:after run statement-1
Fri May 18 13:55:16 EDT 2018:INFO:increment retry attempts-2
Fri May 18 13:55:17 EDT 2018:INFO:before final statement
Fri May 18 13:55:17 EDT 2018:INFO:after run statement-2
Fri May 18 13:55:17 EDT 2018:INFO:before final statement

How to get assertion value using groovy script

I have one test step which contains two assertion.
Not SOAP Fault
Contains. The Condition is that response should contain "Message Sent Successfully"
Now I have one groovy script, from where I am executing this test step. Using this groovy script I need to print assertion name, Value and Status. Below is the code I have written:
testStepSrc = testCase.getTestStepByName(testName)
Assertioncounter = testStepSrc.getAssertionList().size()
for (AssertionCount in 0..Assertioncounter-1)
{
log.info("Assertion :" + testStepSrc.getAssertionAt(AssertionCount).getName() + " :: " + testStepSrc.getAssertionAt(AssertionCount).getStatus())
error = testStepSrc.getAssertionAt(AssertionCount).getErrors()
if (error != null)
{
log.error(error[0].getMessage())
}
}
but in output it is displaying like:
Wed Sep 04 17:21:11 IST 2013:INFO:Assertion :Not SOAP Fault :: VALID
Wed Sep 04 17:21:11 IST 2013:INFO:Assertion :Contains :: VALID
As you can see, I am able to print assertion name and status but not the value of 'Contains' assertion. Please help me how to get the value of a particular assertion.
Thanks in advance.
So here is some things for you to read
http://www.soapui.org/forum/viewtopic.php?t=359
http://whathaveyoutried.com
and what i tried
def assertionsList = testRunner.getTestCase().getTestStepByName("Test Step Name").getAssertionList()
for( e in assertionsList){
log.info e.getToken() //gives the value of the content to search for
log.info e.DESCRIPTION
log.info e.ID
log.info e.LABEL
log.info e.toString()
}
This gives the following output
Wed Sep 04 15:12:19 ADT 2013:INFO:Abhishek //the contains assertion was checking for the word "Abhishek" in the response of my test step where the assertion was applied.
Wed Sep 04 15:12:19 ADT 2013:INFO:Searches for the existence of a string token in the property value, supports regular expressions. Applicable to any property.
Wed Sep 04 15:12:19 ADT 2013:INFO:Simple Contains
Wed Sep 04 15:12:19 ADT 2013:INFO:Contains
Wed Sep 04 15:12:19 ADT 2013:INFO:com.eviware.soapui.impl.wsdl.teststeps.assertions.basic.SimpleContainsAssertion#c4115f0
Abhishek's response did contain you answer I believe but just not in the format you were looking for.
I was looking for the same info for custom reporting and after digging through The SoapUI forms I stumbled upon this.
The piece of code that I believe you are looking for is:
log.info e.getToken()
however this is an example of how to retrieve it only when an error occurs but you can get it in a valid scenario using something similar to:
def iAssertionName = assertionNameList[j]
def iAssertionStatus = testStep.getAssertionAt(j).getStatus().toString()
def tstep = testStep.getName()
def gStatus = testStep.getAssertionAt(j).status
def expect = testStep.getAssertionAt(j).getToken()
log.info "Expected Content: " + expect
This is a subset of my code but produces the log message:
Fri Sep 20 11:04:09 CDT 2013:INFO:Expected Content: success
My SoapUI script assertion was checking to see if my response contained the string "success".
Thanks Abhishek for your response!

Need help - SoapUi testRunner.getStatus() is returning the status as "RUNNING" indefinitely

In SoapUI after executing a soap request test step (which is under a test suite -> test case)
through testRunner.runTestStepByName("Soap Request Name")
and waiting for 10 seconds after that soap request execution testRunner.getStatus() is returning RUNNING status . below is the groovy script (which is under same test suite -> test case)
import groovy.sql.Sql;
import com.eviware.soapui.model.testsuite.TestRunner.Status
testRunner.runTestStepByName("GetCitiesByCountry - Request 1")
sleep(10000)
log.info( "...${testRunner.getStatus()}...")
while ( testRunner.getStatus() == Status.RUNNING ) {
log.info(testRunner.getStatus())
}
the output is below
Wed Apr 17 21:06:22 IST 2013:INFO:RUNNING
Wed Apr 17 21:06:22 IST 2013:INFO:RUNNING
Wed Apr 17 21:06:22 IST 2013:INFO:RUNNING
Wed Apr 17 21:06:22 IST 2013:INFO:RUNNING
Wed Apr 17 21:06:22 IST 2013:INFO:RUNNING
Wed Apr 17 21:06:22 IST 2013:INFO:RUNNING
.
.
continuing for infinite time...
Ideally it should return FINISHED since the above test step is executed ,
Advanced thanks for any help to this
It sounds logical, as long as you are in the loop, the test is 'running'. You can get the status with this:
import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus
myTestStepResult = testRunner.runTestStepByName("GetCitiesByCountry - Request 1")
myStatus = myTestStepResult.getStatus()
if (myStatus == TestStepStatus.OK)
log.info "The step status is: " + myStatus.toString()
else
log.error "The step status is: " + myStatus.toString()
Also, as the call to runTestStepByName is synchronous, there is no 'running' status, only 'CANCELED', 'FAILED', 'OK' or 'UNKNOWN'.
See the doc here

Ways to deal with Daylight Savings time with Quartz Cron Trigger

I have a quartz cron trigger that looks like so:
<bean id="batchProcessCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="batchProcessJobDetail" />
<property name="cronExpression" value="0 30 2 * * ?" />
</bean>
How should I solve this, if I have several configurations that happen within the 2-3am period? Is there an accepted best practice?
Relevant link: http://www.quartz-scheduler.org/docs/faq.html#FAQ-daylightSavings
Basically it says "Deal with it." But my question is how!
I solved it using a separate trigger that only fires (an hour early) on the beginning date of DST for the configurations that happen between 2am and 3am Eastern.
Seems kludgey, but it works...
We are using the following solution. For this you will also need the joda time library.
public class MyCronExpression extends CronExpression
{
CronExpression _orgCronExpression;
public MyCronExpression(String cronExpression) throws ParseException
{
super(cronExpression);
setTimeZone(TimeZone.getTimeZone("UTC"));
_orgCronExpression = new CronExpression(cronExpression);
}
#Override
public Date getTimeAfter(Date date)
{
Date date1 = super.getTimeAfter(new Date(date.getTime()-date.getTimezoneOffset()*60*1000));
if (TimeZone.getDefault().inDaylightTime( date1 ) && !TimeZone.getDefault().inDaylightTime( date ))
{
DateTimeZone dtz = DateTimeZone.getDefault();
Date dstEnd = new Date(dtz.nextTransition(date.getTime()));
int dstEndHour = dstEnd.getHours();
int dstDuration = (dtz.getOffset(date1.getTime()) - dtz.getStandardOffset(date1.getTime()))/(60*60*1000);
int hour = date1.getHours()+date1.getTimezoneOffset()/60;
if (hour < dstEndHour && hour >= dstEndHour-dstDuration)
return dstEnd;
else
return _orgCronExpression.getTimeAfter(date);
}
else
return _orgCronExpression.getTimeAfter(date);
}
}
The class is used as follows:
CronTriggerImpl trigger = new CronTriggerImpl();
trigger.setCronExpression(new MyCronExpression("0 15 2 * * ?"));
Here some sample trigger times:
Tue Mar 25 02:15:00 CET 2014
Wed Mar 26 02:15:00 CET 2014
Thu Mar 27 02:15:00 CET 2014
Fri Mar 28 02:15:00 CET 2014
Sat Mar 29 02:15:00 CET 2014
**Sun Mar 30 03:00:00 CEST 2014**
Mon Mar 31 02:15:00 CEST 2014
Tue Apr 01 02:15:00 CEST 2014
Wed Apr 02 02:15:00 CEST 2014
Please post if you find any bugs/issues with this solution.
I took Ron's very interesting answer and improved the getTimeAfter Method, In order to adjust it to server GMT running and possible differences when scheduling 'Once a year' cron expressions.
#Override
public Date getTimeAfter(Date date) {
Date nextDate = super.getTimeAfter(date);
if(nextDate == null){
return null;
}
DateTime date1 = new DateTime(nextDate);
if (getTimeZone().inDaylightTime(date1.toDate()) && !getTimeZone().inDaylightTime(date)) {
DateTimeZone dtz = DateTimeZone.forTimeZone(getTimeZone());
DateTime dstEndDateTime = new DateTime(new Date(dtz.nextTransition(date.getTime())));
int dstEndHour = dstEndDateTime.getHourOfDay();
int dstDuration = (dtz.getOffset(date1.getMillis()) - dtz.getStandardOffset(date1.getMillis())) / (60 * 60 * 1000);
int hour = date1.getHourOfDay();
// Verifies if the scheduled hour is within a phantom hour (dissapears upon DST change)
if (hour < dstEndHour && hour >= dstEndHour-dstDuration){
// Verify if the date is a skip, otherwise it is a date in the future (like threads that run once a year)
if(dstEndDateTime.getDayOfYear() == date1.minusDays(1).getDayOfYear()){
return dstEndDateTime.toDate();
}else{
return nextDate;
}
}else{
return nextDate;
}
} else{
return nextDate;
}
}
Please note my server runs in GMT mode, therefore I do not use some of the offset conversions present in Ron's answer.
Also I discovered a Quartz bug, in which if you use the following configuration, it will fail because it is not capable of processing the cron expression correctly:
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
String cron = "0 15 2 8 3 ? 2015";
FailsafeCronExpression cronExpression = new FailsafeCronExpression(cron);
cronExpression.setTimeZone(DateTimeZone.forID("America/Vancouver"));
DateTime nextDate = new DateTime(cronExpression.getTimeAfter(sdf.parse("12/11/2014 10:15:00")));
This actually seems to happen because DST change takes place during 9th of March 2am for Vancouver and seems the Quartz internal implementation of the super.getTimeAfter(date) method will always send null.
I hope this information is useful.
I'm aware this question is quite old, but it still seems valid. I believe i've found a way to solve this problem, i'l leave it here in case someone else sumbles upon it and finds it handy
With spring 5.3 comes improved scheduling, rewritten using java.time API. It also supports quartz-specific extensions to cron expressions.
Example computation code:
public Instant calculateNextExecution(String cronExpression, Instant lastExecutionInstant, ZoneId executionZoneId) {
LocalDateTime lastExecutionDateTimeInExecutionZone lastExecutionInstant.atZone(executionZoneId)
.toLocalDateTime();
LocalDateTime nextExecutionDateInExecutionZone = CronExpression.parse(cronExpression).next(lastExecutionDateTimeInExecutionZone);
// skipped checking and handling nonexistant next execution
ZoneOffsetTransition transition = executionZoneId.getRules().getTransition(nextExecutionDateInExecutionZone);
if (transition == null) {
// next execution didn't occur during time transition
return nextExecutionDateInExecutionZone.atZone(executionZoneId)
.toInstant();
} else {
// next execution occured during time transition, one might check if transition was a gap or overlap and do sth with it
return doSthWithIt(transition, nextExecutionDateInExecutionZone);
}
}
Relevant spring class is org.springframework.scheduling.support.CronExpression.
Detailed description https://spring.io/blog/2020/11/10/new-in-spring-5-3-improved-cron-expressions
#update: Spring scheduler doesn't support years in cron expressions :( so it might not work in you scenario

Resources