Skip to content

Commit 452093e

Browse files
committed
Add unit test for metrics auth customization
1 parent 716fad9 commit 452093e

File tree

1 file changed

+154
-21
lines changed

1 file changed

+154
-21
lines changed

gcp-auth-extension/src/test/java/io/opentelemetry/contrib/gcp/auth/GcpAuthAutoConfigurationCustomizerProviderTest.java

Lines changed: 154 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@
1717
import com.google.auto.value.AutoValue;
1818
import com.google.common.collect.ImmutableMap;
1919
import io.opentelemetry.api.common.AttributeKey;
20+
import io.opentelemetry.api.common.Attributes;
21+
import io.opentelemetry.api.metrics.LongCounter;
2022
import io.opentelemetry.api.trace.Span;
2123
import io.opentelemetry.context.Scope;
24+
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
25+
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder;
2226
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
2327
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;
2428
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
@@ -34,6 +38,10 @@
3438
import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider;
3539
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
3640
import io.opentelemetry.sdk.common.CompletableResultCode;
41+
import io.opentelemetry.sdk.metrics.Aggregation;
42+
import io.opentelemetry.sdk.metrics.InstrumentType;
43+
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
44+
import io.opentelemetry.sdk.metrics.data.MetricData;
3745
import io.opentelemetry.sdk.metrics.export.MetricExporter;
3846
import io.opentelemetry.sdk.trace.data.SpanData;
3947
import io.opentelemetry.sdk.trace.export.SpanExporter;
@@ -47,6 +55,7 @@
4755
import java.util.List;
4856
import java.util.Map;
4957
import java.util.Map.Entry;
58+
import java.util.Random;
5059
import java.util.Set;
5160
import java.util.concurrent.TimeUnit;
5261
import java.util.function.Supplier;
@@ -65,18 +74,21 @@
6574
import org.mockito.Mockito;
6675
import org.mockito.MockitoAnnotations;
6776
import org.mockito.junit.jupiter.MockitoExtension;
77+
import org.mockito.stubbing.Answer;
6878

6979
@ExtendWith(MockitoExtension.class)
7080
class GcpAuthAutoConfigurationCustomizerProviderTest {
7181

7282
private static final String DUMMY_GCP_RESOURCE_PROJECT_ID = "my-gcp-resource-project-id";
7383
private static final String DUMMY_GCP_QUOTA_PROJECT_ID = "my-gcp-quota-project-id";
84+
private static final Random TEST_RANDOM = new Random();
7485

7586
@Mock private GoogleCredentials mockedGoogleCredentials;
7687

77-
@Captor private ArgumentCaptor<Supplier<Map<String, String>>> headerSupplierCaptor;
88+
@Captor private ArgumentCaptor<Supplier<Map<String, String>>> traceHeaderSupplierCaptor;
89+
@Captor private ArgumentCaptor<Supplier<Map<String, String>>> metricHeaderSupplierCaptor;
7890

79-
private static final ImmutableMap<String, String> otelProperties =
91+
private static final ImmutableMap<String, String> defaultOtelPropertiesSpanExporter =
8092
ImmutableMap.of(
8193
"otel.exporter.otlp.traces.endpoint",
8294
"https://telemetry.googleapis.com/v1/traces",
@@ -89,13 +101,26 @@ class GcpAuthAutoConfigurationCustomizerProviderTest {
89101
"otel.resource.attributes",
90102
"foo=bar");
91103

104+
private static final ImmutableMap<String, String> defaultOtelPropertiesMetricExporter =
105+
ImmutableMap.of(
106+
"otel.exporter.otlp.metrics.endpoint",
107+
"https://telemetry.googleapis.com/v1/metrics",
108+
"otel.traces.exporter",
109+
"none",
110+
"otel.metrics.exporter",
111+
"otlp",
112+
"otel.logs.exporter",
113+
"none",
114+
"otel.resource.attributes",
115+
"foo=bar");
116+
92117
@BeforeEach
93118
public void setup() {
94119
MockitoAnnotations.openMocks(this);
95120
}
96121

97122
@Test
98-
public void testCustomizerOtlpHttp() {
123+
public void testTraceCustomizerOtlpHttp() {
99124
// Set resource project system property
100125
System.setProperty(
101126
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
@@ -131,9 +156,10 @@ public void testCustomizerOtlpHttp() {
131156

132157
Mockito.verify(mockOtlpHttpSpanExporter, Mockito.times(1)).toBuilder();
133158
Mockito.verify(spyOtlpHttpSpanExporterBuilder, Mockito.times(1))
134-
.setHeaders(headerSupplierCaptor.capture());
135-
assertEquals(2, headerSupplierCaptor.getValue().get().size());
136-
assertThat(authHeadersQuotaProjectIsPresent(headerSupplierCaptor.getValue().get())).isTrue();
159+
.setHeaders(traceHeaderSupplierCaptor.capture());
160+
assertEquals(2, traceHeaderSupplierCaptor.getValue().get().size());
161+
assertThat(authHeadersQuotaProjectIsPresent(traceHeaderSupplierCaptor.getValue().get()))
162+
.isTrue();
137163

138164
Mockito.verify(mockOtlpHttpSpanExporter, Mockito.atLeast(1)).export(Mockito.anyCollection());
139165

@@ -152,6 +178,90 @@ public void testCustomizerOtlpHttp() {
152178
}
153179
}
154180

181+
@Test
182+
public void testMetricCustomizerOtlpHttp() {
183+
// Set resource project system property
184+
System.setProperty(
185+
ConfigurableOption.GOOGLE_CLOUD_PROJECT.getSystemProperty(), DUMMY_GCP_RESOURCE_PROJECT_ID);
186+
// Prepare mocks
187+
prepareMockBehaviorForGoogleCredentials();
188+
OtlpHttpMetricExporter mockOtlpHttpMetricExporter = Mockito.mock(OtlpHttpMetricExporter.class);
189+
OtlpHttpMetricExporterBuilder otlpMetricExporterBuilder = OtlpHttpMetricExporter.builder();
190+
OtlpHttpMetricExporterBuilder spyOtlpHttpMetricExporterBuilder =
191+
Mockito.spy(otlpMetricExporterBuilder);
192+
Mockito.when(spyOtlpHttpMetricExporterBuilder.build()).thenReturn(mockOtlpHttpMetricExporter);
193+
194+
Mockito.when(mockOtlpHttpMetricExporter.shutdown())
195+
.thenReturn(CompletableResultCode.ofSuccess());
196+
List<MetricData> exportedMetrics = new ArrayList<>();
197+
Mockito.when(mockOtlpHttpMetricExporter.export(Mockito.anyCollection()))
198+
.thenAnswer(
199+
invocationOnMock -> {
200+
exportedMetrics.addAll(invocationOnMock.getArgument(0));
201+
return CompletableResultCode.ofSuccess();
202+
});
203+
Mockito.when(mockOtlpHttpMetricExporter.toBuilder())
204+
.thenReturn(spyOtlpHttpMetricExporterBuilder);
205+
// mock the get default aggregation and aggregation temporality - they're required for valid
206+
// metric collection.
207+
Mockito.when(mockOtlpHttpMetricExporter.getDefaultAggregation(Mockito.any()))
208+
.thenAnswer(
209+
(Answer<Aggregation>)
210+
invocationOnMock -> {
211+
InstrumentType instrumentType = invocationOnMock.getArgument(0);
212+
return OtlpHttpMetricExporter.getDefault().getDefaultAggregation(instrumentType);
213+
});
214+
Mockito.when(mockOtlpHttpMetricExporter.getAggregationTemporality(Mockito.any()))
215+
.thenAnswer(
216+
(Answer<AggregationTemporality>)
217+
invocationOnMock -> {
218+
InstrumentType instrumentType = invocationOnMock.getArgument(0);
219+
return OtlpHttpMetricExporter.getDefault()
220+
.getAggregationTemporality(instrumentType);
221+
});
222+
223+
try (MockedStatic<GoogleCredentials> googleCredentialsMockedStatic =
224+
Mockito.mockStatic(GoogleCredentials.class)) {
225+
googleCredentialsMockedStatic
226+
.when(GoogleCredentials::getApplicationDefault)
227+
.thenReturn(mockedGoogleCredentials);
228+
229+
OpenTelemetrySdk sdk = buildOpenTelemetrySdkWithExporter(mockOtlpHttpMetricExporter);
230+
generateTestMetric(sdk);
231+
CompletableResultCode code = sdk.shutdown();
232+
CompletableResultCode joinResult = code.join(10, TimeUnit.SECONDS);
233+
assertTrue(joinResult.isSuccess());
234+
235+
Mockito.verify(mockOtlpHttpMetricExporter, Mockito.times(1)).toBuilder();
236+
Mockito.verify(spyOtlpHttpMetricExporterBuilder, Mockito.times(1))
237+
.setHeaders(metricHeaderSupplierCaptor.capture());
238+
assertEquals(2, metricHeaderSupplierCaptor.getValue().get().size());
239+
assertThat(authHeadersQuotaProjectIsPresent(metricHeaderSupplierCaptor.getValue().get()))
240+
.isTrue();
241+
242+
Mockito.verify(mockOtlpHttpMetricExporter, Mockito.atLeast(1))
243+
.export(Mockito.anyCollection());
244+
245+
assertThat(exportedMetrics)
246+
.hasSizeGreaterThan(0)
247+
.allSatisfy(
248+
metricData -> {
249+
assertThat(metricData.getResource().getAttributes().asMap())
250+
.containsEntry(
251+
AttributeKey.stringKey(GCP_USER_PROJECT_ID_KEY),
252+
DUMMY_GCP_RESOURCE_PROJECT_ID)
253+
.containsEntry(AttributeKey.stringKey("foo"), "bar");
254+
assertThat(metricData.getLongSumData().getPoints())
255+
.hasSizeGreaterThan(0)
256+
.allSatisfy(
257+
longPointData -> {
258+
assertThat(longPointData.getAttributes().asMap())
259+
.containsKey(AttributeKey.longKey("work_loop"));
260+
});
261+
});
262+
}
263+
}
264+
155265
@Test
156266
public void testCustomizerOtlpGrpc() {
157267
// Set resource project system property
@@ -163,7 +273,7 @@ public void testCustomizerOtlpGrpc() {
163273
OtlpGrpcSpanExporterBuilder spyOtlpGrpcSpanExporterBuilder =
164274
Mockito.spy(OtlpGrpcSpanExporter.builder());
165275
List<SpanData> exportedSpans = new ArrayList<>();
166-
configureGrpcMockExporters(
276+
configureGrpcMockSpanExporters(
167277
mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
168278

169279
try (MockedStatic<GoogleCredentials> googleCredentialsMockedStatic =
@@ -180,9 +290,10 @@ public void testCustomizerOtlpGrpc() {
180290

181291
Mockito.verify(mockOtlpGrpcSpanExporter, Mockito.times(1)).toBuilder();
182292
Mockito.verify(spyOtlpGrpcSpanExporterBuilder, Mockito.times(1))
183-
.setHeaders(headerSupplierCaptor.capture());
184-
assertEquals(2, headerSupplierCaptor.getValue().get().size());
185-
assertThat(authHeadersQuotaProjectIsPresent(headerSupplierCaptor.getValue().get())).isTrue();
293+
.setHeaders(traceHeaderSupplierCaptor.capture());
294+
assertEquals(2, traceHeaderSupplierCaptor.getValue().get().size());
295+
assertThat(authHeadersQuotaProjectIsPresent(traceHeaderSupplierCaptor.getValue().get()))
296+
.isTrue();
186297

187298
Mockito.verify(mockOtlpGrpcSpanExporter, Mockito.atLeast(1)).export(Mockito.anyCollection());
188299

@@ -256,7 +367,7 @@ public void testQuotaProjectBehavior(QuotaProjectIdTestBehavior testCase) throws
256367
OtlpGrpcSpanExporterBuilder spyOtlpGrpcSpanExporterBuilder =
257368
Mockito.spy(OtlpGrpcSpanExporter.builder());
258369
List<SpanData> exportedSpans = new ArrayList<>();
259-
configureGrpcMockExporters(
370+
configureGrpcMockSpanExporters(
260371
mockOtlpGrpcSpanExporter, spyOtlpGrpcSpanExporterBuilder, exportedSpans);
261372

262373
try (MockedStatic<GoogleCredentials> googleCredentialsMockedStatic =
@@ -272,10 +383,10 @@ public void testQuotaProjectBehavior(QuotaProjectIdTestBehavior testCase) throws
272383
CompletableResultCode joinResult = code.join(10, TimeUnit.SECONDS);
273384
assertTrue(joinResult.isSuccess());
274385
Mockito.verify(spyOtlpGrpcSpanExporterBuilder, Mockito.times(1))
275-
.setHeaders(headerSupplierCaptor.capture());
386+
.setHeaders(traceHeaderSupplierCaptor.capture());
276387

277388
// assert that the Authorization bearer token header is present
278-
Map<String, String> exportHeaders = headerSupplierCaptor.getValue().get();
389+
Map<String, String> exportHeaders = traceHeaderSupplierCaptor.getValue().get();
279390
assertThat(exportHeaders).containsEntry("Authorization", "Bearer fake");
280391

281392
if (testCase.getExpectedQuotaProjectInHeader() == null) {
@@ -362,7 +473,7 @@ private static Stream<Arguments> provideQuotaBehaviorTestCases() {
362473

363474
// Configure necessary behavior on the Grpc mock exporters to work
364475
// TODO: Potential improvement - make this work for Http exporter as well.
365-
private static void configureGrpcMockExporters(
476+
private static void configureGrpcMockSpanExporters(
366477
OtlpGrpcSpanExporter mockGrpcExporter,
367478
OtlpGrpcSpanExporterBuilder spyGrpcExporterBuilder,
368479
List<SpanData> exportedSpanContainer) {
@@ -430,25 +541,34 @@ private void prepareMockBehaviorForGoogleCredentials() {
430541
}
431542

432543
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(SpanExporter spanExporter) {
433-
return buildOpenTelemetrySdkWithExporter(spanExporter, null, otelProperties);
544+
return buildOpenTelemetrySdkWithExporter(
545+
spanExporter, OtlpHttpMetricExporter.getDefault(), defaultOtelPropertiesSpanExporter);
434546
}
435547

436548
@SuppressWarnings("UnusedMethod")
437-
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(SpanExporter spanExporter, ImmutableMap<String, String> customOTelProperties) {
438-
return buildOpenTelemetrySdkWithExporter(spanExporter, null, customOTelProperties);
549+
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(
550+
SpanExporter spanExporter, ImmutableMap<String, String> customOTelProperties) {
551+
return buildOpenTelemetrySdkWithExporter(
552+
spanExporter, OtlpHttpMetricExporter.getDefault(), customOTelProperties);
439553
}
440554

441555
@SuppressWarnings("UnusedMethod")
442556
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(MetricExporter metricExporter) {
443-
return buildOpenTelemetrySdkWithExporter(null, metricExporter, otelProperties);
557+
return buildOpenTelemetrySdkWithExporter(
558+
OtlpHttpSpanExporter.getDefault(), metricExporter, defaultOtelPropertiesMetricExporter);
444559
}
445560

446561
@SuppressWarnings("UnusedMethod")
447-
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(MetricExporter metricExporter, ImmutableMap<String, String> customOtelProperties) {
448-
return buildOpenTelemetrySdkWithExporter(null, metricExporter, customOtelProperties);
562+
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(
563+
MetricExporter metricExporter, ImmutableMap<String, String> customOtelProperties) {
564+
return buildOpenTelemetrySdkWithExporter(
565+
OtlpHttpSpanExporter.getDefault(), metricExporter, customOtelProperties);
449566
}
450567

451-
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(SpanExporter spanExporter, MetricExporter metricExporter, ImmutableMap<String, String> customOtelProperties) {
568+
private OpenTelemetrySdk buildOpenTelemetrySdkWithExporter(
569+
SpanExporter spanExporter,
570+
MetricExporter metricExporter,
571+
ImmutableMap<String, String> customOtelProperties) {
452572
SpiHelper spiHelper =
453573
SpiHelper.create(GcpAuthAutoConfigurationCustomizerProviderTest.class.getClassLoader());
454574
AutoConfiguredOpenTelemetrySdkBuilder builder =
@@ -514,6 +634,19 @@ private static void generateTestSpan(OpenTelemetrySdk openTelemetrySdk) {
514634
}
515635
}
516636

637+
private static void generateTestMetric(OpenTelemetrySdk openTelemetrySdk) {
638+
LongCounter longCounter =
639+
openTelemetrySdk
640+
.getMeter("test")
641+
.counterBuilder("sample")
642+
.setDescription("sample counter")
643+
.setUnit("1")
644+
.build();
645+
long workOutput = busyloop();
646+
long randomValue = TEST_RANDOM.nextInt(1000);
647+
longCounter.add(randomValue, Attributes.of(AttributeKey.longKey("work_loop"), workOutput));
648+
}
649+
517650
// loop to simulate work done
518651
private static long busyloop() {
519652
Instant start = Instant.now();

0 commit comments

Comments
 (0)