@@ -37,31 +37,218 @@ final class GlobalTracingInstrumentationSystemTests: XCTestCase {
3737 super. tearDown ( )
3838 InstrumentationSystem . bootstrapInternal ( nil )
3939 }
40-
40+
4141 func testItProvidesAccessToATracer( ) {
4242 let tracer = TestTracer ( )
43-
43+
4444 XCTAssertNil ( InstrumentationSystem . _legacyTracer ( of: TestTracer . self) )
4545 XCTAssertNil ( InstrumentationSystem . _tracer ( of: TestTracer . self) )
46-
46+
4747 InstrumentationSystem . bootstrapInternal ( tracer)
4848 XCTAssertFalse ( InstrumentationSystem . instrument is MultiplexInstrument )
4949 XCTAssert ( InstrumentationSystem . _instrument ( of: TestTracer . self) === tracer)
5050 XCTAssertNil ( InstrumentationSystem . _instrument ( of: NoOpInstrument . self) )
51-
51+
5252 XCTAssert ( InstrumentationSystem . _legacyTracer ( of: TestTracer . self) === tracer)
5353 XCTAssert ( InstrumentationSystem . legacyTracer is TestTracer )
5454 XCTAssert ( InstrumentationSystem . _tracer ( of: TestTracer . self) === tracer)
5555 XCTAssert ( InstrumentationSystem . tracer is TestTracer )
56-
56+
5757 let multiplexInstrument = MultiplexInstrument ( [ tracer] )
5858 InstrumentationSystem . bootstrapInternal ( multiplexInstrument)
5959 XCTAssert ( InstrumentationSystem . instrument is MultiplexInstrument )
6060 XCTAssert ( InstrumentationSystem . _instrument ( of: TestTracer . self) === tracer)
61-
61+
6262 XCTAssert ( InstrumentationSystem . _legacyTracer ( of: TestTracer . self) === tracer)
6363 XCTAssert ( InstrumentationSystem . legacyTracer is TestTracer )
6464 XCTAssert ( InstrumentationSystem . _tracer ( of: TestTracer . self) === tracer)
6565 XCTAssert ( InstrumentationSystem . tracer is TestTracer )
6666 }
6767}
68+
69+ final class GlobalTracingMethodsTests : XCTestCase {
70+ override class func tearDown( ) {
71+ super. tearDown ( )
72+ InstrumentationSystem . bootstrapInternal ( nil )
73+ }
74+
75+ func testGlobalTracingMethods( ) async {
76+ // Bootstrap with TestTracer to capture spans
77+ let tracer = TestTracer ( )
78+ InstrumentationSystem . bootstrapInternal ( tracer)
79+
80+ // Create custom timestamps for testing
81+ let clock = DefaultTracerClock ( )
82+ let customInstant1 = clock. now
83+ let customInstant2 = clock. now
84+ let customInstant3 = clock. now
85+
86+ // Create custom contexts to verify they're preserved
87+ var customContext1 = ServiceContext . topLevel
88+ customContext1 [ TestContextKey . self] = " context1 "
89+
90+ var customContext2 = ServiceContext . topLevel
91+ customContext2 [ TestContextKey . self] = " context2 "
92+
93+ // Test 1: startSpan with custom instant
94+ let span1 = startSpan (
95+ " startSpan-with-instant " ,
96+ at: customInstant1,
97+ context: customContext1,
98+ ofKind: . client
99+ )
100+ span1. end ( )
101+
102+ // Test 2: startSpan without instant (uses default)
103+ let span2 = startSpan (
104+ " startSpan-default-instant " ,
105+ context: customContext2,
106+ ofKind: . server
107+ )
108+ span2. end ( )
109+
110+ // Test 3: startSpan with instant (different parameter order)
111+ let span3 = startSpan (
112+ " startSpan-instant-alt " ,
113+ context: . topLevel,
114+ ofKind: . producer,
115+ at: customInstant2
116+ )
117+ span3. end ( )
118+
119+ // Test 4: withSpan synchronous with custom instant
120+ let result1 = withSpan (
121+ " withSpan-sync-instant " ,
122+ at: customInstant3,
123+ context: customContext1,
124+ ofKind: . consumer
125+ ) { span -> String in
126+ XCTAssertEqual ( span. operationName, " withSpan-sync-instant " )
127+ return " sync-result "
128+ }
129+ XCTAssertEqual ( result1, " sync-result " )
130+
131+ // Test 5: withSpan synchronous without instant
132+ let result2 = withSpan (
133+ " withSpan-sync-default " ,
134+ context: customContext2,
135+ ofKind: . internal
136+ ) { span -> Int in
137+ XCTAssertEqual ( span. operationName, " withSpan-sync-default " )
138+ return 42
139+ }
140+ XCTAssertEqual ( result2, 42 )
141+
142+ // Test 6: withSpan synchronous with instant (alt parameter order)
143+ let result3 = withSpan (
144+ " withSpan-sync-instant-alt " ,
145+ context: . topLevel,
146+ ofKind: . server,
147+ at: clock. now
148+ ) { _ in
149+ " alt-result "
150+ }
151+ XCTAssertEqual ( result3, " alt-result " )
152+
153+ // Test 7: withSpan async with custom instant and isolation
154+ let result4 = await withSpan (
155+ " withSpan-async-instant-isolation " ,
156+ at: clock. now,
157+ context: customContext1,
158+ ofKind: . client,
159+ isolation: nil
160+ ) { span -> String in
161+ XCTAssertEqual ( span. operationName, " withSpan-async-instant-isolation " )
162+ return " async-result "
163+ }
164+ XCTAssertEqual ( result4, " async-result " )
165+
166+ // Test 8: withSpan async without instant but with isolation
167+ let result5 = await withSpan (
168+ " withSpan-async-default-isolation " ,
169+ context: customContext2,
170+ ofKind: . producer,
171+ isolation: nil
172+ ) { span -> Bool in
173+ XCTAssertEqual ( span. operationName, " withSpan-async-default-isolation " )
174+ return true
175+ }
176+ XCTAssertEqual ( result5, true )
177+
178+ // Test 9: withSpan async with instant, isolation (alt parameter order)
179+ let result6 = await withSpan (
180+ " withSpan-async-instant-isolation-alt " ,
181+ context: . topLevel,
182+ ofKind: . consumer,
183+ at: clock. now,
184+ isolation: nil
185+ ) { _ in
186+ 99
187+ }
188+ XCTAssertEqual ( result6, 99 )
189+
190+ // Verify all spans were recorded with correct properties
191+ let finishedSpans = tracer. spans
192+ XCTAssertEqual ( finishedSpans. count, 9 , " Expected 9 finished spans " )
193+
194+ // Verify span 1: startSpan with custom instant
195+ let recorded1 = finishedSpans [ 0 ]
196+ XCTAssertEqual ( recorded1. operationName, " startSpan-with-instant " )
197+ XCTAssertEqual ( recorded1. kind, . client)
198+ XCTAssertEqual ( recorded1. context [ TestContextKey . self] , " context1 " )
199+ XCTAssertEqual ( recorded1. startTimestampNanosSinceEpoch, customInstant1. nanosecondsSinceEpoch)
200+
201+ // Verify span 2: startSpan without instant
202+ let recorded2 = finishedSpans [ 1 ]
203+ XCTAssertEqual ( recorded2. operationName, " startSpan-default-instant " )
204+ XCTAssertEqual ( recorded2. kind, . server)
205+ XCTAssertEqual ( recorded2. context [ TestContextKey . self] , " context2 " )
206+ // Note: Can't verify exact instant since it used DefaultTracerClock.now
207+
208+ // Verify span 3: startSpan with instant (alt)
209+ let recorded3 = finishedSpans [ 2 ]
210+ XCTAssertEqual ( recorded3. operationName, " startSpan-instant-alt " )
211+ XCTAssertEqual ( recorded3. kind, . producer)
212+ XCTAssertEqual ( recorded3. startTimestampNanosSinceEpoch, customInstant2. nanosecondsSinceEpoch)
213+
214+ // Verify span 4: withSpan sync with instant
215+ let recorded4 = finishedSpans [ 3 ]
216+ XCTAssertEqual ( recorded4. operationName, " withSpan-sync-instant " )
217+ XCTAssertEqual ( recorded4. kind, . consumer)
218+ XCTAssertEqual ( recorded4. context [ TestContextKey . self] , " context1 " )
219+ XCTAssertEqual ( recorded4. startTimestampNanosSinceEpoch, customInstant3. nanosecondsSinceEpoch)
220+
221+ // Verify span 5: withSpan sync without instant
222+ let recorded5 = finishedSpans [ 4 ]
223+ XCTAssertEqual ( recorded5. operationName, " withSpan-sync-default " )
224+ XCTAssertEqual ( recorded5. kind, . internal)
225+ XCTAssertEqual ( recorded5. context [ TestContextKey . self] , " context2 " )
226+
227+ // Verify span 6: withSpan sync with instant (alt)
228+ let recorded6 = finishedSpans [ 5 ]
229+ XCTAssertEqual ( recorded6. operationName, " withSpan-sync-instant-alt " )
230+ XCTAssertEqual ( recorded6. kind, . server)
231+
232+ // Verify span 7: withSpan async with instant and isolation
233+ let recorded7 = finishedSpans [ 6 ]
234+ XCTAssertEqual ( recorded7. operationName, " withSpan-async-instant-isolation " )
235+ XCTAssertEqual ( recorded7. kind, . client)
236+ XCTAssertEqual ( recorded7. context [ TestContextKey . self] , " context1 " )
237+
238+ // Verify span 8: withSpan async without instant but with isolation
239+ let recorded8 = finishedSpans [ 7 ]
240+ XCTAssertEqual ( recorded8. operationName, " withSpan-async-default-isolation " )
241+ XCTAssertEqual ( recorded8. kind, . producer)
242+ XCTAssertEqual ( recorded8. context [ TestContextKey . self] , " context2 " )
243+
244+ // Verify span 9: withSpan async with instant and isolation (alt)
245+ let recorded9 = finishedSpans [ 8 ]
246+ XCTAssertEqual ( recorded9. operationName, " withSpan-async-instant-isolation-alt " )
247+ XCTAssertEqual ( recorded9. kind, . consumer)
248+ }
249+ }
250+
251+ // Test context key for verification
252+ private enum TestContextKey : ServiceContextKey {
253+ typealias Value = String
254+ }
0 commit comments