@@ -59,9 +59,53 @@ def initialize(*args)
59
59
end
60
60
61
61
describe '.instance' do
62
+ let ( :instrumentation ) do
63
+ Class . new ( OpenTelemetry ::Instrumentation ::Base ) do
64
+ instrumentation_name 'test_instrumentation'
65
+ instrumentation_version '0.1.1'
66
+
67
+ def initialize ( *args )
68
+ # Simulate latency by hinting the VM should switch tasks
69
+ # (this can also be accomplished by something like `sleep(0.1)`).
70
+ # This replicates the worst-case scenario when using default assignment
71
+ # to obtain a singleton, i.e. that the scheduler switches threads between
72
+ # the nil check and object initialization.
73
+ Thread . pass
74
+ super
75
+ end
76
+ end
77
+ end
78
+
79
+ let ( :other_instrumentation ) do
80
+ aux_instrumentation = instrumentation
81
+ Class . new ( OpenTelemetry ::Instrumentation ::Base ) do
82
+ instrumentation_name 'test_instrumentation'
83
+ instrumentation_version '0.1.1'
84
+
85
+ define_method ( :aux_instrumentation ) { aux_instrumentation }
86
+
87
+ def initialize ( *)
88
+ aux_instrumentation . instance
89
+
90
+ super
91
+ end
92
+ end
93
+ end
94
+
62
95
it 'returns an instance' do
63
96
_ ( instrumentation . instance ) . must_be_instance_of ( instrumentation )
64
97
end
98
+
99
+ it 'returns the same singleton instance to every thread' do
100
+ object_ids = Array . new ( 2 ) . map { Thread . new { instrumentation . instance } }
101
+ . map { |thr | thr . join . value }
102
+
103
+ _ ( object_ids . uniq . count ) . must_equal ( 1 )
104
+ end
105
+
106
+ it 'can refer to other instances in initialize without deadlocking' do
107
+ other_instrumentation . instance
108
+ end
65
109
end
66
110
67
111
describe '.option' do
0 commit comments