Search code examples
wiremock

Wiremock ignores mutipart/form-data matchers


In my tests, I want to mock external API (Twilio). I have the following mapping config for Wiremock (version 3.8.0, run as Docker container):

{
  "mappings": [
    {
      "priority": 1,
      "request": {
        "method": "POST",
        "url": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json",
        "multipartPatterns": [
          {
            "matchingType": "ANY",
            "bodyPatterns": [
              {
                "matches": ".*should-fail.*"
              }
            ]
          }
        ]
      },
      "response": {
        "status": 500,
        "jsonBody": {
          "error": "cannot send"
        }
      }
    },
    {
      "priority": 2,
      "request": {
        "method": "POST",
        "url": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json"
      },
      "response": {
        "status": 200,
        "jsonBody": {
          "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
          "api_version": "2010-04-01",
          "body": "foo bar baz",
          "date_created": "Mon, 22 Jul 12:00:00 2024 PT",
          "date_updated": "Mon, 22 Jul 12:01:00 2024 PT",
          "date_sent": "Mon, 22 Jul 12:02:00 2024 PT",
          "direction": "outbound",
          "from": "+1 888 000 1111",
          "messaging_service_sid": "MG0d229447d086b7bc8a63b4be7de0f050",
          "sid": "SM12ababababab12abababab",
          "status": "sending",
          "to": "+1 123 123 1234"
        }
      }
    }
  ]
}

When I'm sending the following request:

