From b787931687c5e00f1dd25f938009856f2254ecba Mon Sep 17 00:00:00 2001 From: David Byron <82477955+dbyron-sf@users.noreply.github.com> Date: Wed, 11 Sep 2024 07:27:15 -0700 Subject: [PATCH] refactor(web/test): remove hard-coded port numbers from EchoServiceTest (#1828) * refactor(web/test): remove hard-coded port numbers from EchoServiceTest so the test can pass when these ports are in-use: EchoServiceTest > initializationError FAILED java.net.BindException: Address already in use at java.base/sun.nio.ch.Net.bind0(Native Method) at java.base/sun.nio.ch.Net.bind(Net.java:555) at java.base/sun.nio.ch.Net.bind(Net.java:544) at java.base/sun.nio.ch.NioSocketImpl.bind(NioSocketImpl.java:648) at java.base/java.net.ServerSocket.bind(ServerSocket.java:393) at com.squareup.okhttp.mockwebserver.MockWebServer.start(MockWebServer.java:354) at com.squareup.okhttp.mockwebserver.MockWebServer.start(MockWebServer.java:337) at com.squareup.okhttp.mockwebserver.MockWebServer.start(MockWebServer.java:324) at com.netflix.spinnaker.gate.service.EchoServiceTest.setUp(EchoServiceTest.java:57) While we're at it, also convert from junit4 which com.squareup.okhttp.mockwebserver.MockWebServer uses, to junit5, which wiremock uses. * chore(build): give tests more memory to execute to avoid OutOfMemoryErrors Please enter the commit message for your changes. Lines starting --- build.gradle | 1 + gate-web/gate-web.gradle | 1 + .../gate/service/EchoServiceTest.java | 116 +++++++++--------- .../resources/application-echo.properties | 12 +- 4 files changed, 66 insertions(+), 64 deletions(-) diff --git a/build.gradle b/build.gradle index a5760fa08b..616b9c432c 100644 --- a/build.gradle +++ b/build.gradle @@ -64,6 +64,7 @@ allprojects { exceptionFormat = 'full' } useJUnitPlatform() + maxHeapSize = "1g" } } diff --git a/gate-web/gate-web.gradle b/gate-web/gate-web.gradle index ee324b9fb4..d4cec83826 100644 --- a/gate-web/gate-web.gradle +++ b/gate-web/gate-web.gradle @@ -67,6 +67,7 @@ dependencies { testImplementation project(":gate-ldap") // TODO: Move system tests to own module testImplementation project(":gate-basic") testImplementation project(":gate-oauth2") + testImplementation "com.github.tomakehurst:wiremock-jre8-standalone" testImplementation "com.squareup.okhttp:mockwebserver" testImplementation "com.squareup.retrofit:retrofit-mock" diff --git a/gate-web/src/test/java/com/netflix/spinnaker/gate/service/EchoServiceTest.java b/gate-web/src/test/java/com/netflix/spinnaker/gate/service/EchoServiceTest.java index c69fc2a994..2e9e5ca6c4 100644 --- a/gate-web/src/test/java/com/netflix/spinnaker/gate/service/EchoServiceTest.java +++ b/gate-web/src/test/java/com/netflix/spinnaker/gate/service/EchoServiceTest.java @@ -16,81 +16,85 @@ package com.netflix.spinnaker.gate.service; -import static org.assertj.core.api.Assertions.assertThat; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.any; +import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import com.netflix.spinnaker.gate.Main; +import com.netflix.spinnaker.gate.services.ApplicationService; +import com.netflix.spinnaker.gate.services.DefaultProviderLookupService; import com.netflix.spinnaker.gate.services.internal.EchoService; -import com.squareup.okhttp.mockwebserver.Dispatcher; -import com.squareup.okhttp.mockwebserver.MockResponse; -import com.squareup.okhttp.mockwebserver.MockWebServer; -import com.squareup.okhttp.mockwebserver.RecordedRequest; -import groovy.util.logging.Slf4j; import java.io.IOException; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ActiveProfiles; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.TestPropertySource; -@ActiveProfiles("echo") -@Slf4j -@DirtiesContext @SpringBootTest(classes = {Main.class}) @TestPropertySource("/application-echo.properties") class EchoServiceTest { @Autowired EchoService echoService; - private static MockWebServer echoServer; - private static MockWebServer clouddriverServer; - private static MockWebServer front50Server; + /** + * To prevent refreshing the applications cache, which involves calls to clouddriver and front50. + */ + @MockBean ApplicationService applicationService; - @BeforeAll - static void setUp() throws IOException { - clouddriverServer = new MockWebServer(); - clouddriverServer.start(7002); - - Dispatcher clouddriverDispatcher = - new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest request) { - return new MockResponse().setResponseCode(200); - } - }; - clouddriverServer.setDispatcher(clouddriverDispatcher); - - front50Server = new MockWebServer(); - front50Server.start(8081); - Dispatcher front50Dispatcher = - new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest request) { - return new MockResponse().setResponseCode(200); - } - }; - front50Server.setDispatcher(front50Dispatcher); - - echoServer = new MockWebServer(); - echoServer.start(8089); + /** To prevent calls to clouddriver */ + @MockBean DefaultProviderLookupService defaultProviderLookupService; + + /** See https://wiremock.org/docs/junit-jupiter/#advanced-usage---programmatic */ + @RegisterExtension + static WireMockExtension wmEcho = + WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); + + @RegisterExtension + static WireMockExtension wmClouddriver = + WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); + + @RegisterExtension + static WireMockExtension wmFront50 = + WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); + + @DynamicPropertySource + static void registerUrls(DynamicPropertyRegistry registry) { + // Configure wiremock's random ports into gate + System.out.println("wiremock echo url: " + wmEcho.baseUrl()); + System.out.println("wiremock clouddriver url: " + wmClouddriver.baseUrl()); + System.out.println("wiremock front50 url: " + wmFront50.baseUrl()); + registry.add("services.echo.base-url", wmEcho::baseUrl); + registry.add("services.clouddriver.base-url", wmClouddriver::baseUrl); + registry.add("services.front50.base-url", wmFront50::baseUrl); } - @AfterAll - static void tearDown() throws IOException { - echoServer.shutdown(); - clouddriverServer.shutdown(); - front50Server.shutdown(); + @BeforeAll + static void setUp() throws IOException { + wmClouddriver.stubFor(any(anyUrl()).willReturn(aResponse().withStatus(200))); + wmFront50.stubFor(any(anyUrl()).willReturn(aResponse().withStatus(200))); } @Test - void shouldNotOrderTheKeysWhenCallingEcho() throws InterruptedException { + void shouldNotOrderTheKeysWhenCallingEcho() throws Exception { + + // The response is arbitrary. This test verifies the request body that gate + // sends to echo. + wmEcho.stubFor( + post("/webhooks/git/github").willReturn(aResponse().withStatus(200).withBody("{}"))); - echoServer.enqueue(new MockResponse().setResponseCode(200)); Map body = new HashMap<>(); body.put("ref", "refs/heads/main"); body.put("before", "ca7376e4b730f1f2878760abaeaed6c039fc5414"); @@ -98,10 +102,12 @@ void shouldNotOrderTheKeysWhenCallingEcho() throws InterruptedException { body.put("id", 105648914); echoService.webhooks("git", "github", body); - RecordedRequest recordedRequest = echoServer.takeRequest(2, TimeUnit.SECONDS); - String requestBody = recordedRequest.getBody().readUtf8(); - assertThat(requestBody) - .isEqualTo( - "{\"ref\":\"refs/heads/main\",\"before\":\"ca7376e4b730f1f2878760abaeaed6c039fc5414\",\"after\":\"c2420ce6e341ef0042f2e12591bdbe9eec29a032\",\"id\":105648914}"); + + String expectedBody = + "{\"ref\":\"refs/heads/main\",\"before\":\"ca7376e4b730f1f2878760abaeaed6c039fc5414\",\"after\":\"c2420ce6e341ef0042f2e12591bdbe9eec29a032\",\"id\":105648914}"; + + wmEcho.verify( + postRequestedFor(urlPathEqualTo("/webhooks/git/github")) + .withRequestBody(equalTo(expectedBody))); } } diff --git a/gate-web/src/test/resources/application-echo.properties b/gate-web/src/test/resources/application-echo.properties index f1ee4857ea..0fb20f3ca9 100644 --- a/gate-web/src/test/resources/application-echo.properties +++ b/gate-web/src/test/resources/application-echo.properties @@ -15,30 +15,24 @@ # spring.application.name=gate -services.clouddriver.baseUrl=http://localhost:7002 -services.deck.baseUrl=http://localhost:9000 services.echo.enabled=true -services.echo.baseUrl=http://localhost:8089 services.fiat.enabled=false - -services.fiat.baseUrl=http://localhost:8082 - -services.front50.baseUrl=http://localhost:8081 +services.fiat.baseUrl=http://nowhere services.igor.enabled=false services.kayenta.enabled=false -services.orca.baseUrl=http://localhost:8083 +services.orca.baseUrl=http://nowhere services.mine.enabled=false services.swabbie.enabled=false services.keel.enabled=false -services.keel.baseUrl=http://localhost:8087 +services.keel.baseUrl=http://nowhere retrofit.enabled=true healthCheckableServices=igor