package org.jooby.metrics; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.isA; import java.util.function.BiConsumer; import org.jooby.Env; import org.jooby.Jooby; import org.jooby.Route; import org.jooby.Router; import org.jooby.internal.metrics.HealthCheckRegistryInitializer; import org.jooby.internal.metrics.MetricRegistryInitializer; import org.jooby.test.MockUnit; import org.jooby.test.MockUnit.Block; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import com.codahale.metrics.ConsoleReporter; import com.codahale.metrics.Meter; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Reporter; import com.codahale.metrics.health.HealthCheck; import com.codahale.metrics.health.HealthCheckRegistry; import com.google.inject.Binder; import com.google.inject.binder.AnnotatedBindingBuilder; import com.google.inject.binder.LinkedBindingBuilder; import com.google.inject.multibindings.MapBinder; import com.google.inject.multibindings.Multibinder; import com.typesafe.config.Config; import javaslang.control.Try.CheckedConsumer; @RunWith(PowerMockRunner.class) @PrepareForTest({Metrics.class, MapBinder.class, Multibinder.class }) public class MetricsTest { @SuppressWarnings("unchecked") private Block bindMetricRegistry = unit -> { MetricRegistry registry = unit.get(MetricRegistry.class); AnnotatedBindingBuilder<MetricRegistry> mrABB = unit.mock(AnnotatedBindingBuilder.class); mrABB.toInstance(registry); Binder binder = unit.get(Binder.class); expect(binder.bind(MetricRegistry.class)).andReturn(mrABB); }; @SuppressWarnings("unchecked") private Block bindMetricRegistryInitializer = unit -> { AnnotatedBindingBuilder<MetricRegistryInitializer> mrABB = unit .mock(AnnotatedBindingBuilder.class); mrABB.asEagerSingleton(); Binder binder = unit.get(Binder.class); expect(binder.bind(MetricRegistryInitializer.class)).andReturn(mrABB); }; @SuppressWarnings("unchecked") private Block bindHealthCheckRegistry = unit -> { HealthCheckRegistry registry = unit.get(HealthCheckRegistry.class); AnnotatedBindingBuilder<HealthCheckRegistry> hcrABB = unit.mock(AnnotatedBindingBuilder.class); hcrABB.toInstance(registry); Binder binder = unit.get(Binder.class); expect(binder.bind(HealthCheckRegistry.class)).andReturn(hcrABB); }; @SuppressWarnings("unchecked") private Block bindHealthCheckRegistryInitializer = unit -> { AnnotatedBindingBuilder<HealthCheckRegistryInitializer> hcrABB = unit .mock(AnnotatedBindingBuilder.class); hcrABB.asEagerSingleton(); Binder binder = unit.get(Binder.class); expect(binder.bind(HealthCheckRegistryInitializer.class)).andReturn(hcrABB); }; private Block newMetricRegistry = unit -> { MetricRegistry registry = unit.constructor(MetricRegistry.class) .build(); unit.registerMock(MetricRegistry.class, registry); }; private Block newHealthCheckRegistry = unit -> { HealthCheckRegistry registry = unit.constructor(HealthCheckRegistry.class) .build(); unit.registerMock(HealthCheckRegistry.class, registry); }; private Block mapBinderStatic = unit -> { unit.mockStatic(MapBinder.class); }; private Block multibinderStatic = unit -> { unit.mockStatic(Multibinder.class); }; private Block routes = unit -> { Router routes = unit.mock(Router.class); unit.registerMock(Router.class, routes); Env env = unit.get(Env.class); expect(env.router()).andReturn(routes); MetricHandler handler = unit.constructor(MetricHandler.class).build(); route(unit, routes, "/sys/metrics", handler); route(unit, routes, "/sys/metrics/:type", handler); route(unit, routes, "/sys/healthcheck", unit.constructor(HealthCheckHandler.class).build()); }; @SuppressWarnings("unchecked") private Block onStop = unit -> { Env env = unit.get(Env.class); expect(env.onStop(unit.capture(CheckedConsumer.class))).andReturn(env); }; @SuppressWarnings("unchecked") @Test public void basic() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, Jooby.class, MetricRegistryInitializer.class) .expect(newMetricRegistry) .expect(newHealthCheckRegistry) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(multibinderStatic) .expect(routes) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .expect(unit -> { MetricRegistryInitializer closer = unit.get(MetricRegistryInitializer.class); closer.close(); Jooby app = unit.get(Jooby.class); expect(app.require(MetricRegistryInitializer.class)).andReturn(closer); }) .run(unit -> { new Metrics() .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }, unit -> { unit.captured(CheckedConsumer.class).get(0).accept(unit.get(Jooby.class)); }); } @Test public void basicWithExtMetricRegistry() throws Exception { new MockUnit(Env.class, Config.class, Binder.class) .expect(unit -> { MetricRegistry registry = unit.mock(MetricRegistry.class); unit.registerMock(MetricRegistry.class, registry); }) .expect(unit -> { HealthCheckRegistry registry = unit.constructor(HealthCheckRegistry.class) .build(); unit.registerMock(HealthCheckRegistry.class, registry); }) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(multibinderStatic) .expect(routes) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { MetricRegistry registry = unit.get(MetricRegistry.class); new Metrics(registry) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @Test public void basicWithExtHealthCheckRegistry() throws Exception { new MockUnit(Env.class, Config.class, Binder.class) .expect(newMetricRegistry) .expect(unit -> { HealthCheckRegistry registry = unit.mock(HealthCheckRegistry.class); unit.registerMock(HealthCheckRegistry.class, registry); }) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(multibinderStatic) .expect(routes) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { HealthCheckRegistry registry = unit.get(HealthCheckRegistry.class); new Metrics(registry) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @Test public void request() throws Exception { new MockUnit(Env.class, Config.class, Binder.class) .expect(newMetricRegistry) .expect(newHealthCheckRegistry) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(multibinderStatic) .expect(unit -> { Router routes = unit.mock(Router.class); Env env = unit.get(Env.class); expect(env.router()).andReturn(routes); MetricHandler handler = unit.constructor(MetricHandler.class).build(); route(unit, routes, "/sys/metrics", handler); route(unit, routes, "/sys/metrics/:type", handler); route(unit, routes, "/sys/healthcheck", unit.constructor(HealthCheckHandler.class).build()); route(unit, routes, "*", unit.constructor(InstrumentedHandler.class).build()); }) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { Metrics metrics = new Metrics().request(); metrics.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @Test public void ping() throws Exception { new MockUnit(Env.class, Config.class, Binder.class) .expect(newMetricRegistry) .expect(newHealthCheckRegistry) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(multibinderStatic) .expect(routes) .expect(unit -> { Router routes = unit.get(Router.class); route(unit, routes, "/sys/ping", unit.constructor(PingHandler.class).build()); }) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { Metrics metrics = new Metrics().ping(); metrics.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @Test public void threadDump() throws Exception { new MockUnit(Env.class, Config.class, Binder.class) .expect(newMetricRegistry) .expect(newHealthCheckRegistry) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(multibinderStatic) .expect(routes) .expect(unit -> { Router routes = unit.get(Router.class); route(unit, routes, "/sys/thread-dump", unit.constructor(ThreadDumpHandler.class).build()); }) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { Metrics metrics = new Metrics().threadDump(); metrics.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void metricInstance() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, Metric.class) .expect(newMetricRegistry) .expect(newHealthCheckRegistry) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(Metric.class, (unit, binder) -> { LinkedBindingBuilder<Metric> mLBB = unit.mock(LinkedBindingBuilder.class); mLBB.toInstance(unit.get(Metric.class)); expect(binder.addBinding("m")).andReturn(mLBB); })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(multibinderStatic) .expect(routes) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { new Metrics() .metric("m", unit.get(Metric.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void metricRef() throws Exception { new MockUnit(Env.class, Config.class, Binder.class) .expect(newMetricRegistry) .expect(newHealthCheckRegistry) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(Metric.class, (unit, binder) -> { LinkedBindingBuilder<Metric> mLBB = unit.mock(LinkedBindingBuilder.class); expect(mLBB.to(Meter.class)).andReturn(null); expect(binder.addBinding("m")).andReturn(mLBB); })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(multibinderStatic) .expect(routes) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { new Metrics() .metric("m", Meter.class) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void healthCheck() throws Exception { new MockUnit(Env.class, Config.class, Binder.class, HealthCheck.class) .expect(newMetricRegistry) .expect(newHealthCheckRegistry) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { LinkedBindingBuilder<HealthCheck> mLBB = unit.mock(LinkedBindingBuilder.class); mLBB.toInstance(unit.get(HealthCheck.class)); expect(binder.addBinding("h")).andReturn(mLBB); })) .expect(multibinderStatic) .expect(routes) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { new Metrics() .healthCheck("h", unit.get(HealthCheck.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void healthRef() throws Exception { new MockUnit(Env.class, Config.class, Binder.class) .expect(newMetricRegistry) .expect(newHealthCheckRegistry) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { LinkedBindingBuilder<HealthCheck> mLBB = unit.mock(LinkedBindingBuilder.class); expect(mLBB.to(HealthCheck.class)).andReturn(null); expect(binder.addBinding("h")).andReturn(mLBB); })) .expect(multibinderStatic) .expect(routes) .expect(setbinder(Reporter.class, (unit, binder) -> { })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { new Metrics() .healthCheck("h", HealthCheck.class) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void reporter() throws Exception { new MockUnit(Env.class, Config.class, Binder.class) .expect(newMetricRegistry) .expect(newHealthCheckRegistry) .expect(mapBinderStatic) .expect(mapbinder(Metric.class, (unit, binder) -> { })) .expect(mapbinder(HealthCheck.class, (unit, binder) -> { })) .expect(multibinderStatic) .expect(routes) .expect(setbinder(Reporter.class, (unit, binder) -> { LinkedBindingBuilder<Reporter> rLBB = unit.mock(LinkedBindingBuilder.class); rLBB.toInstance(isA(ConsoleReporter.class)); expect(binder.addBinding()).andReturn(rLBB); })) .expect(bindMetricRegistry) .expect(bindMetricRegistryInitializer) .expect(bindHealthCheckRegistry) .expect(bindHealthCheckRegistryInitializer) .expect(onStop) .run(unit -> { new Metrics() .reporter(r -> { return ConsoleReporter.forRegistry(r).build(); }) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } private void route(final MockUnit unit, final Router route, final String pattern, final Route.Handler handler) throws Exception { expect(route.use("GET", pattern, handler)).andReturn(null); } private void route(final MockUnit unit, final Router route, final String pattern, final Route.Filter handler) throws Exception { expect(route.use("GET", pattern, handler)).andReturn(null); } @SuppressWarnings("unchecked") private <T> Block mapbinder(final Class<T> type, final BiConsumer<MockUnit, MapBinder<String, T>> callback) { return unit -> { Binder binder = unit.get(Binder.class); MapBinder<String, T> m = unit.mock(MapBinder.class); expect(MapBinder.newMapBinder(binder, String.class, type)).andReturn(m); callback.accept(unit, m); }; } @SuppressWarnings("unchecked") private <T> Block setbinder(final Class<T> type, final BiConsumer<MockUnit, Multibinder<T>> callback) { return unit -> { Binder binder = unit.get(Binder.class); Multibinder<T> m = unit.mock(Multibinder.class); expect(Multibinder.newSetBinder(binder, type)).andReturn(m); callback.accept(unit, m); }; } }