diff --git a/application/src/main/java/org/togetherjava/tjbot/features/analytics/Metrics.java b/application/src/main/java/org/togetherjava/tjbot/features/analytics/Metrics.java index 9da595eaab..9e09c99f85 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/analytics/Metrics.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/analytics/Metrics.java @@ -44,6 +44,26 @@ public void count(String event) { count(event, Map.of()); } + /** + * Track an event execution with dimensions provided. + * + * @param event the event to save + * @param dimensions the dimensions to save + */ + public void count(String event, Map dimensions) { + count(event, dimensions, true); + } + + /** + * Track an event execution with flag for async execution. + * + * @param event the event to save + * @param doAsync the async flag + */ + public void count(String event, boolean doAsync) { + count(event, Map.of(), doAsync); + } + /** * Track an event execution with additional contextual data. * @@ -54,14 +74,19 @@ public void count(String event) { * and analyzing events later. Note: A value for a metric should be a Java primitive * (String, int, double, long float). */ - public void count(String event, Map dimensions) { + void count(String event, Map dimensions, boolean doAsync) { logger.debug("Counting new record for event: {}", event); Instant happenedAt = Instant.now(); - String serializedDimensions = serializeDimensions(dimensions); + String serializedDimensions = dimensions.isEmpty() ? null : serializeDimensions(dimensions); + + Runnable task = () -> processEvent(event, happenedAt, serializedDimensions); - service.submit(() -> processEvent(event, happenedAt, - dimensions.isEmpty() ? null : serializedDimensions)); + if (doAsync) { + service.submit(task); + } else { + task.run(); + } } private static String serializeDimensions(Map dimensions) { @@ -72,12 +97,6 @@ private static String serializeDimensions(Map dimensions) { } } - /** - * - * @param event the event to save - * @param happenedAt the moment when the event is dispatched - * @param dimensionsJson optional JSON-serialized dimensions, or null - */ private void processEvent(String event, Instant happenedAt, @Nullable String dimensionsJson) { database.write(context -> context.newRecord(MetricEvents.METRIC_EVENTS) .setEvent(event) @@ -86,4 +105,14 @@ private void processEvent(String event, Instant happenedAt, @Nullable String dim .insert()); } + /** + * Exposes the underlying executor service. + *

+ * Intended for test teardown only. + * + * @return the executor service backing this instance + */ + public ExecutorService getExecutorService() { + return service; + } } diff --git a/application/src/test/java/org/togetherjava/tjbot/features/MetricsTests.java b/application/src/test/java/org/togetherjava/tjbot/features/MetricsTests.java new file mode 100644 index 0000000000..c9628760c7 --- /dev/null +++ b/application/src/test/java/org/togetherjava/tjbot/features/MetricsTests.java @@ -0,0 +1,47 @@ +package org.togetherjava.tjbot.features; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.togetherjava.tjbot.db.Database; +import org.togetherjava.tjbot.db.generated.tables.MetricEvents; +import org.togetherjava.tjbot.db.generated.tables.records.MetricEventsRecord; +import org.togetherjava.tjbot.features.analytics.Metrics; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +final class MetricsTests { + private Database database; + private Metrics metrics; + + @BeforeEach + void setUp() { + database = Database.createMemoryDatabase(MetricEvents.METRIC_EVENTS); + metrics = new Metrics(database); + } + + @AfterEach + void tearDown() { + metrics.getExecutorService().shutdownNow(); + } + + @Test + void countWithDoAsyncFalsePersists() { + + String testEvent = "metrics_test_event"; + + metrics.count(testEvent, false); + + MetricEventsRecord savedRecord = + database.read(context -> context.selectFrom(MetricEvents.METRIC_EVENTS).fetchOne()); + + assertNotNull(savedRecord); + + assertEquals(testEvent, savedRecord.get(MetricEvents.METRIC_EVENTS.EVENT)); + assertNull(savedRecord.get(MetricEvents.METRIC_EVENTS.DIMENSIONS)); + } + +}