package org.jooby.metrics; import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import java.util.ArrayList; import java.util.Map; import java.util.Optional; import java.util.SortedMap; import java.util.TreeMap; import org.jooby.Mutant; import org.jooby.Request; import org.jooby.Response; import org.jooby.Status; import org.jooby.test.MockUnit; import org.jooby.test.MockUnit.Block; import org.junit.Test; import com.codahale.metrics.Counter; import com.codahale.metrics.Gauge; import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.Metric; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import com.codahale.metrics.UniformReservoir; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.Lists; public class MetricHandlerTest { @Test public void notImplemented() throws Exception { SortedMap<String, Metric> metrics = ImmutableSortedMap.of(); new MockUnit(Request.class, Response.class, MetricRegistry.class) .expect(registry(metrics)) .expect(send(Status.NOT_IMPLEMENTED, metrics)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } @Test public void counters() throws Exception { MetricRegistry registry = new MetricRegistry(); registry.register("c", new Counter()); // result Map<String, Object> result = new TreeMap<>(); result.put("counters", ImmutableMap.of("c", 0L)); new MockUnit(Request.class, Response.class) .expect(registry(registry)) .expect(name("name", Optional.empty())) .expect(param("type", "*")) .expect(param("unit", "seconds", "seconds")) .expect(bparam("showSamples", false)) .expect(send(Status.OK, result)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } @Test public void metricByType() throws Exception { MetricRegistry registry = new MetricRegistry(); registry.register("c1", new Counter()); registry.register("c2", new Counter()); // result Map<String, Object> result = new TreeMap<>(); result.put("c1", 0L); result.put("c2", 0L); new MockUnit(Request.class, Response.class) .expect(registry(registry)) .expect(name("name", Optional.empty())) .expect(param("type", "counters")) .expect(param("unit", "seconds", "seconds")) .expect(bparam("showSamples", false)) .expect(send(Status.OK, result)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } @Test public void metricByName() throws Exception { MetricRegistry registry = new MetricRegistry(); registry.register("c1", new Counter()); registry.register("c2", new Counter()); // result Map<String, Object> result = new TreeMap<>(); result.put("c1", 0L); new MockUnit(Request.class, Response.class) .expect(registry(registry)) .expect(name("name", Optional.of("c1"))) .expect(param("type", "counters")) .expect(param("unit", "seconds", "seconds")) .expect(bparam("showSamples", false)) .expect(send(Status.OK, result)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } @Test public void meters() throws Exception { MetricRegistry registry = new MetricRegistry(); Meter meter = new Meter(); registry.register("m", meter); // result Map<String, Object> result = new TreeMap<>(); result.put("meters", ImmutableMap.of("m", ImmutableMap.builder() .put("count", 0L) .put("duration_units", "seconds") .put("m15_rate", 0D) .put("m1_rate", 0D) .put("m5_rate", 0D) .put("mean_rate", 0D) .put("rate_units", "ops/second") .build())); new MockUnit(Request.class, Response.class) .expect(registry(registry)) .expect(name("name", Optional.empty())) .expect(param("type", "*")) .expect(param("unit", "seconds", "seconds")) .expect(bparam("showSamples", false)) .expect(send(Status.OK, result)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } @Test public void metersByUnit() throws Exception { MetricRegistry registry = new MetricRegistry(); Meter meter = new Meter(); registry.register("m", meter); // result Map<String, Object> result = new TreeMap<>(); result.put("meters", ImmutableMap.of("m", ImmutableMap.builder() .put("count", 0L) .put("duration_units", "milliseconds") .put("m15_rate", 0D) .put("m1_rate", 0D) .put("m5_rate", 0D) .put("mean_rate", 0D) .put("rate_units", "ops/millisecond") .build())); new MockUnit(Request.class, Response.class) .expect(registry(registry)) .expect(name("name", Optional.empty())) .expect(param("type", "*")) .expect(param("unit", "seconds", "milliseconds")) .expect(bparam("showSamples", false)) .expect(send(Status.OK, result)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } @Test public void timers() throws Exception { MetricRegistry registry = new MetricRegistry(); Timer meter = new Timer(); registry.register("t", meter); // result Map<String, Object> result = new TreeMap<>(); result.put("timers", ImmutableMap.of("t", ImmutableMap.builder() .put("count", 0L) .put("duration_units", "seconds") .put("m15_rate", 0D) .put("m1_rate", 0D) .put("m5_rate", 0D) .put("mean_rate", 0D) .put("rate_units", "ops/second") .put("max", 0D) .put("mean", 0D) .put("min", 0D) .put("p50", 0D) .put("p75", 0D) .put("p95", 0D) .put("p98", 0D) .put("p99", 0D) .put("p999", 0D) .put("values", new ArrayList<>()) .build())); new MockUnit(Request.class, Response.class) .expect(registry(registry)) .expect(name("name", Optional.empty())) .expect(param("type", "*")) .expect(param("unit", "seconds", "seconds")) .expect(bparam("showSamples", true)) .expect(send(Status.OK, result)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } @Test public void histograms() throws Exception { MetricRegistry registry = new MetricRegistry(); Histogram h = new Histogram(new UniformReservoir()); registry.register("h", h); h.update(7); // result Map<String, Object> result = new TreeMap<>(); result.put("histograms", ImmutableMap.of("h", ImmutableMap.builder() .put("max", 7D) .put("mean", 7D) .put("min", 7D) .put("p50", 7D) .put("p75", 7D) .put("p95", 7D) .put("p98", 7D) .put("p99", 7D) .put("p999", 7D) .put("values", Lists.newArrayList(7D)) .build())); new MockUnit(Request.class, Response.class) .expect(registry(registry)) .expect(name("name", Optional.empty())) .expect(param("type", "*")) .expect(param("unit", "seconds", "seconds")) .expect(bparam("showSamples", true)) .expect(send(Status.OK, result)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } @Test public void gauges() throws Exception { MetricRegistry registry = new MetricRegistry(); registry.register("g", new Gauge<Object>() { @Override public Object getValue() { return "v"; } }); // result Map<String, Object> result = new TreeMap<>(); result.put("gauges", ImmutableMap.of("g", "v")); new MockUnit(Request.class, Response.class) .expect(registry(registry)) .expect(name("name", Optional.empty())) .expect(param("type", "*")) .expect(param("unit", "seconds", "seconds")) .expect(bparam("showSamples", false)) .expect(send(Status.OK, result)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } @Test public void gaugesErr() throws Exception { MetricRegistry registry = new MetricRegistry(); IllegalStateException v = new IllegalStateException("intentional err"); registry.register("g", new Gauge<Object>() { @Override public Object getValue() { throw v; } }); // result Map<String, Object> result = new TreeMap<>(); result.put("gauges", ImmutableMap.of("g", v.toString())); new MockUnit(Request.class, Response.class) .expect(registry(registry)) .expect(name("name", Optional.empty())) .expect(param("type", "*")) .expect(param("unit", "seconds", "seconds")) .expect(bparam("showSamples", false)) .expect(send(Status.OK, result)) .run(unit -> { new MetricHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); } private Block param(final String name, final String value) { return param(name, "*", value); } private Block param(final String name, final String defvalue, final String value) { return unit -> { Mutant mvalue = unit.mock(Mutant.class); expect(mvalue.value(defvalue)).andReturn(value); Request req = unit.get(Request.class); expect(req.param(name)).andReturn(mvalue); }; } private Block name(final String name, final Optional<String> value) { return unit -> { Mutant mvalue = unit.mock(Mutant.class); expect(mvalue.toOptional()).andReturn(value); Request req = unit.get(Request.class); expect(req.param(name)).andReturn(mvalue); }; } private Block bparam(final String name, final boolean value) { return unit -> { Mutant mvalue = unit.mock(Mutant.class); expect(mvalue.booleanValue(false)).andReturn(value); Request req = unit.get(Request.class); expect(req.param(name)).andReturn(mvalue); }; } private Block registry(final MetricRegistry registry) { return unit -> { Request req = unit.get(Request.class); expect(req.require(MetricRegistry.class)).andReturn(registry); }; } private Block send(final Status status, final Object metrics) { return unit -> { Response rsp = unit.get(Response.class); expect(rsp.status(eq(status))).andReturn(rsp); expect(rsp.header("Cache-Control", "must-revalidate,no-cache,no-store")).andReturn(rsp); rsp.send(eq(metrics)); }; } private Block registry(final SortedMap<String, Metric> metrics) { return unit -> { MetricRegistry registry = unit.get(MetricRegistry.class); expect(registry.getMetrics()).andReturn(metrics); Request req = unit.get(Request.class); expect(req.require(MetricRegistry.class)).andReturn(registry); }; } }