Search code examples
mulemule4munit

How to raise a custom error with internal payload (error.errorMessage.payload) in MUnit


I have a flow that is making an HTTP call to a REST web service. There are a couple of errors that we get as statusCode=500 but with different "errorCodes" inside the response body. This request connector is wrapped inside a try block with multiple on-error-continue based on the content of the response body in its "when" attribute. eg: error.errorMessage.payload.errorCode==CODE_A. Adding an image and source code of the flow below

enter image description here

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core"
    xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">
    <http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="dee432d7-a176-448c-a1ac-a374a86fa85b" >
        <http:listener-connection host="0.0.0.0" port="8081" />
    </http:listener-config>
    <flow name="test2Flow" doc:id="be602af1-cfcf-46f1-a312-ea6a5544503b" >
        <http:listener doc:name="Listener" doc:id="f160fa61-15be-4744-b823-973e20740e73" config-ref="HTTP_Listener_config" path="/test"/>
        <logger level="INFO" doc:name="Some logic before request" doc:id="6354a117-e918-4937-a1d9-df4ae0ef6386" message="Some logic before request"/>
        <try doc:name="Try" doc:id="15bd106a-c116-4d87-958e-8ad698026739" >
            <http:request method="GET" doc:name="Request" doc:id="a046919e-f149-45d6-9a70-db37cac0540f" url="http://example.com/some-resource" />
            <error-handler >
                <on-error-continue enableNotifications="true" logException="true" doc:name="when error.errorMessage.payload.errorCode==CODE_A" doc:id="20fc0575-da65-41b4-81f7-d364227b1639" when='error.errorMessage.payload.errorCode=="CODE_A"'>
                    <logger level="INFO" doc:name="Some logic for CODE_A" doc:id="a699ccd0-952c-415f-b288-4ea027f2cff2" message="Some logic for CODE_A" />
                </on-error-continue>
                <on-error-continue enableNotifications="false" logException="false" doc:name="when error.errorMessage.payload.errorCode==CODE_B" doc:id="63dc8aa5-5fae-4235-a4ae-a80903a76362" when='error.errorMessage.payload.errorCode=="CODE_B"' >
                    <logger level="INFO" doc:name="Some logic for CODE_B" doc:id="9364ff1e-4bcd-48d5-a37a-a207828cda9d" message="Some logic for CODE_B" />
                </on-error-continue>
            </error-handler>
        </try>
        <logger level="INFO" doc:name="Some logic After request" doc:id="fd754198-d6b5-40dd-b23f-c8619faee7e6" message="Some logic After request" />
    </flow>
</mule>

I am trying to write an MUnit test to verify if the correct error-handler block is executed based on response. However, I do not see any option to mock an error with its errorMessage part filled.

I am trying to find out one of these

  1. Any way to mock an error with errorMessage using the simple mock-when's then-return element. I do not think it is possible, but if there is a way please let me know.
  2. Maybe there is a way to use a Java class for raising complex errors. I am thinking if I can use mock-when's then-call to call a flow and then raise an error using it.
  3. Any other way to do it.

Note:

  1. Mule version: 4.3.0 MUnit version: 2.3.0
  2. I can not make change in the REST web service, I do not own that.
  3. I am trying to avoid any code change, For example, I can ignore status code in the message validator and do the error handling using response directly, with something like choice. But I will do it as the last resort.

Solution

  • You can try using something like this when mocking error for HTTP requests:

    Create the following DW file:

    httpError.dwl

    var detailMessage = 'Internal server error'
    var myJsonResponse = '{"errorCode":"ERROR_A"}'
    var typedValue = java!org::mule::runtime::api::metadata::TypedValue::new(myJsonResponse, java!org::mule::runtime::api::metadata::DataType::JSON_STRING)
    var errorMessage = java!org::mule::runtime::api::message::Message::of(typedValue)
    var errorType = java!org::mule::extension::http::api::error::HttpError::INTERNAL_SERVER_ERROR
    ---
    java!org::mule::extension::http::api::request::validator::ResponseValidatorTypedException::new(detailMessage, errorType, errorMessage)
    

    In your MUnit test suite file, create the following flow:

    <flow name="munit-set-error-code-event-flow" doc:id="3b7e266c-2f3b-4105-8fdb-8ea44d5f128e" >
        <munit:set-event doc:name="Generate error" doc:id="4ee8b870-6c8b-4570-bc70-7ec0086a1bca" cloneOriginalEvent="true">
            <munit:error id="HTTP:INTERNAL_SERVER_ERROR" exception="#[${file::httpError.dwl}]" />
        </munit:set-event>
    </flow>
    

    And, finally, in your actual MUnit test flow, configure the then-call option to call the above flow. Eg:

    <munit:test name="test-test-suite-testFlowTest" doc:id="5670a9cd-758a-4f2c-a55f-57b48a9f3b41" description="Test" timeOut="1200000">
        <munit:behavior >
            <munit-tools:mock-when doc:name="Mock when" doc:id="466fd55c-80b4-4e27-82ed-f561223a3b4f" processor="http:request">
                <munit-tools:with-attributes >
                    <munit-tools:with-attribute whereValue="08c4fba6-ef4b-4006-bd7d-deb1fd0f5304" attributeName="doc:id" />
                </munit-tools:with-attributes>
                <munit-tools:then-call flow="munit-set-error-code-event-flow" />
            </munit-tools:mock-when>
        </munit:behavior>
        <munit:execution >
            <flow-ref doc:name="Flow-ref to testFlow" doc:id="c57b3265-b453-432c-88fd-db2df7125fdc" name="testFlow"/>
        </munit:execution>
    </munit:test>
    

    Although I'm not sure if this is something recommended to do, it should work for what you want to achieve.

    Let me know if it works.