6565import java .util .List ;
6666import java .util .Map ;
6767import java .util .Properties ;
68- import java .util .concurrent .ExecutorService ;
69- import java .util .concurrent .Executors ;
70- import java .util .concurrent .Future ;
68+ import java .util .concurrent .CompletableFuture ;
69+ import java .util .concurrent .SynchronousQueue ;
7170import java .util .concurrent .TimeUnit ;
7271import java .util .function .BiFunction ;
7372import java .util .function .Consumer ;
7473import java .util .function .Supplier ;
74+ import org .junit .jupiter .api .Assertions ;
7575import org .junit .jupiter .api .BeforeEach ;
7676import org .junit .jupiter .api .Test ;
7777import org .junit .jupiter .api .extension .ExtendWith ;
@@ -680,13 +680,17 @@ void configurationError_ClosesResources() {
680680 }
681681
682682 @ Test
683- @ SuppressWarnings ("unchecked" )
683+ @ SuppressWarnings ({ "unchecked" , "FutureReturnValueIgnored" } )
684684 void test () throws Exception {
685- AutoConfiguredOpenTelemetrySdkBuilder globalBuilder = builder .setResultAsGlobal ();
686- ExecutorService executor = Executors .newSingleThreadExecutor ();
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 <>();
687693
688- OpenTelemetry gotGetOutput ;
689- AutoConfiguredOpenTelemetrySdk autoConfiguredSdk ;
690694 try (MockedStatic <GlobalOpenTelemetry > mockGot =
691695 Mockito .mockStatic (GlobalOpenTelemetry .class )) {
692696 mockGot .when (GlobalOpenTelemetry ::get ).thenCallRealMethod ();
@@ -695,19 +699,30 @@ void test() throws Exception {
695699 .when (() -> GlobalOpenTelemetry .set (any (OpenTelemetry .class )))
696700 .then (
697701 invocation -> {
698- Thread .sleep (1000 );
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+ }
714+ }
715+ return null ;
716+ });
699717 return invocation .callRealMethod ();
700718 });
701719
702- Future <AutoConfiguredOpenTelemetrySdk > autoConfiguredSdkFuture =
703- executor .submit (globalBuilder ::build );
704- gotGetOutput = GlobalOpenTelemetry .get ();
705- autoConfiguredSdk = autoConfiguredSdkFuture .get ();
706- }
707- assertThat (gotGetOutput )
708- .extracting ("delegate" )
709- .isSameAs (autoConfiguredSdk .getOpenTelemetrySdk ());
720+ AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk =
721+ builder .setResultAsGlobal ().build ();
710722
711- executor .shutdown ();
723+ assertThat (gotGetResult .poll (3 , TimeUnit .SECONDS ))
724+ .extracting ("delegate" )
725+ .isSameAs (autoConfiguredOpenTelemetrySdk .getOpenTelemetrySdk ());
726+ }
712727 }
713728}
0 commit comments