1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package trace
16
17 import (
18 "context"
19 "fmt"
20 "math/rand"
21 "testing"
22
23 "github.com/stretchr/testify/assert"
24 "github.com/stretchr/testify/require"
25
26 "go.opentelemetry.io/otel/trace"
27 )
28
29 func TestParentBasedDefaultLocalParentSampled(t *testing.T) {
30 sampler := ParentBased(AlwaysSample())
31 traceID, _ := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
32 spanID, _ := trace.SpanIDFromHex("00f067aa0ba902b7")
33 parentCtx := trace.ContextWithSpanContext(
34 context.Background(),
35 trace.NewSpanContext(trace.SpanContextConfig{
36 TraceID: traceID,
37 SpanID: spanID,
38 TraceFlags: trace.FlagsSampled,
39 }),
40 )
41 if sampler.ShouldSample(SamplingParameters{ParentContext: parentCtx}).Decision != RecordAndSample {
42 t.Error("Sampling decision should be RecordAndSample")
43 }
44 }
45
46 func TestParentBasedDefaultLocalParentNotSampled(t *testing.T) {
47 sampler := ParentBased(AlwaysSample())
48 traceID, _ := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
49 spanID, _ := trace.SpanIDFromHex("00f067aa0ba902b7")
50 parentCtx := trace.ContextWithSpanContext(
51 context.Background(),
52 trace.NewSpanContext(trace.SpanContextConfig{
53 TraceID: traceID,
54 SpanID: spanID,
55 }),
56 )
57 if sampler.ShouldSample(SamplingParameters{ParentContext: parentCtx}).Decision != Drop {
58 t.Error("Sampling decision should be Drop")
59 }
60 }
61
62 func TestParentBasedWithNoParent(t *testing.T) {
63 params := SamplingParameters{}
64
65 sampler := ParentBased(AlwaysSample())
66 if sampler.ShouldSample(params).Decision != RecordAndSample {
67 t.Error("Sampling decision should be RecordAndSample")
68 }
69
70 sampler = ParentBased(NeverSample())
71 if sampler.ShouldSample(params).Decision != Drop {
72 t.Error("Sampling decision should be Drop")
73 }
74 }
75
76 func TestParentBasedWithSamplerOptions(t *testing.T) {
77 testCases := []struct {
78 name string
79 samplerOption ParentBasedSamplerOption
80 isParentRemote, isParentSampled bool
81 expectedDecision SamplingDecision
82 }{
83 {
84 "localParentSampled",
85 WithLocalParentSampled(NeverSample()),
86 false,
87 true,
88 Drop,
89 },
90 {
91 "localParentNotSampled",
92 WithLocalParentNotSampled(AlwaysSample()),
93 false,
94 false,
95 RecordAndSample,
96 },
97 {
98 "remoteParentSampled",
99 WithRemoteParentSampled(NeverSample()),
100 true,
101 true,
102 Drop,
103 },
104 {
105 "remoteParentNotSampled",
106 WithRemoteParentNotSampled(AlwaysSample()),
107 true,
108 false,
109 RecordAndSample,
110 },
111 }
112
113 for _, tc := range testCases {
114 t.Run(tc.name, func(t *testing.T) {
115 traceID, _ := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
116 spanID, _ := trace.SpanIDFromHex("00f067aa0ba902b7")
117 pscc := trace.SpanContextConfig{
118 TraceID: traceID,
119 SpanID: spanID,
120 Remote: tc.isParentRemote,
121 }
122 if tc.isParentSampled {
123 pscc.TraceFlags = trace.FlagsSampled
124 }
125
126 params := SamplingParameters{
127 ParentContext: trace.ContextWithSpanContext(
128 context.Background(),
129 trace.NewSpanContext(pscc),
130 ),
131 }
132
133 sampler := ParentBased(
134 nil,
135 tc.samplerOption,
136 )
137
138 var wantStr, gotStr string
139 switch tc.expectedDecision {
140 case RecordAndSample:
141 wantStr = "RecordAndSample"
142 case Drop:
143 wantStr = "Drop"
144 default:
145 wantStr = "unknown"
146 }
147
148 actualDecision := sampler.ShouldSample(params).Decision
149 switch actualDecision {
150 case RecordAndSample:
151 gotStr = "RecordAndSample"
152 case Drop:
153 gotStr = "Drop"
154 default:
155 gotStr = "unknown"
156 }
157
158 assert.Equalf(t, tc.expectedDecision, actualDecision, "want %s, got %s", wantStr, gotStr)
159 })
160 }
161 }
162
163 func TestParentBasedDefaultDescription(t *testing.T) {
164 sampler := ParentBased(AlwaysSample())
165
166 expectedDescription := fmt.Sprintf("ParentBased{root:%s,remoteParentSampled:%s,"+
167 "remoteParentNotSampled:%s,localParentSampled:%s,localParentNotSampled:%s}",
168 AlwaysSample().Description(),
169 AlwaysSample().Description(),
170 NeverSample().Description(),
171 AlwaysSample().Description(),
172 NeverSample().Description())
173
174 if sampler.Description() != expectedDescription {
175 t.Errorf("Sampler description should be %s, got '%s' instead",
176 expectedDescription,
177 sampler.Description(),
178 )
179 }
180 }
181
182
183
184
185
186
187 func TestTraceIdRatioSamplesInclusively(t *testing.T) {
188 const (
189 numSamplers = 1000
190 numTraces = 100
191 )
192 idg := defaultIDGenerator()
193
194 for i := 0; i < numSamplers; i++ {
195 ratioLo, ratioHi := rand.Float64(), rand.Float64()
196 if ratioHi < ratioLo {
197 ratioLo, ratioHi = ratioHi, ratioLo
198 }
199 samplerHi := TraceIDRatioBased(ratioHi)
200 samplerLo := TraceIDRatioBased(ratioLo)
201 for j := 0; j < numTraces; j++ {
202 traceID, _ := idg.NewIDs(context.Background())
203
204 params := SamplingParameters{TraceID: traceID}
205 if samplerLo.ShouldSample(params).Decision == RecordAndSample {
206 require.Equal(t, RecordAndSample, samplerHi.ShouldSample(params).Decision,
207 "%s sampled but %s did not", samplerLo.Description(), samplerHi.Description())
208 }
209 }
210 }
211 }
212
213 func TestTracestateIsPassed(t *testing.T) {
214 testCases := []struct {
215 name string
216 sampler Sampler
217 }{
218 {
219 "notSampled",
220 NeverSample(),
221 },
222 {
223 "sampled",
224 AlwaysSample(),
225 },
226 {
227 "parentSampled",
228 ParentBased(AlwaysSample()),
229 },
230 {
231 "parentNotSampled",
232 ParentBased(NeverSample()),
233 },
234 {
235 "traceIDRatioSampler",
236 TraceIDRatioBased(.5),
237 },
238 }
239
240 for _, tc := range testCases {
241 t.Run(tc.name, func(t *testing.T) {
242 traceState, err := trace.ParseTraceState("k=v")
243 if err != nil {
244 t.Error(err)
245 }
246
247 params := SamplingParameters{
248 ParentContext: trace.ContextWithSpanContext(
249 context.Background(),
250 trace.NewSpanContext(trace.SpanContextConfig{
251 TraceState: traceState,
252 }),
253 ),
254 }
255
256 require.Equal(t, traceState, tc.sampler.ShouldSample(params).Tracestate, "TraceState is not equal")
257 })
258 }
259 }
260
View as plain text