Hello. I have a legacy system that communicates ov...
# help
p
Hello. I have a legacy system that communicates over HTTP from Java and shell scripts (curl) run from Java. I'm trying to capture the entirety of that communication (it's not too big, actually) in order to create a mock test that simulates a system run. I was looking at WireMock to see if it can help me achieve that. Sadly, there's no javadoc and the online documentation is not too useful to me. I hate guessing and randomly poking here and there. What I need is to capture the communication, translate the capture to stubs, and then serve those stubs in a test. Any examples, patterns, templates or idioms for that? Thanks.
I have this trivial snippet, which I use to start a server that I hope captures HTTP communication:
Copy code
public static void main(String[] args) {
    var wireMockServer = new WireMockServer(options().enableBrowserProxying(true).port(1080));
    wireMockServer.startRecording(new RecordSpecBuilder().build());
    wireMockServer.start();
    try {
        try {
            Thread.sleep(Duration.ofSeconds(20));
        } catch (InterruptedException ignored) { }
        wireMockServer.getStubMappings().forEach(System.out::println);
    } finally {
        wireMockServer.stop();
    }
}
then I run
curl
to simulate the said communication
Copy code
curl --proxy localhost:1080 <http://google.com>
and observe this output from the server:
Copy code
{
  "id" : "3405af3a-bc9d-44a3-901e-7be961c29c25",
  "name" : "",
  "request" : {
    "url" : "/",
    "method" : "GET"
  },
  "response" : {
    "status" : 200,
    "body" : ...
    "headers" : {
      "Alt-Svc" : "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000",
      "Server" : "gws",
      "P3P" : "CP=\"This is not a P3P policy! See <http://g.co/p3phelp|g.co/p3phelp> for more info.\"",
      "Date" : "Thu, 06 Mar 2025 09:52:19 GMT",
      "Accept-Ranges" : "none",
      "X-Frame-Options" : "SAMEORIGIN",
      "Cache-Control" : "private, max-age=0",
      "Vary" : "Accept-Encoding",
      "Set-Cookie" : ...],
      "Expires" : "-1",
      "X-XSS-Protection" : "0",
      "Accept-CH" : "Sec-CH-Prefers-Color-Scheme",
      "Content-Security-Policy-Report-Only" : "object-src 'none';base-uri 'self';script-src '...' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri <https://csp.withgoogle.com/csp/gws/other-hp>",
      "Content-Type" : "text/html; charset=ISO-8859-1"
    }
  },
  "uuid" : ...,
  "persistent" : true
}
There's no mention of google.com in either request or response. Why?
l
There are a few things that you might want to try. The first is to tell WireMock the URL you are recording. For example, using the WireMock Cloud echo server instead of google.com, I would specify the following:
Copy code
wireMockServer.startRecording("<https://wc-echo.wiremockapi.cloud>");
The second thing you might want to try is to stop recording:
Copy code
wireMockServer.stopRecording();
If I then put all that together using this code:
Copy code
public static void main(String[] args) {
        var wireMockServer = new WireMockServer(options().port(1080));
        wireMockServer.start();
        wireMockServer.startRecording("<https://wc-echo.wiremockapi.cloud>");
        try {
            Thread.sleep(Duration.ofSeconds(30));
            wireMockServer.stopRecording();
            wireMockServer.getStubMappings().forEach(System.out::println);
        } catch (InterruptedException e) {
            // ignore
        }  
        finally {
            wireMockServer.stop();
        }
    }
I then make a request to the local wiremock server:
Copy code
curl localhost:1080/foo/bar
I get the following output in the terminal from the echo server via the local wiremock server:
Copy code
Received the following request

GET /foo/bar HTTP/1.1
Accept: */*
Connection: keep-alive
Host: wc-echo.wiremockapi.cloud
User-Agent: Apache-HttpClient/5.4.2 (Java/23.0.2)
I then wait for the
Thread.sleep
to end and I see this in the console where I am running the code:
Copy code
{
  "id": "c17bfca4-0eda-4935-bbdd-0d40d9965cce",
  "name": "foo_bar",
  "request": {
    "url": "/foo/bar",
    "method": "GET"
  },
  "response": {
    "status": 200,
    "body": "Received the following request\n\nGET /foo/bar HTTP/1.1\nAccept: */*\nConnection: keep-alive\nHost: wc-echo.wiremockapi.cloud\nUser-Agent: Apache-HttpClient/5.4.2 (Java/23.0.2)\n\n",
    "headers": {
      "Matched-Stub-Id": "bece70e6-7ee6-4926-ac9c-161270f6e07b",
      "Matched-Stub-Name": "WireMock Cloud Live Echo",
      "Vary": "Origin",
      "Content-Type": "text/plain"
    }
  },
  "uuid": "c17bfca4-0eda-4935-bbdd-0d40d9965cce",
  "persistent": true
}
The example to specify where to record to and to stop recording can be found on the docs page here - https://wiremock.org/docs/record-playback/#recording
p
And if my system communicates with multiple endpoints that I don't know beforehand?
I had some experience with MockServer, which is sadly no longer supported. MockServer by default proxies HTTP and HTTPS requests, recording them. Just before stopping server I would simply retrieve the collected logs or expectations made from those logs. For that to work, MockServer only requires that every connection that needs to be recorded is proxied through it. Can WireMock work in a similar way?
From your example, it seems that I need to set up a WireMock server per endpoint and target my requests to the server directly rather than proxy through it.
l
WireMock can be setup as a forward proxy. Maybe that would help? - https://wiremock.org/docs/proxying/#running-as-a-browser-proxy
p
That's what I had in my initial snippet in this thread, have a look
WireMockServer(options().enableBrowserProxying(true).port(1080));
The problem with that is when I gather the recordings they lack some HTTP headers, such as Host.
This also does not help:
Copy code
var wireMockServer = new WireMockServer(options()
        .preserveHostHeader(true)
        .recordRequestHeadersForMatching(List.of("host"))
        .enableBrowserProxying(true)
        .port(1080));
Without host, how would I or, more importantly, WireMock would differentiate between various endpoints?
Trial and error in the absence of javadoc lead me to this:
Copy code
wireMockServer.startRecording(new RecordSpecBuilder().captureHeader("host").build());
Thanks for your help.
l
Sorry for the delay. Not sure I was much help there to be honest. So you now have it working?
p
The recorded files now have "host":
Copy code
"name" : "",
  "request" : {
    "url" : "/",
    "method" : "GET",
    "headers" : {
      "host" : {
        "equalTo" : "<http://www.google.com|www.google.com>"
      }
    }
  },
So, yes. It seems working.
l
Awesome