metrics-facade icon indicating copy to clipboard operation
metrics-facade copied to clipboard

Provide tooling for unit testing

Open rc-mairovichaa opened this issue 1 year ago • 1 comments

To simplify unit testing it would be nice to have utility methods, which will ease retrieval of current Metric's values.

Example, which could be used as the starting point - showing needs at least some of our clients have

import com.ringcentral.platform.metrics.MetricInstance;
import com.ringcentral.platform.metrics.MetricKey;
import com.ringcentral.platform.metrics.MetricRegistry;
import com.ringcentral.platform.metrics.counter.Counter;
import com.ringcentral.platform.metrics.dimensions.MetricDimensionValues;
import com.ringcentral.platform.metrics.var.longVar.LongVar;
import org.awaitility.Awaitility;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
import java.util.stream.StreamSupport;

import static com.ringcentral.platform.metrics.dimensions.MetricDimensionValues.NO_DIMENSION_VALUES;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class MetricAssertions {

    public static void assertLongVar(
            MetricRegistry registry,
            long expectedValue,
            MetricKey name,
            MetricDimensionValues dimensionValues,
            Duration maxWaitTime) {

        Awaitility.await().atMost(maxWaitTime)
                .untilAsserted(() -> {
                    assertEquals(expectedValue, findMetric(registry, name, dimensionValues)
                            .map(m -> m.valueOf(LongVar.LONG_VALUE))
                            .orElse(0L));
                });
    }

    public static void assertLongVar(
            MetricRegistry registry,
            long expectedValue,
            MetricKey name) {

        assertLongVar(registry, expectedValue, name, NO_DIMENSION_VALUES, Duration.of(5, ChronoUnit.SECONDS));
    }

    public static void assertCounterMetric(
            MetricRegistry registry,
            long expectedValue,
            MetricKey name,
            MetricDimensionValues dimensionValues,
            Duration maxWaitTime) {

        Awaitility.await().pollInterval(Duration.ofMillis(10)).atMost(maxWaitTime)
                .untilAsserted(() -> assertEquals(expectedValue, getCounterMetric(registry, name, dimensionValues)));
    }

    public static void assertCounterMetric(
            MetricRegistry registry,
            long expectedValue,
            MetricKey name) {

        assertCounterMetric(registry, expectedValue, name, NO_DIMENSION_VALUES, Duration.of(5, ChronoUnit.SECONDS));
    }

    public static long getCounterMetric(
            MetricRegistry registry,
            MetricKey name,
            MetricDimensionValues dimensionValues) {

        return findMetric(registry, name, dimensionValues)
                .map(m -> (Long) m.valueOf(Counter.COUNT))
                .orElse(0L);
    }

    public static long getCounterMetric(MetricRegistry registry, MetricKey name) {
        return getCounterMetric(registry, name, NO_DIMENSION_VALUES);
    }

    public static void assertTimerCountMetric(
            MetricRegistry registry,
            long expectedValue,
            MetricKey name,
            MetricDimensionValues dimensionValues,
            Duration maxWaitTime) {

        Awaitility.await().atMost(maxWaitTime)
                .untilAsserted(() -> {
                    assertEquals(expectedValue, findMetric(registry, name, dimensionValues)
                            .map(m -> m.valueOf(Counter.COUNT))
                            .orElse(0L));
                });
    }

    public static void assertTimerCountMetric(
            MetricRegistry registry,
            long expectedValue,
            MetricKey name) {

        assertTimerCountMetric(registry, expectedValue, name, NO_DIMENSION_VALUES, Duration.of(5, ChronoUnit.SECONDS));
    }

    public static void assertMetricExist(MetricRegistry registry, MetricKey name) {
        assertTrue(
                registry.metrics()
                        .entrySet()
                        .stream()
                        .anyMatch(m -> m.getKey().equals(name)),
                "Metric " + name + " should be presented"
        );
    }

    public static void assertMetricWithPrefixExist(MetricRegistry registry, MetricKey prefix) {
        assertTrue(
                registry.metrics()
                        .entrySet()
                        .stream()
                        .anyMatch(m -> m.getKey().toString().startsWith(prefix.toString())),
                "Metric prefix should be presented"
        );
    }

    private static Optional<MetricInstance> findMetric(MetricRegistry registry, MetricKey name, MetricDimensionValues dimensionValues) {
        return registry.metrics().entrySet()
                .stream()
                .filter(m -> m.getKey().equals(name))
                .flatMap(m -> StreamSupport.stream(m.getValue().spliterator(), false))
                .filter(metric -> dimensionValues.list().stream()
                        .allMatch(d -> d.value().equals(metric.valueOf(d.dimension()))))
                .findFirst();
    }
}

rc-mairovichaa avatar Sep 23 '24 17:09 rc-mairovichaa

It might be great also to have find out metric measurable by metricname and metricdimensionvalues. If null - only by metricname.

jeremyspb avatar Sep 24 '24 07:09 jeremyspb