@@ -139,6 +139,39 @@ func Test_InitServer_FileStrategy(t *testing.T) {
139
139
})
140
140
}
141
141
142
+ func Test_InitServer_FileStrategyErrors (t * testing.T ) {
143
+ t .Run ("fails when strategy file does not exist" , func (t * testing.T ) {
144
+ fbit := & plugin.Fluentbit {
145
+ Logger : newTestLogger (t ),
146
+ Conf : mapConfigLoader {"mode" : "server" , "server.strategy_file" : "/tmp/non-existent-file.json" },
147
+ }
148
+ plug := & jaegerRemotePlugin {}
149
+ err := plug .Init (context .Background (), fbit )
150
+ assert .Error (t , err )
151
+ })
152
+
153
+ t .Run ("fails when strategy file contains invalid json" , func (t * testing.T ) {
154
+ tmpFile , err := os .CreateTemp ("" , "strategy-*.json" )
155
+ assert .NoError (t , err )
156
+ defer os .Remove (tmpFile .Name ())
157
+ _ , err = tmpFile .Write ([]byte (`{ "invalid-json` ))
158
+ assert .NoError (t , err )
159
+ tmpFile .Close ()
160
+
161
+ fbit := & plugin.Fluentbit {
162
+ Logger : newTestLogger (t ),
163
+ Conf : mapConfigLoader {
164
+ "mode" : "server" ,
165
+ "server.strategy_file" : tmpFile .Name (),
166
+ },
167
+ }
168
+ plug := & jaegerRemotePlugin {}
169
+ err = plug .Init (context .Background (), fbit )
170
+ assert .Error (t , err )
171
+ assert .Contains (t , err .Error (), "could not unmarshal" )
172
+ })
173
+ }
174
+
142
175
func Test_InitClient (t * testing.T ) {
143
176
t .Run ("successfully initializes in client mode" , func (t * testing.T ) {
144
177
ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
@@ -258,6 +291,105 @@ func Test_InitServer_EndToEnd(t *testing.T) {
258
291
}
259
292
}
260
293
294
+ /* Helper function to mock sampling manager client */
295
+
296
+ type mockSamplingClient struct {
297
+ api_v2.SamplingManagerClient
298
+ GetSamplingStrategyFunc func (ctx context.Context , in * api_v2.SamplingStrategyParameters , opts ... grpc.CallOption ) (* api_v2.SamplingStrategyResponse , error )
299
+ }
300
+
301
+ func (m * mockSamplingClient ) GetSamplingStrategy (ctx context.Context , in * api_v2.SamplingStrategyParameters , opts ... grpc.CallOption ) (* api_v2.SamplingStrategyResponse , error ) {
302
+ if m .GetSamplingStrategyFunc != nil {
303
+ return m .GetSamplingStrategyFunc (ctx , in , opts ... )
304
+ }
305
+ return nil , status .Error (codes .Unimplemented , "method GetSamplingStrategy not implemented" )
306
+ }
307
+
308
+ func Test_getAndCacheStrategy_Retry (t * testing.T ) {
309
+ t .Run ("should retry on failure and eventually succeed" , func (t * testing.T ) {
310
+ var callCount int
311
+ mockSuccessStrategy := & api_v2.SamplingStrategyResponse {StrategyType : api_v2 .SamplingStrategyType_PROBABILISTIC }
312
+ mockErr := status .Error (codes .Unavailable , "server not ready" )
313
+
314
+ mockClient := & mockSamplingClient {
315
+ GetSamplingStrategyFunc : func (ctx context.Context , in * api_v2.SamplingStrategyParameters , opts ... grpc.CallOption ) (* api_v2.SamplingStrategyResponse , error ) {
316
+ callCount ++
317
+ if callCount > 2 {
318
+ return mockSuccessStrategy , nil
319
+ }
320
+ return nil , mockErr
321
+ },
322
+ }
323
+
324
+ plug := & jaegerRemotePlugin {
325
+ log : newTestLogger (t ),
326
+ config : & Config {
327
+ ServerRetry : & RetryConfig {
328
+ InitialInterval : 10 * time .Millisecond ,
329
+ MaxInterval : 100 * time .Millisecond ,
330
+ Multiplier : 1.5 ,
331
+ MaxRetry : 5 ,
332
+ },
333
+ },
334
+ server : & serverComponent {
335
+ cache : & samplingStrategyCache {
336
+ strategies : make (map [string ]* cacheEntry ),
337
+ },
338
+ sampler : & remoteSampler {
339
+ client : mockClient ,
340
+ },
341
+ },
342
+ }
343
+
344
+ strategy , err := plug .getAndCacheStrategy (context .Background (), "test-service" )
345
+
346
+ assert .NoError (t , err )
347
+ assert .NotZero (t , strategy )
348
+ assert .Equal (t , mockSuccessStrategy , strategy )
349
+ assert .Equal (t , 3 , callCount , "Expected the client to be called 3 times (2 failures, 1 success)" )
350
+ })
351
+
352
+ t .Run ("should stop retrying if context is cancelled" , func (t * testing.T ) {
353
+ mockErr := status .Error (codes .Unavailable , "server not ready" )
354
+ mockClient := & mockSamplingClient {
355
+ GetSamplingStrategyFunc : func (ctx context.Context , in * api_v2.SamplingStrategyParameters , opts ... grpc.CallOption ) (* api_v2.SamplingStrategyResponse , error ) {
356
+ return nil , mockErr
357
+ },
358
+ }
359
+
360
+ plug := & jaegerRemotePlugin {
361
+ log : newTestLogger (t ),
362
+ config : & Config {
363
+ ServerRetry : & RetryConfig {
364
+ InitialInterval : 50 * time .Millisecond ,
365
+ MaxInterval : 200 * time .Millisecond ,
366
+ Multiplier : 1.5 ,
367
+ MaxRetry : 10 ,
368
+ },
369
+ },
370
+ server : & serverComponent {
371
+ cache : & samplingStrategyCache {
372
+ strategies : make (map [string ]* cacheEntry ),
373
+ },
374
+ sampler : & remoteSampler {
375
+ client : mockClient ,
376
+ },
377
+ },
378
+ }
379
+
380
+ ctx , cancel := context .WithCancel (context .Background ())
381
+
382
+ go func () {
383
+ time .Sleep (20 * time .Millisecond )
384
+ cancel ()
385
+ }()
386
+
387
+ _ , err := plug .getAndCacheStrategy (ctx , "test-service" )
388
+
389
+ assert .Error (t , err )
390
+ })
391
+ }
392
+
261
393
func Test_InitServer_Failure (t * testing.T ) {
262
394
t .Run ("fails if both http and grpc listen addresses are missing" , func (t * testing.T ) {
263
395
ctx , cancel := context .WithTimeout (context .Background (), 1 * time .Second )
@@ -440,6 +572,22 @@ func Test_ServerHandlers(t *testing.T) {
440
572
441
573
assert .Equal (t , http .StatusNotFound , rr .Code )
442
574
})
575
+
576
+ t .Run ("HTTP handler returns 400 Bad Request for missing service" , func (t * testing.T ) {
577
+ req := httptest .NewRequest (http .MethodGet , "/sampling" , nil ) // No service param
578
+ rr := httptest .NewRecorder ()
579
+ plug .handleSampling (rr , req )
580
+ assert .Equal (t , http .StatusBadRequest , rr .Code )
581
+ })
582
+
583
+ t .Run ("gRPC handler returns InvalidArgument for missing service name" , func (t * testing.T ) {
584
+ s := & grpcApiServer {plug : plug }
585
+ params := & api_v2.SamplingStrategyParameters {ServiceName : "" } // Empty service name
586
+ _ , err := s .GetSamplingStrategy (context .Background (), params )
587
+ st , ok := status .FromError (err )
588
+ assert .True (t , ok )
589
+ assert .Equal (t , codes .InvalidArgument , st .Code ())
590
+ })
443
591
}
444
592
445
593
func getFreePort (t * testing.T ) string {
0 commit comments