|
| 1 | +package org.ebean.monitor.config; |
| 2 | + |
| 3 | +import org.ebean.monitor.api.MetricRequest; |
| 4 | +import org.ebean.monitor.domain.DApp; |
| 5 | +import org.ebean.monitor.domain.DCaptureRequest; |
| 6 | +import org.ebean.monitor.domain.DEnv; |
| 7 | +import org.ebean.monitor.ingest.PlanShapeBackfill; |
| 8 | +import org.ebean.monitor.web.MessageService; |
| 9 | +import org.junit.jupiter.api.Test; |
| 10 | + |
| 11 | +import java.time.Instant; |
| 12 | +import java.util.List; |
| 13 | + |
| 14 | +import static org.assertj.core.api.Assertions.assertThat; |
| 15 | + |
| 16 | +/** |
| 17 | + * Unit tests for {@link OnStart#pushPendingCaptures}: verifies that pending |
| 18 | + * capture requests are re-pushed into {@link MessageService} correctly on |
| 19 | + * startup, covering both env-specific and any-env cases. |
| 20 | + */ |
| 21 | +class OnStartRehydrateTest { |
| 22 | + |
| 23 | + /** No-op backfill stub — PlanShapeBackfill.run() is never called by pushPendingCaptures. */ |
| 24 | + private static final class NoopBackfill extends PlanShapeBackfill { |
| 25 | + NoopBackfill() { super(null); } |
| 26 | + @Override public int run() { return 0; } |
| 27 | + } |
| 28 | + |
| 29 | + private final MessageService messageService = new MessageService(); |
| 30 | + private final OnStart onStart = new OnStart(new NoopBackfill(), messageService); |
| 31 | + |
| 32 | + private static MetricRequest poll(String app, String env) { |
| 33 | + return MetricRequest.builder().appName(app).environment(env).build(); |
| 34 | + } |
| 35 | + |
| 36 | + private static DCaptureRequest request(String appName, String envName, String hash) { |
| 37 | + DApp app = new DApp(appName); |
| 38 | + DEnv env = envName != null ? new DEnv(envName) : null; |
| 39 | + return new DCaptureRequest(app, hash) |
| 40 | + .setEnv(env) |
| 41 | + .setRequestedAt(Instant.now()); |
| 42 | + } |
| 43 | + |
| 44 | + @Test |
| 45 | + void envSpecific_rehydratedAndDeliveredToCorrectEnv() { |
| 46 | + var r = request("myapp", "test", "abc123"); |
| 47 | + |
| 48 | + int count = onStart.pushPendingCaptures(List.of(r)); |
| 49 | + |
| 50 | + assertThat(count).isEqualTo(1); |
| 51 | + assertThat(messageService.pendingResponse()).isTrue(); |
| 52 | + // delivered to the matching env |
| 53 | + assertThat(messageService.responseBody(poll("myapp", "test"))).isEqualTo("v1|qp:abc123"); |
| 54 | + // queue is now drained |
| 55 | + assertThat(messageService.pendingResponse()).isFalse(); |
| 56 | + } |
| 57 | + |
| 58 | + @Test |
| 59 | + void anyEnv_nullEnvOnRequest_usesAnyEnvSentinel() { |
| 60 | + var r = request("myapp", null, "def456"); |
| 61 | + |
| 62 | + onStart.pushPendingCaptures(List.of(r)); |
| 63 | + |
| 64 | + // any-env bucket: delivered regardless of which env polls |
| 65 | + assertThat(messageService.responseBody(poll("myapp", "prod"))).isEqualTo("v1|qp:def456"); |
| 66 | + } |
| 67 | + |
| 68 | + @Test |
| 69 | + void multipleRequests_allRehydrated() { |
| 70 | + var r1 = request("app1", "dev", "hash1"); |
| 71 | + var r2 = request("app1", "dev", "hash2"); |
| 72 | + var r3 = request("app2", null, "hash3"); |
| 73 | + |
| 74 | + int count = onStart.pushPendingCaptures(List.of(r1, r2, r3)); |
| 75 | + |
| 76 | + assertThat(count).isEqualTo(3); |
| 77 | + String body = messageService.responseBody(poll("app1", "dev")); |
| 78 | + assertThat(body).contains("qp:hash1").contains("qp:hash2"); |
| 79 | + assertThat(messageService.responseBody(poll("app2", "test"))).isEqualTo("v1|qp:hash3"); |
| 80 | + } |
| 81 | + |
| 82 | + @Test |
| 83 | + void emptyList_returnsZero_noMessagesQueued() { |
| 84 | + int count = onStart.pushPendingCaptures(List.of()); |
| 85 | + |
| 86 | + assertThat(count).isEqualTo(0); |
| 87 | + assertThat(messageService.pendingResponse()).isFalse(); |
| 88 | + } |
| 89 | +} |
0 commit comments