Skip to content

Commit 8ebb79a

Browse files
fandreuzjack-berg
andauthored
apply suggestion
Co-authored-by: jack-berg <[email protected]>
1 parent f2d9648 commit 8ebb79a

File tree

1 file changed

+57
-44
lines changed

1 file changed

+57
-44
lines changed

sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -680,51 +680,64 @@ void configurationError_ClosesResources() {
680680
}
681681

682682
@Test
683-
@SuppressWarnings({"unchecked", "FutureReturnValueIgnored"})
684-
void test() throws Exception {
685-
// Idea of the test:
686-
// 1. Thread 1 calls AutoConfiguredOpenTelemetrySdkBuilder#build
687-
// 2. It acquires the mutex in GlobalOpenTelemetry.set(Supplier<OpenTelemetry>)
688-
// 3. While holding the mutex before the call to GlobalOpenTelemetry.set(OpenTelemetry),
689-
// it spawns Thread 2 which calls GlobalOpenTelemetry.get
690-
// 4. We test that Thread 2 does not fail, and that its result is the same OpenTelemetry
691-
// instance embedded in the AutoConfiguredOpenTelemetrySdk
692-
SynchronousQueue<OpenTelemetry> gotGetResult = new SynchronousQueue<>();
693-
694-
try (MockedStatic<GlobalOpenTelemetry> mockGot =
695-
Mockito.mockStatic(GlobalOpenTelemetry.class)) {
696-
mockGot.when(GlobalOpenTelemetry::get).thenCallRealMethod();
697-
mockGot.when(() -> GlobalOpenTelemetry.set(any(Supplier.class))).thenCallRealMethod();
698-
mockGot
699-
.when(() -> GlobalOpenTelemetry.set(any(OpenTelemetry.class)))
700-
.then(
701-
invocation -> {
702-
CompletableFuture.supplyAsync(GlobalOpenTelemetry::get)
703-
.handle(
704-
(sdk, exc) -> {
705-
if (exc != null) {
706-
Assertions.fail(exc);
707-
} else {
708-
try {
709-
gotGetResult.put(sdk);
710-
} catch (InterruptedException exception) {
711-
Thread.currentThread().interrupt();
712-
Assertions.fail(exception);
713-
}
683+
void globalOpenTelemetryLock() throws InterruptedException, ExecutionException, TimeoutException {
684+
CountDownLatch autoconfigStarted = new CountDownLatch(1);
685+
CountDownLatch completeAutoconfig = new CountDownLatch(1);
686+
ExecutorService executorService = Executors.newFixedThreadPool(2);
687+
688+
// Submit a future to autoconfigure the SDK and set the result as global. Add a customization
689+
// hook which blocks until we say so.
690+
CompletableFuture<OpenTelemetrySdk> autoConfiguredOpenTelemetryFuture =
691+
CompletableFuture.supplyAsync(
692+
() ->
693+
builder
694+
.addLoggerProviderCustomizer(
695+
(sdkLoggerProviderBuilder, configProperties) -> {
696+
autoconfigStarted.countDown();
697+
try {
698+
completeAutoconfig.await();
699+
} catch (InterruptedException e) {
700+
Thread.currentThread().interrupt();
714701
}
715-
return null;
716-
});
717-
// Give Thread 2 some time to try obtaining the mutex and getting blocked
718-
Thread.sleep(500);
719-
return invocation.callRealMethod();
720-
});
721-
722-
AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk =
723-
builder.setResultAsGlobal().build();
724-
725-
assertThat(gotGetResult.poll(3, TimeUnit.SECONDS))
726-
.extracting("delegate")
727-
.isSameAs(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk());
702+
return sdkLoggerProviderBuilder;
703+
})
704+
.setResultAsGlobal()
705+
.build()
706+
.getOpenTelemetrySdk(),
707+
executorService);
708+
709+
// Wait for autoconfiguration to enter our callback, then try to get an instance of
710+
// GlobalOpenTelemetry. GlobalOpenTelemetry.get() should block until we release the
711+
// completeAutoconfig latch and allow autoconfiguration to complete.
712+
autoconfigStarted.await();
713+
CompletableFuture<OpenTelemetry> globalOpenTelemetryFuture =
714+
CompletableFuture.supplyAsync(GlobalOpenTelemetry::get, executorService);
715+
Thread.sleep(10);
716+
assertThat(globalOpenTelemetryFuture.isDone()).isFalse();
717+
assertThat(autoConfiguredOpenTelemetryFuture.isDone()).isFalse();
718+
719+
// Release the latch, allowing autoconfiguration to complete. Confirm that our
720+
// GlobalOpenTelemetry.get() future resolved to the same instance as autoconfiguration.
721+
completeAutoconfig.countDown();
722+
assertThat(unobfuscate(globalOpenTelemetryFuture.get(10, TimeUnit.SECONDS)))
723+
.isSameAs(autoConfiguredOpenTelemetryFuture.get(10, TimeUnit.SECONDS));
724+
725+
// Cleanup
726+
executorService.shutdown();
727+
autoConfiguredOpenTelemetryFuture.get().shutdown().join(10, TimeUnit.SECONDS);
728+
GlobalOpenTelemetry.resetForTest();
729+
}
730+
731+
private static OpenTelemetry unobfuscate(OpenTelemetry openTelemetry) {
732+
try {
733+
Field delegateField =
734+
Class.forName("io.opentelemetry.api.GlobalOpenTelemetry$ObfuscatedOpenTelemetry")
735+
.getDeclaredField("delegate");
736+
delegateField.setAccessible(true);
737+
Object delegate = delegateField.get(openTelemetry);
738+
return (OpenTelemetry) delegate;
739+
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) {
740+
throw new IllegalStateException("Error unobfuscating OpenTelemetry", e);
728741
}
729742
}
730743
}

0 commit comments

Comments
 (0)