Forum Discussion

amitst's avatar
amitst
Occasional Contributor
7 years ago

context.ThreadIndex is always zero in the target test case called through "Run Test Case Step"

I have written following groovy code in the target test case called from a source test case (in a thread-safe way with "create isolated copy for reach run").

 

testRunner.testCase.testSuite.setPropertyValue("token" + context.ThreadIndex);

 

The source test case uses the tokenNUM variable while sending its request.

 

I have noticed that when running as a LoadTest with multiple threads, the called test case is always setting token0 variable in the test suite level. While the source test case is trying to use token1, token2, .... etc. variables through each thread.

 

Is it possible to pass/set ThreadIndex based variables from called test case nased on the ThreadIndex of the caller?

  • Here's how you can implement something similar to what the "Run Test Case" test step is doing. In fact, I pinched this from the Source Code in:

    src/main/java/com/eviware/soapui/impl/wsdl/teststeps/WsdlRunTestCaseTestStep.java

    FIrst, add this method to your script :

    import com.eviware.soapui.SoapUI;
    import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase
    import com.eviware.soapui.config.TestCaseConfig
    import com.eviware.soapui.config.LoadTestConfig;
    
    private WsdlTestCase createTestCase(WsdlTestCase testCase) {
       testCase.beforeSave();
       try {
           TestCaseConfig config = TestCaseConfig.Factory.parse(testCase.getConfig().xmlText());
           config.setLoadTestArray(new LoadTestConfig[0]);
           WsdlTestCase wsdlTestCase = testCase.getTestSuite().buildTestCase(config, true);
           wsdlTestCase.afterLoad();
           return wsdlTestCase;
       } catch (Throwable e) {
           SoapUI.logError(e);
       }
    
       return null;
    }

    And then in the code you posted, replace

    def myTestCase = myTestSuite.getTestCaseByName("Login") 

    by:

    def myTestCase = createTestCase( myTestSuite.getTestCaseByName("Login") )

    This should fix your threading issues!

  • amitst's avatar
    amitst
    Occasional Contributor

    Looks like I was trying to solve the issue in a wrong manner. To solve the issue, instead of setting the 'token' property at Test Suite level, I set it at Test Case level in my groovy script.

     

    Also after setting the property and running the test case once, I could see the 'token0' variable in the "run test case" properties dialog box (in the "values to return" section).

     

    I simply checked this variable (so that it is returned to caller) and used "token0" variable in my source test case's request. Every thread in my source test case got different value for 'token0' and the load test was able to run successfully with multiple threads.

    • amitst's avatar
      amitst
      Occasional Contributor

      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?

      • amitst's avatar
        amitst
        Occasional Contributor

        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?