POST http://localhost:8081/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json
Content-Type: application/x-www-form-urlencoded
Content-Length: 57
User-Agent: IntelliJ HTTP Client/PyCharm 2024.1.4
Accept-Encoding: br, deflate, gzip, x-gzip
Accept: */*

To=%2B1+123+123+9999&From=%2B18880001111&Body=should-fail

Wiremock, for some cosmic reason, constantly matches the later mapping and responds with:

{"account_sid":"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","api_version":"2010-04-01","body":"foo bar baz","date_created":"Mon, 22 Jul 12:00:00 2024 PT","date_updated":"Mon, 22 Jul 12:01:00 2024 PT","date_sent":"Mon, 22 Jul 12:02:00 2024 PT","direction":"outbound","from":"+1 888 000 1111","messaging_service_sid":"MG0d229447d086b7bc8a63b4be7de0f050","sid":"SM12ababababab12abababab","status":"sending","to":"+1 123 123 1234"}

Response code: 200 (OK); Time: 27ms (27 ms); Content length: 419 bytes (419 B)

Here is the request journal:

{
  "requests" : [ {
    "id" : "51e64e51-52af-46ef-b086-3c8eb8032767",
    "request" : {
      "url" : "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json",
      "absoluteUrl" : "http://localhost:8081/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json",
      "method" : "POST",
      "clientIp" : "192.168.65.1",
      "headers" : {
        "Content-Type" : "application/x-www-form-urlencoded",
        "Content-Length" : "57",
        "User-Agent" : "IntelliJ HTTP Client/PyCharm 2024.1.4",
        "Accept-Encoding" : "br, deflate, gzip, x-gzip",
        "Accept" : "*/*",
        "Host" : "localhost:8081"
      },
      "cookies" : { },
      "browserProxyRequest" : false,
      "loggedDate" : 1721656632388,
      "bodyAsBase64" : "VG89JTJCMSsxMjMrMTIzKzk5OTkmRnJvbT0lMkIxODg4MDAwMTExMSZCb2R5PXNob3VsZC1mYWls",
      "body" : "To=%2B1+123+123+9999&From=%2B18880001111&Body=should-fail",
      "protocol" : "HTTP/1.1",
      "scheme" : "http",
      "host" : "localhost",
      "port" : 8081,
      "loggedDateString" : "2024-07-22T13:57:12.388Z",
      "queryParams" : { },
      "formParams" : {
        "To" : {
          "key" : "To",
          "values" : [ "+1 123 123 9999" ]
        },
        "From" : {
          "key" : "From",
          "values" : [ "+18880001111" ]
        },
        "Body" : {
          "key" : "Body",
          "values" : [ "should-fail" ]
        }
      }
    },
    "responseDefinition" : {
      "status" : 200,
      "jsonBody" : {
        "account_sid" : "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "api_version" : "2010-04-01",
        "body" : "foo bar baz",
        "date_created" : "Mon, 22 Jul 12:00:00 2024 PT",
        "date_updated" : "Mon, 22 Jul 12:01:00 2024 PT",
        "date_sent" : "Mon, 22 Jul 12:02:00 2024 PT",
        "direction" : "outbound",
        "from" : "+1 888 000 1111",
        "messaging_service_sid" : "MG0d229447d086b7bc8a63b4be7de0f050",
        "sid" : "SM12ababababab12abababab",
        "status" : "sending",
        "to" : "+1 123 123 1234"
      }
    },
    "response" : {
      "status" : 200,
      "headers" : {
        "Matched-Stub-Id" : "3629754a-3ff0-4ece-bdd5-e2315c1589fa"
      },
      "bodyAsBase64" : "eyJhY2NvdW50X3NpZCI6IkFDWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFgiLCJhcGlfdmVyc2lvbiI6IjIwMTAtMDQtMDEiLCJib2R5IjoiZm9vIGJhciBiYXoiLCJkYXRlX2NyZWF0ZWQiOiJNb24sIDIyIEp1bCAxMjowMDowMCAyMDI0IFBUIiwiZGF0ZV91cGRhdGVkIjoiTW9uLCAyMiBKdWwgMTI6MDE6MDAgMjAyNCBQVCIsImRhdGVfc2VudCI6Ik1vbiwgMjIgSnVsIDEyOjAyOjAwIDIwMjQgUFQiLCJkaXJlY3Rpb24iOiJvdXRib3VuZCIsImZyb20iOiIrMSA4ODggMDAwIDExMTEiLCJtZXNzYWdpbmdfc2VydmljZV9zaWQiOiJNRzBkMjI5NDQ3ZDA4NmI3YmM4YTYzYjRiZTdkZTBmMDUwIiwic2lkIjoiU00xMmFiYWJhYmFiYWIxMmFiYWJhYmFiIiwic3RhdHVzIjoic2VuZGluZyIsInRvIjoiKzEgMTIzIDEyMyAxMjM0In0=",
      "body" : "{\"account_sid\":\"ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\"api_version\":\"2010-04-01\",\"body\":\"foo bar baz\",\"date_created\":\"Mon, 22 Jul 12:00:00 2024 PT\",\"date_updated\":\"Mon, 22 Jul 12:01:00 2024 PT\",\"date_sent\":\"Mon, 22 Jul 12:02:00 2024 PT\",\"direction\":\"outbound\",\"from\":\"+1 888 000 1111\",\"messaging_service_sid\":\"MG0d229447d086b7bc8a63b4be7de0f050\",\"sid\":\"SM12ababababab12abababab\",\"status\":\"sending\",\"to\":\"+1 123 123 1234\"}"
    },
    "wasMatched" : true,
    "timing" : {
      "addedDelay" : 0,
      "processTime" : 0,
      "responseSendTime" : 0,
      "serveTime" : 0,
      "totalTime" : 0
    },
    "subEvents" : [ ],
    "stubMapping" : {
      "id" : "3629754a-3ff0-4ece-bdd5-e2315c1589fa",
      "request" : {
        "url" : "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json",
        "method" : "POST"
      },
      "response" : {
        "status" : 200,
        "jsonBody" : {
          "account_sid" : "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
          "api_version" : "2010-04-01",
          "body" : "foo bar baz",
          "date_created" : "Mon, 22 Jul 12:00:00 2024 PT",
          "date_updated" : "Mon, 22 Jul 12:01:00 2024 PT",
          "date_sent" : "Mon, 22 Jul 12:02:00 2024 PT",
          "direction" : "outbound",
          "from" : "+1 888 000 1111",
          "messaging_service_sid" : "MG0d229447d086b7bc8a63b4be7de0f050",
          "sid" : "SM12ababababab12abababab",
          "status" : "sending",
          "to" : "+1 123 123 1234"
        }
      },
      "uuid" : "3629754a-3ff0-4ece-bdd5-e2315c1589fa",
      "priority" : 2
    }
  } ],
  "meta" : {
    "total" : 1
  },
  "requestJournalDisabled" : false
}

I already tried changing matchers, like contains, or other matching types (i.e., bodyPatterns) but with no luck.

Side note: Tests are in the Python app, so using the Java SDK is not an option for me.

Any idea what I'm doing wrong?


Solution

  • The form you're sending in the request (application/x-www-form-urlencoded) isn't multipart.

    To match attributes of this type of form you need to use the formParameters element e.g.

    {
      "priority": 1,
      "request": {
        "method": "POST",
        "url": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json",
        "formParameters": {
          "myFormElement": {
            "matches": ".*should-fail.*"
          }
        }
      },
      "response": {
        "status": 500,
        "jsonBody": {
          "error": "cannot send"
        }
      }
    }