package com.baiyue.common.web; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.jupiter.api.Test; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import java.time.LocalDateTime; import java.sql.Timestamp; import java.util.Map; import java.util.List; import static org.mockito.ArgumentMatchers.*; import java.util.UUID; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; class EventDeliveryMetricsTest { @Test void samplesBoundedTypesAndPreservesPriorValuesWhenDatabaseFailsWithoutQueryingDuringScrapes() { var jdbc = spy(new JdbcTemplate(new DriverManagerDataSource("jdbc:h2:mem:" + UUID.randomUUID() + ";MODE=MySQL;DB_CLOSE_DELAY=-1", "sa", ""))); jdbc.execute("CREATE TABLE ll_event_outbox(event_type VARCHAR(200),status VARCHAR(32),created_at TIMESTAMP)"); var now = LocalDateTime.now(); jdbc.update("INSERT INTO ll_event_outbox VALUES('BusinessFeeSourceChanged','PENDING',?)", now.minusSeconds(60)); jdbc.update("INSERT INTO ll_event_outbox VALUES('BusinessFeeSourceChanged','PROCESSING',?)", now.minusSeconds(30)); jdbc.update("INSERT INTO ll_event_outbox VALUES('BusinessFeeSourceChanged','DEAD',?)", now.minusSeconds(120)); jdbc.update("INSERT INTO ll_event_outbox VALUES('user-controlled-unknown-type','PENDING',?)", now.minusYears(1)); var registry = new SimpleMeterRegistry(); var metrics = new EventDeliveryMetrics(jdbc, registry); metrics.sample(EventDeliveryMetrics.Stream.FEE, now); assertThat(registry.get("baiyue.event.delivery.pending").gauge().value()).isEqualTo(2); assertThat(registry.get("baiyue.event.delivery.dead").gauge().value()).isEqualTo(1); assertThat(registry.get("baiyue.event.delivery.oldest.pending.seconds").gauge().value()).isBetween(59.99, 60.01); double sampledAt = registry.get("baiyue.event.delivery.sample.timestamp").gauge().value(); jdbc.execute("DROP TABLE ll_event_outbox"); metrics.sample(EventDeliveryMetrics.Stream.FEE, now.plusMinutes(1)); clearInvocations(jdbc); assertThat(registry.get("baiyue.event.delivery.pending").gauge().value()).isEqualTo(2); assertThat(registry.get("baiyue.event.delivery.sample.timestamp").gauge().value()).isEqualTo(sampledAt); assertThat(registry.get("baiyue.event.delivery.sample.success").gauge().value()).isZero(); registry.getMeters().forEach(meter -> { assertThat(meter.getId().getTag("event_type")).isEqualTo("BusinessFeeSourceChanged"); meter.measure().forEach(measurement -> measurement.getValue()); }); verifyNoInteractions(jdbc); } @Test void supportsBothMysqlLocalDateTimeAndJdbcTimestampAndRejectsUnknownTypes() { var jdbc = mock(JdbcTemplate.class); var now = LocalDateTime.of(2026, 9, 29, 12, 0); var registry = new SimpleMeterRegistry(); var metrics = new EventDeliveryMetrics(jdbc, registry); for (Object oldest : List.of(now.minusSeconds(45), Timestamp.valueOf(now.minusSeconds(45)))) { Map row = Map.of("pending_count", 1L, "dead_count", 0L, "oldest", oldest); when(jdbc.queryForMap(anyString(), eq("BusinessFeeSourceChanged"))).thenReturn(row); metrics.sample(EventDeliveryMetrics.Stream.FEE, now); assertThat(registry.get("baiyue.event.delivery.oldest.pending.seconds").gauge().value()).isEqualTo(45); assertThat(registry.get("baiyue.event.delivery.sample.success").gauge().value()).isEqualTo(1); } when(jdbc.queryForMap(anyString(), eq("BusinessFeeSourceChanged"))) .thenReturn(Map.of("pending_count", 0L, "dead_count", 0L, "oldest", "not a JDBC time")); metrics.sample(EventDeliveryMetrics.Stream.FEE, now); assertThat(registry.get("baiyue.event.delivery.pending").gauge().value()).isEqualTo(1); assertThat(registry.get("baiyue.event.delivery.oldest.pending.seconds").gauge().value()).isEqualTo(45); assertThat(registry.get("baiyue.event.delivery.sample.success").gauge().value()).isZero(); } @Test void initialFailureIsUnknownRatherThanFalseZero() { var jdbc = new JdbcTemplate(new DriverManagerDataSource("jdbc:h2:mem:" + UUID.randomUUID(), "sa", "")); var registry = new SimpleMeterRegistry(); new EventDeliveryMetrics(jdbc, registry).sample(EventDeliveryMetrics.Stream.FINANCE, LocalDateTime.now()); assertThat(registry.get("baiyue.event.delivery.pending").gauge().value()).isNaN(); assertThat(registry.get("baiyue.event.delivery.sample.timestamp").gauge().value()).isZero(); assertThat(registry.get("baiyue.event.delivery.sample.success").gauge().value()).isZero(); } }