-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FFM-6581 - Java SDK - Poller was not restarted + timeouts logged (#135)
* FFM-6581 - Java SDK - Poller was not restarted + timeouts logged What Fixed timeout exception, reduce some log levels to debug and added additional unit tests. Why We see timeout errors logged becauses the code calls awaitTermination() before shutDown() when stopping the update processor. Also we log misleading warnings about poller not being restarted when in fact the code is working as intented (though it's candidate for additional optimisation in future releases). Testing Added new unit tets for EventSource + manual testing
- Loading branch information
1 parent
21d2e9a
commit b2bdbe0
Showing
10 changed files
with
212 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
src/test/java/io/harness/cf/client/connector/CountingUpdater.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package io.harness.cf.client.connector; | ||
|
||
import io.harness.cf.client.api.testutils.PollingAtomicLong; | ||
import io.harness.cf.client.dto.Message; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
class CountingUpdater implements Updater { | ||
@Getter @Setter private PollingAtomicLong connectCount = new PollingAtomicLong(0); | ||
@Getter @Setter private PollingAtomicLong disconnectCount = new PollingAtomicLong(0); | ||
@Getter @Setter private PollingAtomicLong readyCount = new PollingAtomicLong(0); | ||
@Getter @Setter private PollingAtomicLong failureCount = new PollingAtomicLong(0); | ||
@Getter @Setter private PollingAtomicLong updateCount = new PollingAtomicLong(0); | ||
@Getter @Setter private PollingAtomicLong errorCount = new PollingAtomicLong(0); | ||
|
||
@Override | ||
public void onConnected() { | ||
log.debug("onConnected"); | ||
connectCount.incrementAndGet(); | ||
} | ||
|
||
@Override | ||
public void onDisconnected() { | ||
log.debug("onDisconnected"); | ||
disconnectCount.incrementAndGet(); | ||
} | ||
|
||
@Override | ||
public void onReady() { | ||
log.debug("onReady"); | ||
readyCount.incrementAndGet(); | ||
} | ||
|
||
@Override | ||
public void onFailure(String message) { | ||
log.debug("onFailure: " + message); | ||
failureCount.incrementAndGet(); | ||
} | ||
|
||
@Override | ||
public void onError() { | ||
log.info("onError"); | ||
errorCount.incrementAndGet(); | ||
} | ||
|
||
@Override | ||
public void update(Message message) { | ||
log.debug("update: " + message); | ||
updateCount.incrementAndGet(); | ||
} | ||
}; |
127 changes: 127 additions & 0 deletions
127
src/test/java/io/harness/cf/client/connector/EventSourceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package io.harness.cf.client.connector; | ||
|
||
import static io.harness.cf.client.api.dispatchers.CannedResponses.*; | ||
import static java.lang.System.out; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
import java.io.IOException; | ||
import java.util.HashMap; | ||
import java.util.Objects; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
import lombok.SneakyThrows; | ||
import lombok.extern.slf4j.Slf4j; | ||
import okhttp3.mockwebserver.*; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.junit.jupiter.api.Test; | ||
|
||
@Slf4j | ||
class EventSourceTest { | ||
|
||
private final AtomicInteger version = new AtomicInteger(2); | ||
|
||
static class StreamDispatcher extends Dispatcher { | ||
private final AtomicInteger version = new AtomicInteger(2); | ||
protected final AtomicInteger request = new AtomicInteger(1); | ||
|
||
protected MockResponse makeStreamResponse() { | ||
int reqNo = request.getAndIncrement(); | ||
if (reqNo <= 3) { | ||
// Force a disconnect on the first few attempts | ||
out.printf("ReqNo %d will be disconnected on purpose\n", reqNo); | ||
return new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AFTER_REQUEST); | ||
} else { | ||
// Eventually allow a good connection attempt and send a flag | ||
out.printf("ReqNo %d will be allowed\n", reqNo); | ||
return makeMockStreamResponse( | ||
200, | ||
makeFlagPatchEvent("simplebool", version.getAndIncrement()), | ||
makeFlagPatchEvent("simplebool", version.getAndIncrement())) | ||
.setSocketPolicy(SocketPolicy.KEEP_OPEN); | ||
} | ||
} | ||
|
||
@Override | ||
@SneakyThrows | ||
@NotNull | ||
public MockResponse dispatch(RecordedRequest recordedRequest) { | ||
out.println("DISPATCH GOT ------> " + recordedRequest.getPath()); | ||
|
||
// recordedRequest.getHeaders().forEach(h -> out.printf(" %s: %s\n", h.component1(), | ||
// h.component2())); | ||
|
||
if (Objects.requireNonNull(recordedRequest.getPath()).equals("/api/1.0/stream?cluster=1")) { | ||
return makeStreamResponse(); | ||
} | ||
throw new UnsupportedOperationException("ERROR: url not mapped " + recordedRequest.getPath()); | ||
} | ||
} | ||
|
||
static class FailingStreamDispatcher extends StreamDispatcher { | ||
@Override | ||
protected MockResponse makeStreamResponse() { | ||
int reqNo = request.getAndIncrement(); | ||
// Force a disconnect on all requests | ||
out.printf("ReqNo %d will be disconnected on purpose\n", reqNo); | ||
return new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AFTER_REQUEST); | ||
} | ||
} | ||
|
||
@Test | ||
void shouldNotCallErrorHandlerIfRetryEventuallyReconnectsToStreamEndpoint() | ||
throws IOException, InterruptedException { | ||
CountingUpdater updater = new CountingUpdater(); | ||
|
||
try (MockWebServer mockSvr = new MockWebServer(); | ||
EventSource eventSource = | ||
new EventSource( | ||
setupMockServer(mockSvr, new StreamDispatcher()), new HashMap<>(), updater, 1, 1)) { | ||
eventSource.start(); | ||
|
||
TimeUnit.SECONDS.sleep(15); | ||
} | ||
|
||
// for this test, connection to the /stream endpoint will fail several times but eventually | ||
// connect. | ||
// There should be at least 1 connect event. Each retry calls onError | ||
|
||
assertTrue(updater.getConnectCount().get() >= 1); | ||
assertEquals(0, updater.getFailureCount().get()); | ||
assertEquals(5, updater.getErrorCount().get()); | ||
} | ||
|
||
@Test | ||
void shouldRestartPollerIfAllConnectionAttemptsToStreamEndpointFail() | ||
throws IOException, InterruptedException { | ||
CountingUpdater updater = new CountingUpdater(); | ||
|
||
try (MockWebServer mockSvr = new MockWebServer(); | ||
EventSource eventSource = | ||
new EventSource( | ||
setupMockServer(mockSvr, new FailingStreamDispatcher()), | ||
new HashMap<>(), | ||
updater, | ||
1, | ||
1)) { | ||
eventSource.start(); | ||
|
||
TimeUnit.SECONDS.sleep(15); | ||
} | ||
|
||
// for this test, connection to the /stream endpoint will never succeed. | ||
// we expect the error handler to be called, connect handler should not be called | ||
|
||
assertEquals(0, updater.getConnectCount().get()); | ||
assertEquals(0, updater.getFailureCount().get()); | ||
assertTrue(updater.getErrorCount().get() >= 1); | ||
} | ||
|
||
@SneakyThrows | ||
private String setupMockServer(MockWebServer mockSvr, Dispatcher dispatcher) { | ||
mockSvr.setDispatcher(dispatcher); | ||
mockSvr.start(); | ||
return String.format( | ||
"http://%s:%s/api/1.0/stream?cluster=%d", mockSvr.getHostName(), mockSvr.getPort(), 1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters