From 13ca0a54f6106dbf33053153e0ee68fe0e62b57c Mon Sep 17 00:00:00 2001 From: alobodzki Date: Wed, 28 Feb 2018 11:15:32 +0000 Subject: [PATCH] fix for issue #90: Race condition in e2e test: ExpiringConnectionSpec (#95) * fix for issue #90: Race condition in e2e test: ExpiringConnectionSpec --- .../styx/support/api/BlockingObservables.java | 4 +- .../styx/client/ExpiringConnectionSpec.scala | 41 +++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/support/api-testsupport/src/main/java/com/hotels/styx/support/api/BlockingObservables.java b/support/api-testsupport/src/main/java/com/hotels/styx/support/api/BlockingObservables.java index dfdf69b0c5..4b9bb11880 100644 --- a/support/api-testsupport/src/main/java/com/hotels/styx/support/api/BlockingObservables.java +++ b/support/api-testsupport/src/main/java/com/hotels/styx/support/api/BlockingObservables.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013-2017 Expedia Inc. + * Copyright (C) 2013-2018 Expedia Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ public static FullHttpResponse waitForResponse(Observable response return responseObs .flatMap(response -> response.toFullResponse(120*1024)) .toBlocking() - .first(); + .single(); } public static HttpResponse waitForStreamingResponse(Observable responseObs) { diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/ExpiringConnectionSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/ExpiringConnectionSpec.scala index e9be110f36..5543becb69 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/ExpiringConnectionSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/ExpiringConnectionSpec.scala @@ -18,15 +18,19 @@ package com.hotels.styx.client import java.nio.charset.StandardCharsets.UTF_8 import com.github.tomakehurst.wiremock.client.WireMock.{get => _, _} +import com.hotels.styx.{DefaultStyxConfiguration, StyxProxySpec} import com.hotels.styx.api.HttpRequest.Builder._ +import com.hotels.styx.api.client.Origin.newOriginBuilder +import com.hotels.styx.api.client.{ActiveOrigins, Origin} import com.hotels.styx.api.messages.HttpResponseStatus.OK +import com.hotels.styx.client.OriginsInventory.newOriginsInventoryBuilder +import com.hotels.styx.client.StyxHttpClient.newHttpClientBuilder +import com.hotels.styx.client.applications.BackendService +import com.hotels.styx.client.loadbalancing.strategies.RoundRobinStrategy import com.hotels.styx.support.api.BlockingObservables.waitForResponse import com.hotels.styx.support.backends.FakeHttpServer import com.hotels.styx.support.configuration.{ConnectionPoolSettings, HttpBackend, Origins, StyxConfig} import com.hotels.styx.support.server.UrlMatchingStrategies._ -import com.hotels.styx.{StyxClientSupplier, StyxProxySpec} -import io.netty.handler.codec.http.HttpHeaders.Names._ -import io.netty.handler.codec.http.HttpHeaders.Values._ import org.hamcrest.MatcherAssert._ import org.hamcrest.Matchers._ import org.scalatest.FunSpec @@ -35,19 +39,17 @@ import org.scalatest.concurrent.Eventually import scala.concurrent.duration._ class ExpiringConnectionSpec extends FunSpec + with DefaultStyxConfiguration with StyxProxySpec - with StyxClientSupplier with Eventually { val mockServer = FakeHttpServer.HttpStartupConfig() .start() .stub(urlStartingWith("/app1"), aResponse .withStatus(200) - .withHeader(TRANSFER_ENCODING, CHUNKED) - .withBody("I should be here!") ) - override val styxConfig = StyxConfig() + var pooledClient: StyxHttpClient = _ override protected def beforeAll(): Unit = { super.beforeAll() @@ -57,10 +59,13 @@ class ExpiringConnectionSpec extends FunSpec connectionPoolConfig = ConnectionPoolSettings(connectionExpirationSeconds = 1L)) ) - val request = get(s"http://localhost:${mockServer.port()}/app1").build() - val resp = decodedRequest(request) - resp.status() should be(OK) - resp.bodyAs(UTF_8) should be("I should be here!") + val backendService = new BackendService.Builder() + .origins(newOriginBuilder("localhost", styxServer.httpPort).build()) + .build() + + pooledClient = newHttpClientBuilder(backendService) + .loadBalancingStrategy(roundRobinStrategy(activeOrigins(backendService))) + .build } override protected def afterAll(): Unit = { @@ -69,25 +74,29 @@ class ExpiringConnectionSpec extends FunSpec } it("Should expire connection after 1 second") { - val request = get(styxServer.routerURL("/app1")) - .build() + val request = get(styxServer.routerURL("/app1")).build() - val response1 = waitForResponse(client.sendRequest(request)) + val response1 = waitForResponse(pooledClient.sendRequest(request)) assertThat(response1.status(), is(OK)) - eventually(timeout(2.seconds)) { + eventually(timeout(1.seconds)) { styxServer.metricsSnapshot.gauge(s"origins.appOne.generic-app-01.connectionspool.available-connections").get should be(1) styxServer.metricsSnapshot.gauge(s"origins.appOne.generic-app-01.connectionspool.connections-closed").get should be(0) } Thread.sleep(1000) - val response2 = waitForResponse(client.sendRequest(request)) + val response2 = waitForResponse(pooledClient.sendRequest(request)) + assertThat(response2.status(), is(OK)) eventually(timeout(2.seconds)) { styxServer.metricsSnapshot.gauge(s"origins.appOne.generic-app-01.connectionspool.available-connections").get should be(1) styxServer.metricsSnapshot.gauge(s"origins.appOne.generic-app-01.connectionspool.connections-terminated").get should be(1) } } + + def activeOrigins(backendService: BackendService): ActiveOrigins = newOriginsInventoryBuilder(backendService).build() + + def roundRobinStrategy(activeOrigins: ActiveOrigins): RoundRobinStrategy = new RoundRobinStrategy(activeOrigins) }