diff --git a/java/google/registry/monitoring/metrics/contrib/AbstractMetricSubject.java b/java/google/registry/monitoring/metrics/contrib/AbstractMetricSubject.java index d54d53539..899d0ba02 100644 --- a/java/google/registry/monitoring/metrics/contrib/AbstractMetricSubject.java +++ b/java/google/registry/monitoring/metrics/contrib/AbstractMetricSubject.java @@ -107,7 +107,7 @@ abstract class AbstractMetricSubject> } if (!metricPoint.value().equals(value)) { failWithBadResults( - String.format("has a value of %s for labels", value), + String.format("has a value of %s for labels", getMessageRepresentation(value)), Joiner.on(':').join(labels), "has a value of", getMessageRepresentation(metricPoint.value())); diff --git a/java/google/registry/monitoring/metrics/contrib/DistributionMetricSubject.java b/java/google/registry/monitoring/metrics/contrib/DistributionMetricSubject.java index 95609f111..2c03ac5be 100644 --- a/java/google/registry/monitoring/metrics/contrib/DistributionMetricSubject.java +++ b/java/google/registry/monitoring/metrics/contrib/DistributionMetricSubject.java @@ -16,12 +16,17 @@ package google.registry.monitoring.metrics.contrib; import static com.google.common.truth.Truth.assertAbout; +import com.google.common.base.Joiner; import com.google.common.collect.BoundType; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Range; import com.google.common.truth.FailureMetadata; import google.registry.monitoring.metrics.Distribution; +import google.registry.monitoring.metrics.ImmutableDistribution; import google.registry.monitoring.metrics.Metric; import google.registry.monitoring.metrics.MetricPoint; +import google.registry.monitoring.metrics.MutableDistribution; import java.util.Map; import javax.annotation.Nullable; @@ -36,6 +41,8 @@ import javax.annotation.Nullable; * .hasNoOtherValues(); * assertThat(myDistributionMetric) * .doesNotHaveAnyValueForLabels("label1", "label2"); + * assertThat(myDistributionMetric) + * .hasDataSetForLabels(ImmutableSet.of(data1, data2, data3), "label1", "label2"); * * *

The assertions treat an empty distribution as no value at all. This is not how the data is @@ -94,4 +101,25 @@ public final class DistributionMetricSubject sb.append('}'); return sb.toString(); } + + /** + * Asserts that the distribution for the given label can be constructed from the given data set. + * + *

Note that this only tests that the distribution has the same binned histogram as it would if + * it had recorded the specified data points. It could have in fact collected different data + * points that resulted in the same histogram, but that information is lost to us and cannot be + * tested. + */ + public And hasDataSetForLabels( + ImmutableSet dataSet, String... labels) { + ImmutableList> metricPoints = actual().getTimestampedValues(); + if (metricPoints.isEmpty()) { + failWithBadResults( + "has a distribution for labels", Joiner.on(':').join(labels), "has", "no values"); + } + MutableDistribution targetDistribution = + new MutableDistribution(metricPoints.get(0).value().distributionFitter()); + dataSet.forEach(data -> targetDistribution.add(data.doubleValue())); + return hasValueForLabels(ImmutableDistribution.copyOf(targetDistribution), labels); + } } diff --git a/javatests/google/registry/monitoring/metrics/contrib/BUILD b/javatests/google/registry/monitoring/metrics/contrib/BUILD index 6e1299f85..813687ed0 100644 --- a/javatests/google/registry/monitoring/metrics/contrib/BUILD +++ b/javatests/google/registry/monitoring/metrics/contrib/BUILD @@ -13,6 +13,7 @@ java_library( deps = [ "//java/google/registry/monitoring/metrics", "//java/google/registry/monitoring/metrics/contrib", + "//javatests/google/registry/testing", "@com_google_guava", "@com_google_truth", "@com_google_truth_extensions_truth_java8_extension", diff --git a/javatests/google/registry/monitoring/metrics/contrib/DistributionMetricSubjectTest.java b/javatests/google/registry/monitoring/metrics/contrib/DistributionMetricSubjectTest.java index 21fef1cd1..832415691 100644 --- a/javatests/google/registry/monitoring/metrics/contrib/DistributionMetricSubjectTest.java +++ b/javatests/google/registry/monitoring/metrics/contrib/DistributionMetricSubjectTest.java @@ -15,9 +15,8 @@ package google.registry.monitoring.metrics.contrib; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static google.registry.monitoring.metrics.contrib.DistributionMetricSubject.assertThat; -import static org.junit.Assert.fail; +import static google.registry.testing.JUnitBackports.expectThrows; import com.google.common.collect.ImmutableSet; import google.registry.monitoring.metrics.EventMetric; @@ -54,17 +53,15 @@ public class DistributionMetricSubjectTest { @Test public void testWrongNumberOfLabels_fails() { - try { - assertThat(metric).hasAnyValueForLabels("Domestic"); - fail("Expected assertion error"); - } catch (AssertionError e) { - assertThat(e) - .hasMessageThat() - .isEqualTo( - "Not true that has a value for labels ." - + " It has labeled values <[Bighorn:Blue =>" - + " {[4.0..16.0)=1}, Domestic:Green => {[1.0..4.0)=1}]>"); - } + AssertionError e = + expectThrows( + AssertionError.class, () -> assertThat(metric).hasAnyValueForLabels("Domestic")); + assertThat(e) + .hasMessageThat() + .isEqualTo( + "Not true that has a value for labels ." + + " It has labeled values <[Bighorn:Blue =>" + + " {[4.0..16.0)=1}, Domestic:Green => {[1.0..4.0)=1}]>"); } @Test @@ -89,33 +86,104 @@ public class DistributionMetricSubjectTest { @Test public void testDoesNotHaveValueForLabels_failure() { - try { - assertThat(metric).doesNotHaveAnyValueForLabels("Domestic", "Green"); - fail("Expected assertion error"); - } catch (AssertionError e) { - assertThat(e) - .hasMessageThat() - .isEqualTo( - "Not true that has no value for labels ." - + " It has a value of <{[1.0..4.0)=1}>"); - } + AssertionError e = + expectThrows( + AssertionError.class, + () -> assertThat(metric).doesNotHaveAnyValueForLabels("Domestic", "Green")); + assertThat(e) + .hasMessageThat() + .isEqualTo( + "Not true that has no value for labels ." + + " It has a value of <{[1.0..4.0)=1}>"); } @Test public void testUnexpectedValue_failure() { - try { - assertThat(metric) - .hasAnyValueForLabels("Domestic", "Green") - .and() - .hasNoOtherValues(); - fail("Expected assertion error"); - } catch (AssertionError e) { - assertThat(e) - .hasMessageThat() - .isEqualTo( - "Not true that has ." - + " It has labeled values <[Bighorn:Blue =>" - + " {[4.0..16.0)=1}, Domestic:Green => {[1.0..4.0)=1}]>"); - } + AssertionError e = + expectThrows( + AssertionError.class, + () -> + assertThat(metric) + .hasAnyValueForLabels("Domestic", "Green") + .and() + .hasNoOtherValues()); + assertThat(e) + .hasMessageThat() + .isEqualTo( + "Not true that has ." + + " It has labeled values <[Bighorn:Blue =>" + + " {[4.0..16.0)=1}, Domestic:Green => {[1.0..4.0)=1}]>"); + } + + @Test + public void testExpectedDataSet_success() { + metric.record(7.5, "Domestic", "Green"); + assertThat(metric).hasDataSetForLabels(ImmutableSet.of(2.5, 7.5), "Domestic", "Green"); + } + + @Test + public void testExpectedDataSetsChained_success() { + metric.record(7.5, "Domestic", "Green"); + assertThat(metric) + .hasDataSetForLabels(ImmutableSet.of(2.5, 7.5), "Domestic", "Green") + .and() + .hasDataSetForLabels(ImmutableSet.of(10), "Bighorn", "Blue") + .and() + .hasNoOtherValues(); + } + + @Test + public void testUnexpectedDataSet_failure() { + AssertionError e = + expectThrows( + AssertionError.class, + () -> + assertThat(metric) + .hasDataSetForLabels(ImmutableSet.of(2.5, 7.5), "Domestic", "Green")); + assertThat(e) + .hasMessageThat() + .isEqualTo( + "Not true that has a value of" + + " {[1.0..4.0)=1,[4.0..16.0)=1} for labels ." + + " It has a value of <{[1.0..4.0)=1}>"); + } + + @Test + public void testNonExistentLabels_failure() { + AssertionError e = + expectThrows( + AssertionError.class, + () -> + assertThat(metric) + .hasDataSetForLabels(ImmutableSet.of(2.5, 7.5), "Domestic", "Blue")); + assertThat(e) + .hasMessageThat() + .isEqualTo( + "Not true that has a value for labels ." + + " It has labeled values <[Bighorn:Blue => {[4.0..16.0)=1}," + + " Domestic:Green => {[1.0..4.0)=1}]>"); + } + + @Test + public void testEmptyMetric_failure() { + EventMetric emptyMetric = + MetricRegistryImpl.getDefault() + .newEventMetric( + "/test/event/goat", + "Sheep Latency", + "sheeplatency", + LABEL_DESCRIPTORS, + EventMetric.DEFAULT_FITTER); + AssertionError e = + expectThrows( + AssertionError.class, + () -> + assertThat(emptyMetric) + .hasDataSetForLabels(ImmutableSet.of(2.5, 7.5), "Domestic", "Blue")); + assertThat(e) + .hasMessageThat() + .isEqualTo( + "Not true that has a distribution for labels ." + + " It has "); } }