geoand / quarkus-test-demo

Source code for demo shown at https://www.youtube.com/watch?v=OCPFdpvL1Q0
10 stars 4 forks source link

WireMock.verify fails with Connection refused #1

Open Manfred73 opened 1 year ago

Manfred73 commented 1 year ago

I've been following this example to test my resource, which in turn calls an external resource. I used WireMock to mock the external resource call as described in this demo: https://github.com/geoand/quarkus-test-demo/blob/main/src/test/java/org/acme/getting/started/country/WiremockCountries.java

The stubbing part works fine and I can test the result with RestAssured. But verficiation of the right URL being used at the end of the test fails with a connection refused on localhost:8080.

My application-test.yaml:

files:
   baseUrl: 'http://localhost:8088'

My WireMock proxy class:

public class MyWireMockProxy implements QuarkusTestResourceLifecycleManager {
   public static final String URL = "v1/files/12345";
   private static final int WIREMOCK_PORT = 8079;

   WireMockServer wireMockServer;

   @Override
   public Map<String, String> start() {
      wireMockServer = new WireMockServer(WIREMOCK_PORT);
      wireMockServer.start();
      configureFor(WIREMOCK_PORT);
      stubForFilesQueryResource();

      // NOTE: not using the Quarkus rest client here like "org.acme.getting.started.country.CountriesService/mp-rest/url"
      // because that doesn't seem to work well with StreamingOutput; instead using the default JAX-RS method as described
      // here: https://www.adam-bien.com/roller/abien/entry/sending_and_receiving_streams_with
      // Is this maybe causing any issue with WireMock?
      return Collections.singletonMap("files.baseUrl", wireMockServer.baseUrl());
   } 

   private static void stubForFilesQueryResource() {
      try (final var is = Files.newInputStream(ResourceReader.getAbsolutePathFromClassLoaderResourceAsPath("files/myFile.txt"))) {
         stubFor(get(urlPathMatching(URL))
                .willReturn(
                        aResponse()
                                .withHeader("Content-Type", MediaType.APPLICATION_OCTET_STREAM)
                                .withBody(is.readAllBytes())
                                .withStatus(HttpStatus.SC_OK)));
      } catch (IOException ioe) {
         throw new UnexpectedTestException(ioe);
      }
   }

   @Override
   public void stop() {
      if (wireMockServer != null) {
         wireMockServer.stop();
      }
   }  
}

The FilesITProfile to make sure integration test uses the application-test.yaml:

public class FilesITProfile implements QuarkusTestProfile {
   @Override
   public String getConfigProfile() {
      return "test";
   } 
}

The IntegrationTest:

@QuarkusIntegrationTest
@TestHTTPEndpoint(FilesQueryResource.class)
@TestProfile(FilesITProfile.class)
@QuarkusTestResource(MyWireMockProxy.class)
@Tag("integration")
class FilesQueryResourceHappyFlowIntegrationTest extends TestIntegrationBase {

   @Test
   @DisplayName("When a GET request with id of a file is done, I expect a number of 2 records to be returned")
   void expect_number_of_2_records_returned_when_get_by_id() {
      // GIVEN / WHEN
      final var jsonPath = given()
            .contentType(ContentType.JSON)
            .pathParam("id", "12345")
            .when()
            .get("/number-of-records/{id}")
            .then()
            .statusCode(200)
            .extract()
            .jsonPath();

      // THEN
      expectingResponseResultWithoutErrors(jsonPath);
      final var numberOfRecords = getResultFromResponseResult(NumberOfRecords.class, jsonPath);
      assertThat(numberOfRecords.getNumber()).isEqualTo(2);

      // HERE IT FAILS with:
      // org.apache.hc.client5.http.HttpHostConnectException:
      //      Connect to http://localhost:8080 [localhost/127.0.0.1] failed: Connection refused
      WireMock.verify(getRequestedFor(urlEqualTo(URL)) // URL is defined in MyWireMockProxy class
            .withHeader("Content-Type", containing(MediaType.APPLICATION_OCTET_STREAM)));
   } 
}

So everything works fine up till the stubbing and assertions of the result. But the WireMock.verify fails with an exception Connection refused on localhost:8080. I'm not sure where the localhost:8080 is coming from (looks like some default) since I'm using port 8079 as WIREMOCK_PORT and also in my application-test.yaml the port is 8088 and not 8080.

I've been trying out some things suggested here, but none of them seem to help: https://github.com/wiremock/wiremock/issues/607

Verification works fine with a spring application, but that's configured differently using spring annotations:

@AutoConfigureWireMock(port = 8079)

@DynamicPropertySource
static void setDynamicProperties(final DynamicPropertyRegistry registry) {
    registry.add("files.baseUrl", () -> "http://localhost:8079/" + BASE_PATH);
} 

Am I missing some configuration or is this a bug?

geoand commented 1 year ago

I haven't checked this in a while to be honest

Manfred73 commented 1 year ago

Cloned your project to give it a try there (updating quarkus version to 2.15.3.Final, java version to 17, disabling preview and added version for assertj).

Added

WireMock.verify(getRequestedFor(urlEqualTo("/v2/name/GR")));

to RegularCountriesServiceTest and the test passes.

The difference between this test is and my test is that yours uses @QuarkusTest and in my test I use @QuarkusIntegrationTest together with RestAssured, because I want my integration tests to run against the native image.