Forum Discussion

stevieoh's avatar
stevieoh
New Contributor
9 months ago

Get Source URL from Request into Mock Service

I am sending a request into my Mock Service and I want to read in the requests source URL, the reason being I am mocking an asynchronous responses so I want to be able to set the endpoint for the other additional responses I will send via a TestSuite's Test Case.

I am triggering the send of additional responses / test case through "AfterRequest Script".

Any advice, I assume I need to be able to look at the mockRequest to get the info but I haven't been able to successfully view the value as plain text

This is what I was getting:

Tue Jan 09 10:48:21 GMT 2024:INFO:[Ljava.lang.String;@4453ba5f

 

Here's the very badly written code I have for it...

<SPAN class="token comment">// create XmlHolder for request content</SPAN>
<SPAN class="token keyword">def</SPAN> holder <SPAN class="token operator">=</SPAN> <SPAN class="token keyword">new</SPAN> <SPAN class="token class-name">com<SPAN class="token punctuation">.</SPAN>eviware<SPAN class="token punctuation">.</SPAN>soapui<SPAN class="token punctuation">.</SPAN>support<SPAN class="token punctuation">.</SPAN>XmlHolder</SPAN><SPAN class="token punctuation">(</SPAN> mockRequest<SPAN class="token punctuation">.</SPAN>requestContent <SPAN class="token punctuation">)</SPAN>

<SPAN class="token keyword">def</SPAN> config <SPAN class="token operator">=</SPAN> holder<SPAN class="token punctuation">.</SPAN>getEndpoint

log<SPAN class="token punctuation">.</SPAN>info <SPAN class="token punctuation">(</SPAN>config<SPAN class="token punctuation">)</SPAN>
  • nmrao's avatar
    nmrao
    Champion Level 3

    What is the expected value as per your request? And what is it showing?

    • stevieoh's avatar
      stevieoh
      New Contributor

       Hey nmrao!

      I managed to get it working, so I got the value and saved to a variable and it appears to be the value I wanted.

      Here's my solution (probably stolen from an older response from you in some form or another!).

      // create XmlHolder for request content
      def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
      def tempURL = "http://" + mockRequest.requestHeaders.get("Host")[0] //as value is saved is array we must access the content directly
      mockRunner.mockService.project.setPropertyValue('requestURL',tempURL) //save to Project Variable for now

      So I'm happy enough in my Mock Service that I can access details of the incoming request and use them for certain decisions and save things to variables.

      In this example I save at a project level, which may change but I'm struggling to find documentation to set/save this at a test suite or test case level which I think would be more suitable / useful.

      This might be a separate topic /question and it's one I have seen you and another user answer on in some form for previous queries but I am looking to test/mock an asynchronous service and do it for multiple potential SOAP Actions.

      So the real end system I am mocking will send an ACK and then later send additional updates (effectively order progress). I will also be mocking a decetly large number of SOAP Actions (10+ let's say) that update in this way.

      I have handled this through a Test Suite and Test Case setup that is called via the OnRequest Script and AfterRequest Script functionality in the SOAP UI Mock Service and the decision on which Test Case to call is based on the SOAP Action and a switch statement. I'm not 100% happy with these choices for below reasons.

      1. Currently I save the values of host and SOAP Action in the OnRequest Script and then let my mock service respond with the ACK. In this response I generate a UUID (<ORDER_ID>${=java.util.UUID.randomUUID()}</ORDER_ID>).

      In the script for the mock response I save a UUID at a project level which needs to be reused in future "expected" asynch responses for this specific request (such as subsequent Update, Complete notifications).

      I then use AfterRequest Script to kick off the test case to send suitable subsequent responses of Update and Complete using the same UUID.

      // create XmlHolder for request content
      def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
      def tempURL = "http://" + mockRequest.requestHeaders.get("Host")[0]
      def tempAction = mockRequest.requestHeaders.get("SOAP-Action")[0]
      
      mockRunner.mockService.project.setPropertyValue('requestURL',tempURL)
      log.info ("Step 1: Saved request URL and SOAP Action...")
      
      // get target testcase by Action
      
      switch(tempAction){
      	case "Service 1":
      		def testCase = mockRunner.mockService.project.getTestSuiteByName("ASync_Responses").getTestCaseByName("Service 1")
      		log.info ("Step 2: Selected test case...")
      		// run testCase
      		def runner = testCase.run( new com.eviware.soapui.support.types.StringToObjectMap(), false )
      		log.info ("Step 5: Scripts completed!") //Step 3 and Step 4 is in the ASyncResponses Test Suite Test Case selected by script above
      	case "Service 2":
      		def testCase = mockRunner.mockService.project.getTestSuiteByName("ASync_Responses").getTestCaseByName("Service 2")
      		log.info ("Step 2: Selected test case...")
      		// run testCase
      		def runner = testCase.run( new com.eviware.soapui.support.types.StringToObjectMap(), false )
      		log.info ("Step 5: Scripts completed!") //Step 3 and Step 4 is in the ASyncResponses Test Suite Test Case selected by script above
      	...
      	case "Service X":
      	etc.
      }

      The problem:

      I know I need to move this UUID to be saved at some form of a context level within a test case as I could receive two requests in quick succession and could end up mixing up which UUID to use for the following updates (i.e. the second request to the MockService will overwrite the UUID for the first so the requesting system receives duplicate updates for Order 2 and not all Updates for Order 1).

      I think that ideally my Mock Service wouldn't send any response and will only select a test case to run which will send all the responses instead. This should mean everything can be contained within the test case itself and at a context level.

      EDIT: On further thought perhaps I do most of my work in OnRequest Script, which calls the test case and then the final response (Completion) is populated by the test case as called out here:
      https://www.soapui.org/docs/soap-mocking/creating-dynamic-mockservices/#4-Creating-the-response-from-the-result-of-a-TestCase

      So my last step of the test case can be to generate the final asynch response body but let the MockService send it (no clue how that would work ha!).

      What do you think? Any suggestion?

      • nmrao's avatar
        nmrao
        Champion Level 3

        stevieoh 

        1. Never used handling of async services. So, really nothing much to offer.
        2. Just noticed this documentation, please see if not already.

         

        In this example I save at a project level, which may change but I'm struggling to find documentation to set/save this at a test suite or test case level which I think would be more suitable / useful.

        Think this developing mock service as independent activity or entirely using different technology, then also neither we have project, nor test suite / case. So need to come up with different way of holding required data with in the mock response handler itself such as Map or some file based serialization, load the at start and serialize at the end in case if losing the state over the time.

        As per the above documentation link, use context to add your properties

        say, to set a value

        context.myprop = 1

        and later get it context.myprop

        Similarly context can hold uuid's too as long as unique key is used.

        MockResponse Response Scripts

        The context script variable available in the MockResponse Response Script, acts both as a MockRunContext and a TestRunContext, allowing it to access the same context variables as other Groovy scripts in the TestCase

        Noticed in the script that you are trying to run test case from mock service which I am not sure if it is right to do so. Also didn't have complete context, so don't want to jump into conclusions.

         

  • stevieoh's avatar
    stevieoh
    New Contributor

    Apologies for the malformed code above.

    Repasted here:

    // create XmlHolder for request content
    def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
    
    def config = holder.getEndpoint
    
    log.info (config)

    I know believe below to be the correct solution, saves it to a project level at least.

    Other options would be to save to a test case or even to the MockService itself but I'm not aware of the exact commands are to do that (i.e. is it mockRunner.mockService.setPropertyValue('propName',variable) ).

    // create XmlHolder for request content
    def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
    def tempURL = "http://" + mockRequest.requestHeaders.get("Host")[0]
    def tempAction = mockRequest.requestHeaders.get("SOAP-Action")[0]
    
    mockRunner.mockService.project.setPropertyValue('requestURL',tempURL)