Move gauge assertions into stable testing artifact. (#4395)

* Move gauge assertions into stable testing artifact.

* Disable publishing of old metrics-testing
This commit is contained in:
Anuraag Agrawal 2022-04-21 11:31:15 +09:00 committed by GitHub
parent 98369a5aad
commit f464817013
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1218 additions and 41 deletions

View File

@ -1,2 +1,59 @@
Comparing source compatibility of against
No changes.
+++ NEW CLASS: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasAttribute(io.opentelemetry.api.common.AttributeKey, java.lang.Object)
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasAttribute(io.opentelemetry.sdk.testing.assertj.AttributeAssertion)
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasAttributes(io.opentelemetry.api.common.Attributes)
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasAttributes(java.util.Map$Entry[])
+++ NEW ANNOTATION: java.lang.SafeVarargs
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasAttributesSatisfying(io.opentelemetry.sdk.testing.assertj.AttributeAssertion[])
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasAttributesSatisfying(java.lang.Iterable)
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasEpochNanos(long)
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasExemplars(io.opentelemetry.sdk.metrics.data.ExemplarData[])
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasExemplarsSatisfying(java.util.function.Consumer[])
+++ NEW ANNOTATION: java.lang.SafeVarargs
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasExemplarsSatisfying(java.lang.Iterable)
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert hasStartEpochNanos(long)
+++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.DoubleGaugeAssert (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.DoubleGaugeAssert hasPointsSatisfying(java.util.function.Consumer[])
+++ NEW ANNOTATION: java.lang.SafeVarargs
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.DoubleGaugeAssert hasPointsSatisfying(java.lang.Iterable)
+++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.DoublePointDataAssert (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW SUPERCLASS: io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.DoublePointDataAssert hasValue(double)
+++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasEpochNanos(long)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasFilteredAttribute(io.opentelemetry.api.common.AttributeKey, java.lang.Object)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasFilteredAttribute(io.opentelemetry.sdk.testing.assertj.AttributeAssertion)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasFilteredAttributes(io.opentelemetry.api.common.Attributes)
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasFilteredAttributes(java.util.Map$Entry[])
+++ NEW ANNOTATION: java.lang.SafeVarargs
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasFilteredAttributesSatisfying(io.opentelemetry.sdk.testing.assertj.AttributeAssertion[])
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasFilteredAttributesSatisfying(java.lang.Iterable)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasSpanId(java.lang.String)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasTraceId(java.lang.String)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.ExemplarDataAssert hasValue(double)
+++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.LongGaugeAssert (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW METHOD: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.LongGaugeAssert hasPointsSatisfying(java.util.function.Consumer[])
+++ NEW ANNOTATION: java.lang.SafeVarargs
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.LongGaugeAssert hasPointsSatisfying(java.lang.Iterable)
+++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.LongPointDataAssert (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW SUPERCLASS: io.opentelemetry.sdk.testing.assertj.AbstractPointDataAssert
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.LongPointDataAssert hasValue(long)
+++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.testing.assertj.MetricDataAssert (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.MetricDataAssert hasDescription(java.lang.String)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.MetricDataAssert hasDoubleGaugeSatisfying(java.util.function.Consumer)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.MetricDataAssert hasInstrumentationScope(io.opentelemetry.sdk.common.InstrumentationScopeInfo)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.MetricDataAssert hasLongGaugeSatisfying(java.util.function.Consumer)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.MetricDataAssert hasName(java.lang.String)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.MetricDataAssert hasResource(io.opentelemetry.sdk.resources.Resource)
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.MetricDataAssert hasUnit(java.lang.String)
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.testing.assertj.MetricDataAssert assertThat(io.opentelemetry.sdk.metrics.data.MetricData)

View File

@ -1,6 +1,5 @@
plugins {
id("otel.java-conventions")
id("otel.publish-conventions")
}
description = "OpenTelemetry Metrics SDK Testing utilities"

View File

@ -0,0 +1,137 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.metrics.data.ExemplarData;
import io.opentelemetry.sdk.metrics.data.PointData;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
/** Assertions for an exported {@link PointData}. */
public abstract class AbstractPointDataAssert<
PointAssertT extends AbstractPointDataAssert<PointAssertT, PointT>,
PointT extends PointData>
extends AbstractAssert<PointAssertT, PointT> {
AbstractPointDataAssert(@Nullable PointT actual, Class<PointAssertT> assertClass) {
super(actual, assertClass);
}
/** Asserts the point has the given start epoch timestamp, in nanos. */
public final PointAssertT hasStartEpochNanos(long expected) {
isNotNull();
Assertions.assertThat(actual.getStartEpochNanos()).as("startEpochNanos").isEqualTo(expected);
return myself;
}
/** Asserts the point has the given epoch timestamp, in nanos. */
public final PointAssertT hasEpochNanos(long expected) {
isNotNull();
Assertions.assertThat(actual.getEpochNanos()).as("epochNanos").isEqualTo(expected);
return myself;
}
/** Asserts the point has the given attribute. */
public final <T> PointAssertT hasAttribute(AttributeKey<T> key, T value) {
return hasAttribute(OpenTelemetryAssertions.equalTo(key, value));
}
/** Asserts the point has an attribute matching the {@code attributeAssertion}. */
public final PointAssertT hasAttribute(AttributeAssertion attributeAssertion) {
isNotNull();
Set<AttributeKey<?>> actualKeys = actual.getAttributes().asMap().keySet();
AttributeKey<?> key = attributeAssertion.getKey();
assertThat(actualKeys).as("attribute keys").contains(key);
Object value = actual.getAttributes().get(key);
AbstractAssert<?, ?> assertion = AttributeAssertion.attributeValueAssertion(key, value);
attributeAssertion.getAssertion().accept(assertion);
return myself;
}
/** Asserts the point has the given attributes. */
public final PointAssertT hasAttributes(Attributes attributes) {
isNotNull();
if (!AssertUtil.attributesAreEqual(actual.getAttributes(), attributes)) {
failWithActualExpectedAndMessage(
actual.getAttributes(),
attributes,
"Expected point to have attributes <%s> but was <%s>",
attributes,
actual.getAttributes());
}
return myself;
}
/** Asserts the point has the given attributes. */
@SuppressWarnings({"rawtypes", "unchecked"})
@SafeVarargs
public final PointAssertT hasAttributes(Map.Entry<? extends AttributeKey<?>, ?>... entries) {
AttributesBuilder attributesBuilder = Attributes.builder();
for (Map.Entry<? extends AttributeKey<?>, ?> attr : entries) {
attributesBuilder.put((AttributeKey) attr.getKey(), attr.getValue());
}
Attributes attributes = attributesBuilder.build();
return hasAttributes(attributes);
}
/**
* Asserts the point has attributes matching all {@code assertions} and no more. Assertions can be
* created using methods like {@link OpenTelemetryAssertions#satisfies(AttributeKey,
* OpenTelemetryAssertions.LongAssertConsumer)}.
*/
public final PointAssertT hasAttributesSatisfying(AttributeAssertion... assertions) {
return hasAttributesSatisfying(Arrays.asList(assertions));
}
/**
* Asserts the point has attributes matching all {@code assertions} and no more. Assertions can be
* created using methods like {@link OpenTelemetryAssertions#satisfies(AttributeKey,
* OpenTelemetryAssertions.LongAssertConsumer)}.
*/
public final PointAssertT hasAttributesSatisfying(Iterable<AttributeAssertion> assertions) {
AssertUtil.assertAttributes(actual.getAttributes(), assertions);
return myself;
}
/** Asserts the point has the specified exemplars, in any order. */
public final PointAssertT hasExemplars(ExemplarData... exemplars) {
isNotNull();
Assertions.assertThat(actual.getExemplars())
.as("exemplars")
.containsExactlyInAnyOrder(exemplars);
return myself;
}
/** Asserts the point has exemplars matching all of the assertions, in any order. */
@SafeVarargs
@SuppressWarnings("varargs")
public final PointAssertT hasExemplarsSatisfying(Consumer<ExemplarDataAssert>... assertions) {
return hasExemplarsSatisfying(Arrays.asList(assertions));
}
/** Asserts the point has exemplars matching all of the assertions, in any order. */
public final PointAssertT hasExemplarsSatisfying(
Iterable<? extends Consumer<ExemplarDataAssert>> assertions) {
isNotNull();
assertThat(actual.getExemplars())
.satisfiesExactlyInAnyOrder(AssertUtil.toConsumers(assertions, ExemplarDataAssert::new));
return myself;
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import org.assertj.core.api.AbstractAssert;
final class AssertUtil {
/**
* Converts from consumers of our assertions provided by the user to consumers of the data for use
* with satisfiesExactlyInAnyOrder.
*/
static <T, U extends AbstractAssert<U, T>> Consumer<T>[] toConsumers(
Iterable<? extends Consumer<U>> assertions, Function<T, U> assertionFactory) {
Stream.Builder<Consumer<T>> builder = Stream.builder();
for (Consumer<U> assertion : assertions) {
builder.add(item -> assertion.accept(assertionFactory.apply(item)));
}
@SuppressWarnings({"rawtypes", "unchecked"})
Consumer<T>[] consumers = builder.build().toArray(Consumer[]::new);
return consumers;
}
static void assertAttributes(Attributes actual, Iterable<AttributeAssertion> assertions) {
Set<AttributeKey<?>> actualKeys = actual.asMap().keySet();
Set<AttributeKey<?>> checkedKeys = new HashSet<>();
for (AttributeAssertion attributeAssertion : assertions) {
AttributeKey<?> key = attributeAssertion.getKey();
Object value = actual.get(key);
if (value != null) {
checkedKeys.add(key);
}
AbstractAssert<?, ?> assertion = AttributeAssertion.attributeValueAssertion(key, value);
attributeAssertion.getAssertion().accept(assertion);
}
assertThat(actualKeys).as("attribute keys").containsExactlyInAnyOrderElementsOf(checkedKeys);
}
/**
* Compares {@link Attributes} as maps since currently attributes cannot be compared across
* implementations.
*/
static boolean attributesAreEqual(Attributes actual, Attributes other) {
return actual.asMap().equals(other.asMap());
}
private AssertUtil() {}
}

View File

@ -5,9 +5,13 @@
package io.opentelemetry.sdk.testing.assertj;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.auto.value.AutoValue;
import io.opentelemetry.api.common.AttributeKey;
import java.util.List;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.assertj.core.api.AbstractAssert;
/** An assertion on an attribute key. */
@ -15,8 +19,7 @@ import org.assertj.core.api.AbstractAssert;
public abstract class AttributeAssertion {
// This method is not type-safe! But because the constructor is private, we know it will only be
// created through
// our factories, which are type-safe.
// created through our factories, which are type-safe.
@SuppressWarnings("unchecked")
static AttributeAssertion create(
AttributeKey<?> key, Consumer<? extends AbstractAssert<?, ?>> assertion) {
@ -27,5 +30,30 @@ public abstract class AttributeAssertion {
abstract Consumer<AbstractAssert<?, ?>> getAssertion();
// The return type of these assertions must match the parameters in methods like
// OpenTelemetryAssertions.satisfies.
// Our code is nullness annotated but assertj is not. NullAway seems to still treat the base class
// of OpenTelemetryAssertions as annotated though, so there seems to be no way to avoid
// suppressing here.
@SuppressWarnings("NullAway")
static AbstractAssert<?, ?> attributeValueAssertion(AttributeKey<?> key, @Nullable Object value) {
switch (key.getType()) {
case STRING:
return assertThat((String) value);
case BOOLEAN:
return assertThat((Boolean) value);
case LONG:
return assertThat((Long) value);
case DOUBLE:
return assertThat((Double) value);
case STRING_ARRAY:
case BOOLEAN_ARRAY:
case LONG_ARRAY:
case DOUBLE_ARRAY:
return assertThat((List<?>) value);
}
throw new IllegalArgumentException("Unknown type for key " + key);
}
AttributeAssertion() {}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.sdk.metrics.data.DoublePointData;
import io.opentelemetry.sdk.metrics.data.GaugeData;
import java.util.Arrays;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.assertj.core.api.AbstractAssert;
/** Assertions for an exported double {@link GaugeData}. */
public final class DoubleGaugeAssert
extends AbstractAssert<DoubleGaugeAssert, GaugeData<DoublePointData>> {
DoubleGaugeAssert(@Nullable GaugeData<DoublePointData> actual) {
super(actual, DoubleGaugeAssert.class);
}
/**
* Asserts the gauge has points matching all of the given assertions and no more, in any order.
*/
@SafeVarargs
@SuppressWarnings("varargs")
public final DoubleGaugeAssert hasPointsSatisfying(
Consumer<DoublePointDataAssert>... assertions) {
return hasPointsSatisfying(Arrays.asList(assertions));
}
/**
* Asserts the gauge has points matching all of the given assertions and no more, in any order.
*/
public DoubleGaugeAssert hasPointsSatisfying(
Iterable<? extends Consumer<DoublePointDataAssert>> assertions) {
isNotNull();
assertThat(actual.getPoints())
.satisfiesExactlyInAnyOrder(AssertUtil.toConsumers(assertions, DoublePointDataAssert::new));
return this;
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj;
import io.opentelemetry.sdk.metrics.data.DoublePointData;
import javax.annotation.Nullable;
import org.assertj.core.api.Assertions;
/** Test assertions for {@link DoublePointData}. */
public final class DoublePointDataAssert
extends AbstractPointDataAssert<DoublePointDataAssert, DoublePointData> {
DoublePointDataAssert(@Nullable DoublePointData actual) {
super(actual, DoublePointDataAssert.class);
}
/** Asserts the point has the given value. */
public DoublePointDataAssert hasValue(double expected) {
isNotNull();
Assertions.assertThat(actual.getValue()).as("value").isEqualTo(expected);
return this;
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.metrics.data.DoubleExemplarData;
import io.opentelemetry.sdk.metrics.data.ExemplarData;
import io.opentelemetry.sdk.metrics.data.LongExemplarData;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import org.assertj.core.api.AbstractAssert;
/** Assertions for an exported {@link ExemplarData}. */
public final class ExemplarDataAssert extends AbstractAssert<ExemplarDataAssert, ExemplarData> {
ExemplarDataAssert(@Nullable ExemplarData actual) {
super(actual, ExemplarDataAssert.class);
}
/** Asserts the exemplar has the given epoch timestamp, in nanos. */
public ExemplarDataAssert hasEpochNanos(long expected) {
isNotNull();
assertThat(actual.getEpochNanos()).as("epochNanos").isEqualTo(expected);
return this;
}
/** Asserts the exemplar has the given span ID. */
public ExemplarDataAssert hasSpanId(String expected) {
isNotNull();
assertThat(actual.getSpanContext().getSpanId()).as("spanId").isEqualTo(expected);
return this;
}
/** Asserts the exemplar has the given trace ID. */
public ExemplarDataAssert hasTraceId(String expected) {
isNotNull();
assertThat(actual.getSpanContext().getTraceId()).as("traceId").isEqualTo(expected);
return this;
}
/** Asserts the exemplar has the given value. */
public ExemplarDataAssert hasValue(double expected) {
isNotNull();
double value =
actual instanceof DoubleExemplarData
? ((DoubleExemplarData) actual).getValue()
: ((LongExemplarData) actual).getValue();
assertThat(value).as("value").isEqualTo(expected);
return this;
}
/** Asserts the exemplar has the given filtered attribute. */
public <T> ExemplarDataAssert hasFilteredAttribute(AttributeKey<T> key, T value) {
return hasFilteredAttribute(OpenTelemetryAssertions.equalTo(key, value));
}
/** Asserts the exemplar has the given filtered attribute. */
public ExemplarDataAssert hasFilteredAttribute(AttributeAssertion attributeAssertion) {
isNotNull();
Set<AttributeKey<?>> actualKeys = actual.getFilteredAttributes().asMap().keySet();
AttributeKey<?> key = attributeAssertion.getKey();
assertThat(actualKeys).as("attribute keys").contains(key);
Object value = actual.getFilteredAttributes().get(key);
AbstractAssert<?, ?> assertion = AttributeAssertion.attributeValueAssertion(key, value);
attributeAssertion.getAssertion().accept(assertion);
return this;
}
/** Asserts the exemplar has the given filtered attributes. */
public ExemplarDataAssert hasFilteredAttributes(Attributes expected) {
isNotNull();
assertThat(actual.getFilteredAttributes()).as("filtered_attributes").isEqualTo(expected);
return this;
}
/** Asserts the exemplar has the given filtered attributes. */
@SuppressWarnings({"rawtypes", "unchecked"})
@SafeVarargs
public final ExemplarDataAssert hasFilteredAttributes(
Map.Entry<? extends AttributeKey<?>, ?>... entries) {
AttributesBuilder attributesBuilder = Attributes.builder();
for (Map.Entry<? extends AttributeKey<?>, ?> attr : entries) {
attributesBuilder.put((AttributeKey) attr.getKey(), attr.getValue());
}
Attributes attributes = attributesBuilder.build();
return hasFilteredAttributes(attributes);
}
/** Asserts the exemplar has filtered attributes matching all {@code assertions} and no more. */
public ExemplarDataAssert hasFilteredAttributesSatisfying(AttributeAssertion... assertions) {
return hasFilteredAttributesSatisfying(Arrays.asList(assertions));
}
/**
* Asserts the exemplar has filtered attributes matching all {@code assertions} and no more.
* Assertions can be created using methods like {@link
* OpenTelemetryAssertions#satisfies(AttributeKey, OpenTelemetryAssertions.LongAssertConsumer)}.
*/
public ExemplarDataAssert hasFilteredAttributesSatisfying(
Iterable<AttributeAssertion> assertions) {
AssertUtil.assertAttributes(actual.getFilteredAttributes(), assertions);
return myself;
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.sdk.metrics.data.GaugeData;
import io.opentelemetry.sdk.metrics.data.LongPointData;
import java.util.Arrays;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.assertj.core.api.AbstractAssert;
/** Assertions for an exported long {@link GaugeData}. */
public final class LongGaugeAssert
extends AbstractAssert<LongGaugeAssert, GaugeData<LongPointData>> {
LongGaugeAssert(@Nullable GaugeData<LongPointData> actual) {
super(actual, LongGaugeAssert.class);
}
/**
* Asserts the gauge has points matching all of the given assertions and no more, in any order.
*/
@SafeVarargs
@SuppressWarnings("varargs")
public final LongGaugeAssert hasPointsSatisfying(Consumer<LongPointDataAssert>... assertions) {
return hasPointsSatisfying(Arrays.asList(assertions));
}
/**
* Asserts the gauge has points matching all of the given assertions and no more, in any order.
*/
public LongGaugeAssert hasPointsSatisfying(
Iterable<? extends Consumer<LongPointDataAssert>> assertions) {
assertThat(actual.getPoints())
.satisfiesExactlyInAnyOrder(AssertUtil.toConsumers(assertions, LongPointDataAssert::new));
return this;
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj;
import io.opentelemetry.sdk.metrics.data.LongPointData;
import javax.annotation.Nullable;
import org.assertj.core.api.Assertions;
/** Assertions for an exported {@link LongPointData}. */
public final class LongPointDataAssert
extends AbstractPointDataAssert<LongPointDataAssert, LongPointData> {
LongPointDataAssert(@Nullable LongPointData actual) {
super(actual, LongPointDataAssert.class);
}
/** Asserts the point has the given value. */
public LongPointDataAssert hasValue(long expected) {
isNotNull();
Assertions.assertThat(actual.getValue()).as("value").isEqualTo(expected);
return this;
}
}

View File

@ -0,0 +1,126 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.data.MetricDataType;
import io.opentelemetry.sdk.resources.Resource;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.assertj.core.api.AbstractAssert;
/** Assertions for an exported {@link MetricData}. */
public final class MetricDataAssert extends AbstractAssert<MetricDataAssert, MetricData> {
MetricDataAssert(@Nullable MetricData actual) {
super(actual, MetricDataAssert.class);
}
/** Asserts the metric has the given {@link Resource}. */
public MetricDataAssert hasResource(Resource resource) {
isNotNull();
if (!actual.getResource().equals(resource)) {
failWithActualExpectedAndMessage(
actual,
"resource: " + resource,
"Expected MetricData to have resource <%s> but found <%s>",
resource,
actual.getResource());
}
return this;
}
/** Asserts the metric has the given the {@link InstrumentationScopeInfo}. */
public MetricDataAssert hasInstrumentationScope(
InstrumentationScopeInfo instrumentationScopeInfo) {
isNotNull();
if (!actual.getInstrumentationScopeInfo().equals(instrumentationScopeInfo)) {
failWithActualExpectedAndMessage(
actual,
"instrumentation scope: " + instrumentationScopeInfo,
"Expected MetricData to have resource <%s> but found <%s>",
instrumentationScopeInfo,
actual.getInstrumentationScopeInfo());
}
return this;
}
/** Asserts the metric has the given name. */
public MetricDataAssert hasName(String name) {
isNotNull();
if (!actual.getName().equals(name)) {
failWithActualExpectedAndMessage(
actual,
"name: " + name,
"Expected MetricData to have name <%s> but found <%s>",
name,
actual.getName());
}
return this;
}
/** Asserts the metric has the given description. */
public MetricDataAssert hasDescription(String description) {
isNotNull();
if (!actual.getDescription().equals(description)) {
failWithActualExpectedAndMessage(
actual,
"description: " + description,
"Expected MetricData to have description <%s> but found <%s>",
description,
actual.getDescription());
}
return this;
}
/** Asserts the metric has the given unit. */
public MetricDataAssert hasUnit(String unit) {
isNotNull();
if (!actual.getUnit().equals(unit)) {
failWithActualExpectedAndMessage(
actual,
"unit: " + unit,
"Expected MetricData to have unit <%s> but found <%s>",
unit,
actual.getUnit());
}
return this;
}
/**
* Asserts this {@link MetricData} is a {@code DoubleGauge} that satisfies the provided assertion.
*/
public MetricDataAssert hasDoubleGaugeSatisfying(Consumer<DoubleGaugeAssert> assertion) {
isNotNull();
if (actual.getType() != MetricDataType.DOUBLE_GAUGE) {
failWithActualExpectedAndMessage(
actual,
"type: DOUBLE_GAUGE",
"Expected MetricData to have type <%s> but found <%s>",
MetricDataType.DOUBLE_GAUGE,
actual.getType());
}
assertion.accept(new DoubleGaugeAssert(actual.getDoubleGaugeData()));
return this;
}
/**
* Asserts this {@link MetricData} is a {@code LongGauge} that satisfies the provided assertion.
*/
public MetricDataAssert hasLongGaugeSatisfying(Consumer<LongGaugeAssert> assertion) {
isNotNull();
if (actual.getType() != MetricDataType.LONG_GAUGE) {
failWithActualExpectedAndMessage(
actual,
"type: LONG_GAUGE",
"Expected MetricData to have type <%s> but found <%s>",
MetricDataType.LONG_GAUGE,
actual.getType());
}
assertion.accept(new LongGaugeAssert(actual.getLongGaugeData()));
return this;
}
}

View File

@ -7,6 +7,7 @@ package io.opentelemetry.sdk.testing.assertj;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.trace.data.EventData;
import io.opentelemetry.sdk.trace.data.SpanData;
import java.util.AbstractMap;
@ -35,11 +36,16 @@ public final class OpenTelemetryAssertions extends Assertions {
return new AttributesAssert(attributes);
}
/** Returns an assertion for {@link SpanDataAssert}. */
/** Returns an assertion for {@link SpanData}. */
public static SpanDataAssert assertThat(@Nullable SpanData spanData) {
return new SpanDataAssert(spanData);
}
/** Returns an assertion for {@link MetricData}. */
public static MetricDataAssert assertThat(@Nullable MetricData metricData) {
return new MetricDataAssert(metricData);
}
/** Returns an assertion for {@link EventDataAssert}. */
public static EventDataAssert assertThat(@Nullable EventData eventData) {
return new EventDataAssert(eventData);

View File

@ -267,7 +267,7 @@ public final class SpanDataAssert extends AbstractAssert<SpanDataAssert, SpanDat
assertThat(actualKeys).as("span [%s] attribute keys", actual.getName()).contains(key);
Object value = actual.getAttributes().get(key);
AbstractAssert<?, ?> assertion = attributeValueAssertion(key, value);
AbstractAssert<?, ?> assertion = AttributeAssertion.attributeValueAssertion(key, value);
attributeAssertion.getAssertion().accept(assertion);
return this;
@ -276,7 +276,7 @@ public final class SpanDataAssert extends AbstractAssert<SpanDataAssert, SpanDat
/** Asserts the span has the given attributes. */
public SpanDataAssert hasAttributes(Attributes attributes) {
isNotNull();
if (!attributesAreEqual(attributes)) {
if (!AssertUtil.attributesAreEqual(actual.getAttributes(), attributes)) {
failWithActualExpectedAndMessage(
actual.getAttributes(),
attributes,
@ -300,12 +300,6 @@ public final class SpanDataAssert extends AbstractAssert<SpanDataAssert, SpanDat
return hasAttributes(attributes);
}
private boolean attributesAreEqual(Attributes attributes) {
// compare as maps, since implementations do not have equals that work correctly across
// implementations.
return actual.getAttributes().asMap().equals(attributes.asMap());
}
/** Asserts the span has attributes satisfying the given condition. */
public SpanDataAssert hasAttributesSatisfying(Consumer<Attributes> attributes) {
isNotNull();
@ -332,7 +326,7 @@ public final class SpanDataAssert extends AbstractAssert<SpanDataAssert, SpanDat
if (value != null) {
checkedKeys.add(key);
}
AbstractAssert<?, ?> assertion = attributeValueAssertion(key, value);
AbstractAssert<?, ?> assertion = AttributeAssertion.attributeValueAssertion(key, value);
attributeAssertion.getAssertion().accept(assertion);
}
@ -343,32 +337,6 @@ public final class SpanDataAssert extends AbstractAssert<SpanDataAssert, SpanDat
return this;
}
// The return type of these assertions must match the parameters in methods like
// OpenTelemetryAssertions.satisfies.
// Our code is nullness annotated but assertj is not. NullAway seems to still treat the base class
// of OpenTelemetryAssertions as annotated though, so there seems to be no way to avoid
// suppressing here.
@SuppressWarnings("NullAway")
private static AbstractAssert<?, ?> attributeValueAssertion(
AttributeKey<?> key, @Nullable Object value) {
switch (key.getType()) {
case STRING:
return assertThat((String) value);
case BOOLEAN:
return assertThat((Boolean) value);
case LONG:
return assertThat((Long) value);
case DOUBLE:
return assertThat((Double) value);
case STRING_ARRAY:
case BOOLEAN_ARRAY:
case LONG_ARRAY:
case DOUBLE_ARRAY:
return assertThat((List<?>) value);
}
throw new IllegalArgumentException("Unknown type for key " + key);
}
/**
* Asserts the span has an exception event for the given {@link Throwable}. The stack trace is not
* matched against.

View File

@ -0,0 +1,539 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.offset;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.metrics.data.DoubleExemplarData;
import io.opentelemetry.sdk.metrics.data.DoublePointData;
import io.opentelemetry.sdk.metrics.data.LongExemplarData;
import io.opentelemetry.sdk.metrics.data.LongPointData;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoubleExemplarData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoublePointData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableGaugeData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongExemplarData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData;
import io.opentelemetry.sdk.metrics.internal.data.ImmutableMetricData;
import io.opentelemetry.sdk.resources.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
// We always assert the contents of lists out of order to verify that assertions behave that way.
class MetricAssertionsTest {
private static final String TRACE_ID = "00000000000000010000000000000002";
private static final String SPAN_ID1 = "0000000000000003";
private static final String SPAN_ID2 = "0000000000000004";
private static final Resource RESOURCE =
Resource.create(Attributes.builder().put("dog", "bark").build());
private static final InstrumentationScopeInfo INSTRUMENTATION_SCOPE_INFO =
InstrumentationScopeInfo.create("opentelemetry", "1.0", null);
private static final AttributeKey<String> BEAR = AttributeKey.stringKey("bear");
private static final AttributeKey<String> CAT = AttributeKey.stringKey("cat");
private static final AttributeKey<Boolean> WARM = AttributeKey.booleanKey("warm");
private static final AttributeKey<Long> TEMPERATURE = AttributeKey.longKey("temperature");
private static final AttributeKey<Double> LENGTH = AttributeKey.doubleKey("length");
private static final AttributeKey<List<String>> COLORS = AttributeKey.stringArrayKey("colors");
private static final AttributeKey<List<Boolean>> CONDITIONS =
AttributeKey.booleanArrayKey("conditions");
private static final AttributeKey<List<Long>> SCORES = AttributeKey.longArrayKey("scores");
private static final AttributeKey<List<Double>> COINS = AttributeKey.doubleArrayKey("coins");
private static final Attributes ATTRIBUTES =
Attributes.builder()
.put(BEAR, "mya")
.put(WARM, true)
.put(TEMPERATURE, 30)
.put(LENGTH, 1.2)
.put(COLORS, Arrays.asList("red", "blue"))
.put(CONDITIONS, Arrays.asList(false, true))
.put(SCORES, Arrays.asList(0L, 1L))
.put(COINS, Arrays.asList(0.01, 0.05, 0.1))
.build();
private static final DoubleExemplarData DOUBLE_EXEMPLAR1 =
ImmutableDoubleExemplarData.create(
ATTRIBUTES,
0,
SpanContext.create(TRACE_ID, SPAN_ID1, TraceFlags.getDefault(), TraceState.getDefault()),
1.0);
private static final DoubleExemplarData DOUBLE_EXEMPLAR2 =
ImmutableDoubleExemplarData.create(
Attributes.empty(),
2,
SpanContext.create(TRACE_ID, SPAN_ID2, TraceFlags.getDefault(), TraceState.getDefault()),
2.0);
private static final DoublePointData DOUBLE_POINT_DATA =
ImmutableDoublePointData.create(1, 2, ATTRIBUTES, 3.0, Collections.emptyList());
private static final DoublePointData DOUBLE_POINT_DATA_WITH_EXEMPLAR =
ImmutableDoublePointData.create(
3, 4, Attributes.empty(), 3.0, Arrays.asList(DOUBLE_EXEMPLAR1, DOUBLE_EXEMPLAR2));
private static final LongExemplarData LONG_EXEMPLAR1 =
ImmutableLongExemplarData.create(
ATTRIBUTES,
0,
SpanContext.create(TRACE_ID, SPAN_ID1, TraceFlags.getDefault(), TraceState.getDefault()),
1);
private static final LongExemplarData LONG_EXEMPLAR2 =
ImmutableLongExemplarData.create(
Attributes.empty(),
2,
SpanContext.create(TRACE_ID, SPAN_ID2, TraceFlags.getDefault(), TraceState.getDefault()),
// TODO(anuraaga): Currently there is no good way of asserting on actual long exemplar
// values.
2);
private static final LongPointData LONG_POINT_DATA =
ImmutableLongPointData.create(1, 2, ATTRIBUTES, 1, Collections.emptyList());
private static final LongPointData LONG_POINT_DATA_WITH_EXEMPLAR =
ImmutableLongPointData.create(
3, 4, Attributes.empty(), Long.MAX_VALUE, Arrays.asList(LONG_EXEMPLAR1, LONG_EXEMPLAR2));
private static final MetricData DOUBLE_GAUGE_METRIC =
ImmutableMetricData.createDoubleGauge(
RESOURCE,
INSTRUMENTATION_SCOPE_INFO,
/* name= */ "gauge",
/* description= */ "a gauge",
/* unit= */ "1",
ImmutableGaugeData.create(
// Points
Arrays.asList(DOUBLE_POINT_DATA, DOUBLE_POINT_DATA_WITH_EXEMPLAR)));
private static final MetricData LONG_GAUGE_METRIC =
ImmutableMetricData.createLongGauge(
RESOURCE,
INSTRUMENTATION_SCOPE_INFO,
/* name= */ "gauge",
/* description= */ "a gauge",
/* unit= */ "1",
ImmutableGaugeData.create(
// Points
Arrays.asList(LONG_POINT_DATA, LONG_POINT_DATA_WITH_EXEMPLAR)));
@Test
void doubleGauge() {
assertThat(DOUBLE_GAUGE_METRIC)
.hasResource(RESOURCE)
.hasInstrumentationScope(INSTRUMENTATION_SCOPE_INFO)
.hasName("gauge")
.hasDescription("a gauge")
.hasUnit("1")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasStartEpochNanos(3)
.hasEpochNanos(4)
.hasAttributes(Attributes.empty())
.hasValue(3.0)
.hasExemplars(DOUBLE_EXEMPLAR2, DOUBLE_EXEMPLAR1)
.hasExemplarsSatisfying(
exemplar ->
exemplar
.hasEpochNanos(2)
.hasTraceId(TRACE_ID)
.hasSpanId(SPAN_ID2)
.hasValue(2.0)
.hasFilteredAttributes(Attributes.empty()),
exemplar ->
exemplar
.hasEpochNanos(0)
.hasTraceId(TRACE_ID)
.hasSpanId(SPAN_ID1)
.hasValue(1.0)
.hasFilteredAttribute(BEAR, "mya")
.hasFilteredAttribute(equalTo(BEAR, "mya"))
.hasFilteredAttributes(ATTRIBUTES)
.hasFilteredAttributes(
attributeEntry("bear", "mya"),
attributeEntry("warm", true),
attributeEntry("temperature", 30),
attributeEntry("length", 1.2),
attributeEntry("colors", "red", "blue"),
attributeEntry("conditions", false, true),
attributeEntry("scores", 0L, 1L),
attributeEntry("coins", 0.01, 0.05, 0.1))
.hasFilteredAttributesSatisfying(
equalTo(BEAR, "mya"),
equalTo(WARM, true),
equalTo(TEMPERATURE, 30),
equalTo(LENGTH, 1.2),
equalTo(COLORS, Arrays.asList("red", "blue")),
equalTo(CONDITIONS, Arrays.asList(false, true)),
equalTo(SCORES, Arrays.asList(0L, 1L)),
equalTo(COINS, Arrays.asList(0.01, 0.05, 0.1)))
.hasFilteredAttributesSatisfying(
satisfies(BEAR, val -> val.startsWith("mya")),
satisfies(WARM, val -> val.isTrue()),
satisfies(
TEMPERATURE, val -> val.isGreaterThanOrEqualTo(30)),
satisfies(LENGTH, val -> val.isCloseTo(1, offset(0.3))),
satisfies(
COLORS, val -> val.containsExactly("red", "blue")),
satisfies(
CONDITIONS,
val -> val.containsExactly(false, true)),
satisfies(SCORES, val -> val.containsExactly(0L, 1L)),
satisfies(
COINS, val -> val.containsExactly(0.01, 0.05, 0.1)))
// Demonstrates common usage of many exact matches and one
// needing a loose one.
.hasFilteredAttributesSatisfying(
equalTo(BEAR, "mya"),
equalTo(WARM, true),
equalTo(TEMPERATURE, 30L),
equalTo(COLORS, Arrays.asList("red", "blue")),
equalTo(CONDITIONS, Arrays.asList(false, true)),
equalTo(SCORES, Arrays.asList(0L, 1L)),
equalTo(COINS, Arrays.asList(0.01, 0.05, 0.1)),
satisfies(
LENGTH, val -> val.isCloseTo(1, offset(0.3))))),
point ->
point
.hasStartEpochNanos(1)
.hasEpochNanos(2)
.hasValue(3.0)
.hasAttribute(BEAR, "mya")
.hasAttribute(equalTo(BEAR, "mya"))
.hasAttributes(ATTRIBUTES)
.hasAttributes(
attributeEntry("bear", "mya"),
attributeEntry("warm", true),
attributeEntry("temperature", 30),
attributeEntry("length", 1.2),
attributeEntry("colors", "red", "blue"),
attributeEntry("conditions", false, true),
attributeEntry("scores", 0L, 1L),
attributeEntry("coins", 0.01, 0.05, 0.1))
.hasAttributesSatisfying(
equalTo(BEAR, "mya"),
equalTo(WARM, true),
equalTo(TEMPERATURE, 30),
equalTo(LENGTH, 1.2),
equalTo(COLORS, Arrays.asList("red", "blue")),
equalTo(CONDITIONS, Arrays.asList(false, true)),
equalTo(SCORES, Arrays.asList(0L, 1L)),
equalTo(COINS, Arrays.asList(0.01, 0.05, 0.1)))
.hasAttributesSatisfying(
satisfies(BEAR, val -> val.startsWith("mya")),
satisfies(WARM, val -> val.isTrue()),
satisfies(TEMPERATURE, val -> val.isGreaterThanOrEqualTo(30)),
satisfies(LENGTH, val -> val.isCloseTo(1, offset(0.3))),
satisfies(COLORS, val -> val.containsExactly("red", "blue")),
satisfies(CONDITIONS, val -> val.containsExactly(false, true)),
satisfies(SCORES, val -> val.containsExactly(0L, 1L)),
satisfies(COINS, val -> val.containsExactly(0.01, 0.05, 0.1)))
// Demonstrates common usage of many exact matches and one needing a
// loose one.
.hasAttributesSatisfying(
equalTo(BEAR, "mya"),
equalTo(WARM, true),
equalTo(TEMPERATURE, 30L),
equalTo(COLORS, Arrays.asList("red", "blue")),
equalTo(CONDITIONS, Arrays.asList(false, true)),
equalTo(SCORES, Arrays.asList(0L, 1L)),
equalTo(COINS, Arrays.asList(0.01, 0.05, 0.1)),
satisfies(LENGTH, val -> val.isCloseTo(1, offset(0.3))))));
}
@Test
void doubleGaugeFailure() {
assertThatThrownBy(() -> assertThat(DOUBLE_GAUGE_METRIC).hasResource(Resource.empty()))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasInstrumentationScope(InstrumentationScopeInfo.empty()))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(() -> assertThat(DOUBLE_GAUGE_METRIC).hasName("whoami"))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(() -> assertThat(DOUBLE_GAUGE_METRIC).hasDescription("whatami"))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(() -> assertThat(DOUBLE_GAUGE_METRIC).hasUnit("kelvin"))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(() -> assertThat(DOUBLE_GAUGE_METRIC).hasLongGaugeSatisfying(gauge -> {}))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
// Not enough points
gauge -> gauge.hasPointsSatisfying(point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point -> point.hasStartEpochNanos(100), point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point -> point.hasEpochNanos(100), point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(point -> point.hasValue(100), point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
// Not enough exemplars
point -> point.hasExemplarsSatisfying(exemplar -> {}),
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
// Not enough exemplars
point -> point.hasExemplars(DOUBLE_EXEMPLAR1),
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasExemplarsSatisfying(
exemplar -> exemplar.hasEpochNanos(100), exemplar -> {}),
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasExemplarsSatisfying(
exemplar -> exemplar.hasTraceId("trace"), exemplar -> {}),
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasExemplarsSatisfying(
exemplar -> exemplar.hasSpanId("span"), exemplar -> {}),
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasExemplarsSatisfying(
exemplar -> exemplar.hasValue(100.0), exemplar -> {}),
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasExemplarsSatisfying(
exemplar -> exemplar.hasFilteredAttribute(CAT, "garfield"),
exemplar -> {}),
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasExemplarsSatisfying(
exemplar ->
exemplar.hasFilteredAttributes(
Attributes.of(CAT, "garfield")),
exemplar -> {}),
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasExemplarsSatisfying(
exemplar ->
// Extra CAT
exemplar.hasFilteredAttributesSatisfying(
satisfies(BEAR, val -> val.startsWith("mya")),
satisfies(CAT, val -> val.startsWith("nya")),
satisfies(WARM, val -> val.isTrue()),
satisfies(
TEMPERATURE,
val -> val.isGreaterThanOrEqualTo(30)),
satisfies(
LENGTH, val -> val.isCloseTo(1, offset(0.3))),
satisfies(
COLORS,
val -> val.containsExactly("red", "blue")),
satisfies(
CONDITIONS,
val -> val.containsExactly(false, true)),
satisfies(
SCORES, val -> val.containsExactly(0L, 1L)),
satisfies(
COINS,
val -> val.containsExactly(0.01, 0.05, 0.1))),
exemplar -> {}),
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point -> point.hasAttributes(Attributes.empty()),
point -> point.hasAttribute(CAT, "garfield"))))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point -> point.hasAttributes(Attributes.empty()),
point -> point.hasAttributes(Attributes.of(CAT, "garfield")))))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_GAUGE_METRIC)
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point -> point.hasAttributes(Attributes.empty()),
// Extra CAT
point ->
point.hasAttributesSatisfying(
satisfies(BEAR, val -> val.startsWith("mya")),
satisfies(CAT, val -> val.startsWith("nya")),
satisfies(WARM, val -> val.isTrue()),
satisfies(
TEMPERATURE, val -> val.isGreaterThanOrEqualTo(30)),
satisfies(LENGTH, val -> val.isCloseTo(1, offset(0.3))),
satisfies(
COLORS, val -> val.containsExactly("red", "blue")),
satisfies(
CONDITIONS, val -> val.containsExactly(false, true)),
satisfies(SCORES, val -> val.containsExactly(0L, 1L)),
satisfies(
COINS, val -> val.containsExactly(0.01, 0.05, 0.1))))))
.isInstanceOf(AssertionError.class);
}
// The above tests verify shared behavior in AbstractPointDataAssert and MetricDataAssert so we
// keep tests simpler
// by only checking specific logic below.
@Test
void longGauge() {
assertThat(LONG_GAUGE_METRIC)
.hasLongGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(Long.MAX_VALUE)
.hasExemplarsSatisfying(
exemplar -> exemplar.hasValue(2), exemplar -> exemplar.hasValue(1)),
point -> point.hasValue(1)));
}
@Test
void longGaugeFailure() {
assertThatThrownBy(() -> assertThat(LONG_GAUGE_METRIC).hasDoubleGaugeSatisfying(gauge -> {}))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(LONG_GAUGE_METRIC)
.hasLongGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
// Not enough points
point -> {})))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(LONG_GAUGE_METRIC)
.hasLongGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point -> point.hasValue(2), point -> point.hasValue(1))))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(LONG_GAUGE_METRIC)
.hasLongGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point -> point.hasExemplars(LONG_EXEMPLAR2),
point -> point.hasValue(1))))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(LONG_GAUGE_METRIC)
.hasLongGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasExemplarsSatisfying(
exemplar -> exemplar.hasValue(100), exemplar -> {}),
point -> point.hasValue(1))))
.isInstanceOf(AssertionError.class);
}
}

View File

@ -34,7 +34,7 @@ import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
@SuppressWarnings("PreferJavaTimeOverload")
class OpenTelemetryAssertionsTest {
class TraceAssertionsTest {
private static final String TRACE_ID = "00000000000000010000000000000002";
private static final String SPAN_ID1 = "0000000000000003";
private static final String SPAN_ID2 = "0000000000000004";