Forum Discussion
Unfortunately my above reply solved only half the issue. I am able to return a distinct value from the called test case to the caller in each thread.
However, my called test case is still considering context.ThreadIndex value as 0 and I am unable to use context.ThreadIndex to pickup a distinct variable for each thread in the called test case itself.
So the below request in the called test case is always using username0 and password0 variables from Project level instead of each thread using username1/password1, username2/password2 and so on from the Project level.
<myrequest><user>${=context.testCase.testSuite.project.getPropertyValue("username"+context.ThreadIndex)}</user><password>${=context.testCase.testSuite.project.getPropertyValue("password"+context.ThreadIndex)}</password></myrequest>
I also tried checking the "copy LoadTest related properties in the target context" option in the run test case step options dialog.
Any tips? Is it possible to pass arguments to called test case so that each caller thread instance can pass distinct value?
The above issue is solved after I called the test case through Groovy script and passing a new context to it while running. Similarly returning the context from the run test case and using properties set in the run test case back in the parent test case.
The groovy step looks like below (that calls Login test case).
import com.eviware.soapui.support.types.StringToObjectMap
// get test suite
def myTestSuite = testRunner.testCase.testSuite.project.getTestSuiteByName("TestSuite 1")
// get your test case
def myTestCase = myTestSuite.getTestCaseByName("Login")
// set the user and password properties in the context
context.setProperty("username", context.testCase.testSuite.project.getPropertyValue("username" + context.ThreadIndex))
context.setProperty("password", context.testCase.testSuite.project.getPropertyValue("password" + context.ThreadIndex))
// run the testCase passing the context
def contextMap = new StringToObjectMap( context )
def calledTestRun = myTestCase.run(contextMap,false);
def myContext = calledTestRun.getRunContext()
token = myContext.testCase.getPropertyValue("token")
context.setProperty("token", token)
The login test case (called test case) used ${#username} and ${#password} variables in its request to use distinct login credential values for each thread.
Similarly the groovy script inside the login test case set a 'token' property inside context.testCase.setPropertyValue(). This will be extracted by caller by getting the context.
During the load test I have observed that in 1 in 15 times, I saw 2 threads overwriting each other's token (around 3-4 invalid token errors after say 50 successful logins).
Can you please let me know if getRunContext() call is not thread-safe after running the test case?
Where you have:
myContext.testCase.setPropertyValue(...)
This means:
myContext.getTestCase().setPropertyValue(...)
and getTestCase() returns the actual test case itself, i.e. the object that you are setting the property on is NOT unique to your run context.
(edited: I had some incorrect advice below here)
Also I'm not sure what this is supposed to do:
def contextMap = new StringToObjectMap( context ) def calledTestRun = myTestCase.run(contextMap,false); def myContext = calledTestRun.getRunContext()
I would have thought that this is just creating two references to the same object:
assert contextMap.is(myContext)
Isn't it?
Thanks for your response JHunt. Yes, both variables should point to the same one. I didn't realise that the contextMap passed on to the run() method is itself getting updated after the test case is run.
I will try out your solution and post the response.
EDIT: I guess you have removed part of your advice from the above post. Shouldn't context.setProperty('token', somevalue) work from the called test case and caller extract it using contextMap.getProperty('token')?