16
16
@_spi ( Locking) import Instrumentation
17
17
import Testing
18
18
import Tracing
19
- import InMemoryTracing
19
+ @ _spi ( Testing ) import InMemoryTracing
20
20
21
21
@Suite ( " InMemoryTracer " )
22
22
struct InMemoryTracerTests {
@@ -353,95 +353,26 @@ struct InMemoryTracerTests {
353
353
}
354
354
}
355
355
356
- #if compiler(>=6.2) // Exit tests require Swift 6.2
357
- @Suite ( " TestSpan can't be mutated after being ended " )
358
- struct FinishedSpanImmutability {
359
- @Test ( " Operation name is immutable on ended span " )
360
- func operationName( ) async {
361
- await #expect( processExitsWith: . failure) {
362
- let span = InMemorySpan . stub
363
- span. operationName = " ✅ "
364
-
365
- span. end ( )
366
-
367
- span. operationName = " 💥 "
368
- }
369
- }
370
-
371
- @Test ( " Attributes are immutable on ended span " )
372
- func attributes( ) async {
373
- await #expect( processExitsWith: . failure) {
374
- let span = InMemorySpan . stub
375
- span. attributes [ " before " ] = " ✅ "
376
-
377
- span. end ( )
378
-
379
- span. attributes [ " after " ] = " 💥 "
356
+ @Test ( " Span can't be ended repeatedly " )
357
+ func inMemoryDoubleEnd( ) async {
358
+ let endCounter = LockedValueBox < Int > ( 0 )
359
+ let span = InMemorySpan . stub { finished in
360
+ endCounter. withValue { counter in
361
+ counter += 1
362
+ #expect( counter < 2 , " Must not end() a span multiple times. " )
380
363
}
381
364
}
365
+ span. setStatus ( SpanStatus ( code: . ok) )
382
366
383
- @Test ( " Events are immutable on ended span " )
384
- func events( ) async {
385
- await #expect( processExitsWith: . failure) {
386
- let span = InMemorySpan . stub
387
- span. addEvent ( " ✅ " )
388
-
389
- span. end ( )
390
-
391
- span. addEvent ( " 💥 " )
392
- }
393
- }
394
-
395
- @Test ( " Links are immutable on ended span " )
396
- func links( ) async {
397
- await #expect( processExitsWith: . failure) {
398
- let span = InMemorySpan . stub
399
- span. addLink ( . stub)
400
-
401
- span. end ( )
367
+ let clock = MockClock ( )
368
+ clock. setTime ( 111 )
369
+ span. end ( )
402
370
403
- span. addLink ( . stub)
404
- }
405
- }
406
-
407
- @Test ( " Errors are immutable on ended span " )
408
- func errors( ) async {
409
- await #expect( processExitsWith: . failure) {
410
- struct TestError : Error { }
411
- let span = InMemorySpan . stub
412
- span. recordError ( TestError ( ) )
413
-
414
- span. end ( )
415
-
416
- span. recordError ( TestError ( ) )
417
- }
418
- }
419
-
420
- @Test ( " Status is immutable on ended span " )
421
- func status( ) async {
422
- await #expect( processExitsWith: . failure) {
423
- let span = InMemorySpan . stub
424
- span. setStatus ( SpanStatus ( code: . ok) )
425
-
426
- span. end ( )
427
-
428
- span. setStatus ( SpanStatus ( code: . error) )
429
- }
430
- }
371
+ clock. setTime ( 222 )
372
+ span. end ( at: clock. now) // should not blow up, but also, not update time again
431
373
432
- @Test ( " Span can't be ended repeatedly " )
433
- func end( ) async {
434
- await #expect( processExitsWith: . failure) {
435
- let span = InMemorySpan . stub
436
- span. setStatus ( SpanStatus ( code: . ok) )
437
-
438
- span. end ( )
439
-
440
- span. end ( )
441
- }
442
- }
374
+ #expect( endCounter. withValue { $0 } == 1 )
443
375
}
444
- #endif
445
376
}
446
377
447
378
extension InMemorySpan {
@@ -455,6 +386,17 @@ extension InMemorySpan {
455
386
onEnd: { _ in }
456
387
)
457
388
}
389
+
390
+ fileprivate static func stub( onEnd: @Sendable @escaping ( FinishedInMemorySpan ) -> ( ) ) -> InMemorySpan {
391
+ InMemorySpan (
392
+ operationName: " stub " ,
393
+ context: . topLevel,
394
+ spanContext: InMemorySpanContext ( traceID: " stub " , spanID: " stub " , parentSpanID: nil ) ,
395
+ kind: . internal,
396
+ startInstant: DefaultTracerClock ( ) . now,
397
+ onEnd: onEnd
398
+ )
399
+ }
458
400
}
459
401
460
402
private struct DictionaryInjector : Injector {
@@ -472,4 +414,26 @@ private struct DictionaryExtractor: Extractor {
472
414
private struct UnrelatedContextKey : ServiceContextKey {
473
415
typealias Value = Int
474
416
}
417
+
418
+ final class MockClock {
419
+ var _now : UInt64 = 0
420
+
421
+ init ( ) { }
422
+
423
+ func setTime( _ time: UInt64 ) {
424
+ self . _now = time
425
+ }
426
+
427
+ struct Instant : TracerInstant {
428
+ var nanosecondsSinceEpoch : UInt64
429
+ static func < ( lhs: MockClock . Instant , rhs: MockClock . Instant ) -> Bool {
430
+ lhs. nanosecondsSinceEpoch < rhs. nanosecondsSinceEpoch
431
+ }
432
+ }
433
+
434
+ var now : Instant {
435
+ Instant ( nanosecondsSinceEpoch: self . _now)
436
+ }
437
+ }
438
+
475
439
#endif
0 commit comments