Howdy! I've been upgrading an app from spring boo...
# help
j
Howdy! I've been upgrading an app from spring boot 2->3, and I'm seeing something odd in wiremock that wasn't true before. New version is 3.10.0 When I create a stub, the URL has ?send=true in it, but when I run the test spring webClient is sending %3fsend=true. Therefore, none of those tests pass the urlEqualTo test.
t
Can you share a test case that illustrates this so we can reproduce? One suggestion I’d make generally is to use query parameter matchers + URL path matching rather than matching the whole URL. This gives you more control and order invariance.
j
I think the webclient is encoding the URL so that ? turns into &3F. I created this test
Copy code
@Test
    public void wireMockTest2() throws InterruptedException {

        wireMockServer.stubFor(<http://WireMock.post|WireMock.post>(urlPathEqualTo("/111?one=two")));
        wireMockServer.stubFor(<http://WireMock.post|WireMock.post>(urlPathEqualTo("/222?one=two")));
        wireMockServer.stubFor(<http://WireMock.post|WireMock.post>(urlPathEqualTo("/333?one=two")));

        String twostring = "two";
        Mono<String> resp = <http://scheduleMessageWebClient.post|scheduleMessageWebClient.post>().uri(uriBuilder -> uriBuilder
                        .path("/111?one={two}")
                        .build(twostring))
                .retrieve()
                .bodyToMono(String.class);
        wireMockServer.verify(1, postRequestedFor(urlEqualTo("/111?one=two")));
        Thread.sleep(5000);

    }
But every time I get back
Copy code
com.github.tomakehurst.wiremock.client.VerificationException: Expected at least one request matching: {
  "url" : "/111?one=two",
  "method" : "POST"
}
Requests received: [ ]
@Tom It loos like to me the webclient isn't pointing to the mock server, but When I run it with stubs for ? I get back 404 not found. If I change the stubs to %3F, I get back a 500 Internal Server Error.
t
Yes, the
Requests received: [ ]
implies that no requests arrived in WireMock. How is
scheduleMessageWebClient
being initialised and injected?
j
@Tom Creating web client with HttpClient httpClient = HttpClient.create() .responseTimeout(Duration.ofMillis(scheduleMessageProperties.getResponseTimeout())); return webClient(scheduleMessageProperties.getBaseURL(), oauthConfiguration.getAccessTokenUri(), oauthConfiguration.getClientId(), oauthConfiguration.getClientSecret(), "scheduleMessageClient", objectMapper, httpClient); Stub: wireMockServer.stubFor(WireMock.post(urlPathEqualTo("/111%3Fone=two"))); Call to wiremock Mono<String> resp = scheduleMessageWebClient.post().uri(uriBuilder -> uriBuilder .path("/111?one={two}") .build(twostring)) .retrieve() .bodyToMono(String.class); This returns a 404 Verify wireMockServer.verify(1, postRequestedFor(urlEqualTo("/111%3Fone=two"))); Error com.github.tomakehurst.wiremock.client.VerificationException: Expected at least one request matching: { "url" : "/111%3Fone=two", "method" : "POST" } Requests received: [ ] Where can I see what requests have been made? Also, where can I see what stubs are recorded? I’ve gone back and forth over the ? vs %3F for the stub and verify, but I can’t get a match.
If I do wireMockServer.getStubMappings() After setting up the stub I see it. { "id" : "4ac0d69f-636f-4d35-96a6-1b538938c256", "request" : { "urlPath" : "/111%3Fone=two", "method" : "POST" }, "response" : { "status" : 200 }, "uuid" : "4ac0d69f-636f-4d35-96a6-1b538938c256" }
If I do wireMockServer.getStubMappings() After setting up the stub I see it. { "id" : "4ac0d69f-636f-4d35-96a6-1b538938c256", "request" : { "urlPath" : "/111%3Fone=two", "method" : "POST" }, "response" : { "status" : 200 }, "uuid" : "4ac0d69f-636f-4d35-96a6-1b538938c256" } In the verify I see the requestPatternBuilder.url = path and query equalTo /111%3Fone=two Down inside the verify if I do this.requestJournal.getAllServeEvents().get(0).request I see { "url" : "/operationsexecutionscheduleMessage/111%3Fone=two", "absoluteUrl" : "http://localhost:11286/operationsexecutionscheduleMessage/111%3Fone=two", "method" : "POST", "clientIp" : "127.0.0.1", "headers" : { "User-Agent" : "ReactorNetty/1.1.13", "Host" : "localhost:11286", "Accept" : "*/*", "Transfer-Encoding" : "chunked", "Authorization" : "Bearer eyJ<snip>" }, "cookies" : { }, "browserProxyRequest" : false, "loggedDate" : 1733759207411, "bodyAsBase64" : "", "body" : "", "protocol" : "HTTP/1.1", "scheme" : "http", "host" : "localhost", "port" : 11286, "loggedDateString" : "2024-12-09T154647Z", "queryParams" : { } } And the response is this.requestJournal.getAllServeEvents().get(0).response Status = 404
So it looks to me like when I use %3F it doesn't realize %3F means question mark.
If I change all the %3F to ? I see the stub mapping with a ? in it. { "id" : "e1491ebe-8d9b-4f84-9435-6c361871fa23", "request" : { "urlPath" : "/111?one=two", "method" : "POST" }, "response" : { "status" : 200 }, "uuid" : "e1491ebe-8d9b-4f84-9435-6c361871fa23" } I still get back 404 NOT_FOUND When I check wireMockServer.findAllUnmatchedRequests() I see { "url" : "/operationsexecutionscheduleMessage/111%3Fone=two", "absoluteUrl" : "http://localhost:11479/operationsexecutionscheduleMessage/111%3Fone=two", "method" : "POST", "clientIp" : "127.0.0.1", "headers" : { "User-Agent" : "ReactorNetty/1.1.13", "Host" : "localhost:11479", "Accept" : "*/*", "Transfer-Encoding" : "chunked", "Authorization" : "Bearer eyJ<snip>" }, "cookies" : { }, "browserProxyRequest" : false, "loggedDate" : 1733760184757, "bodyAsBase64" : "", "body" : "", "protocol" : "HTTP/1.1", "scheme" : "http", "host" : "localhost", "port" : 11479, "loggedDateString" : "2024-12-09T160304Z", "queryParams" : { } }
t
Are you actually intending to put what looks like a query parameter in a path segment? Or should you be calling something like
.query("one", "two")
in your HTTP request builder code?
j
If I change it to wireMockServer.stubFor(WireMock.post(urlPathEqualTo("/111")).withQueryParam("one", equalTo("two")));
wireMockServer.verify(1, postRequestedFor(urlPathEqualTo("/111")).withQueryParam("one", equalTo("two")));
t
I mean your HTTP client, rather than WireMock
You’ve got
.path("/111?one={two}")
whereas maybe the query part should be broken out from that?
j
I still get a 404 'cause it's encoding the url with %3F.
I think it all goes away if I can create a url with a ? in it, but I've looked at the urlbuilder variations and I haven't hit on the right config.
Oh! I just realized what you said. Let me change that and see
t
Yes, but I think it’s encoding it that way because you’re saying it’s part of the path
Try something like
Copy code
uriBuilder
    .path("/111")
    .queryParam("one", "two")
j
Copy code
wireMockServer.stubFor(<http://WireMock.post|WireMock.post>(urlPathEqualTo("/111")).withQueryParam("one", equalTo("two")));
scheduleMessageWebClient.post().uri(uriBuilder -> uriBuilder .path("/111").queryParam("one", "two") .build()) Returns a 404
Copy code
wireMockServer.findAllUnmatchedRequests()
returns { "url" : "/operationsexecutionscheduleMessage/111?one=two", "absoluteUrl" : "http://localhost:12166/operationsexecutionscheduleMessage/111?one=two", "method" : "POST", "clientIp" : "127.0.0.1", "headers" : { "User-Agent" : "ReactorNetty/1.1.13", "Host" : "localhost:12166", "Accept" : "*/*", "Transfer-Encoding" : "chunked", "Authorization" : "Bearer ey<snip>" }, "cookies" : { }, "browserProxyRequest" : false, "loggedDate" : 1733762263678, "bodyAsBase64" : "", "body" : "", "protocol" : "HTTP/1.1", "scheme" : "http", "host" : "localhost", "port" : 12166, "loggedDateString" : "2024-12-09T163743Z", "queryParams" : { "one" : { "key" : "one", "values" : [ "two" ] } } }
Right when I’m in the verify if I run scheduleMessageWebClient.post().uri(uriBuilder -> uriBuilder.path("/111").queryParam("one", "two").build()) The URI does look right http://localhost:12166/operationsexecutionscheduleMessage/111?one=two
t
Looks like you’re missing
/operationsexecutionscheduleMessage
from your stubbed URL path
j
It's set as the baseURL when the webclient gets created.
but I'll check.
t
But it looks like you’re not including it in your stubbed URL, which is why it’s not matching and returning a 404
j
Wow. I spent two days looking for that. 😅 If I do it that way I still see com.github.tomakehurst.wiremock.client.VerificationException: Expected at least one request matching: { "urlPath" : "/operationsexecutionscheduleMessage/111", "method" : "POST", "queryParameters" : { "one" : { "equalTo" : "two" } } } Requests received: [ ]
t
Are you definitely setting the base URL to WireMock for the WebClient? I didn’t see that in your code snippet.
j
It's in the webClient contrstrutor.
IT JUST WORKED!
🎉 1
Thank you so much for the help. Where can I send you a pint?
t
No worries, no pint required 🙂