@@ -14,6 +14,7 @@ import (
14
14
15
15
"github.com/stretchr/testify/assert"
16
16
"github.com/stretchr/testify/mock"
17
+ "github.com/stretchr/testify/require"
17
18
"google.golang.org/protobuf/proto"
18
19
19
20
"github.com/open-telemetry/opamp-go/client/internal"
@@ -311,3 +312,124 @@ func TestRedirectHTTP(t *testing.T) {
311
312
})
312
313
}
313
314
}
315
+
316
+ func TestHTTPReportsAvailableComponents (t * testing.T ) {
317
+ testCases := []struct {
318
+ desc string
319
+ capabilities protobufs.AgentCapabilities
320
+ availableComponents * protobufs.AvailableComponents
321
+ startErr error
322
+ }{
323
+ {
324
+ desc : "Does not report AvailableComponents" ,
325
+ availableComponents : nil ,
326
+ },
327
+ {
328
+ desc : "Reports AvailableComponents" ,
329
+ capabilities : protobufs .AgentCapabilities_AgentCapabilities_ReportsAvailableComponents ,
330
+ availableComponents : generateTestAvailableComponents (),
331
+ },
332
+ {
333
+ desc : "No AvailableComponents on Start() despite capability" ,
334
+ capabilities : protobufs .AgentCapabilities_AgentCapabilities_ReportsAvailableComponents ,
335
+ startErr : internal .ErrAvailableComponentsMissing ,
336
+ },
337
+ }
338
+
339
+ for _ , tc := range testCases {
340
+ t .Run (tc .desc , func (t * testing.T ) {
341
+ // Start a Server.
342
+ srv := internal .StartMockServer (t )
343
+ var rcvCounter atomic.Uint64
344
+ srv .OnMessage = func (msg * protobufs.AgentToServer ) * protobufs.ServerToAgent {
345
+ assert .EqualValues (t , rcvCounter .Load (), msg .SequenceNum )
346
+ rcvCounter .Add (1 )
347
+ time .Sleep (50 * time .Millisecond )
348
+ if rcvCounter .Load () == 1 {
349
+ resp := & protobufs.ServerToAgent {
350
+ InstanceUid : msg .InstanceUid ,
351
+ }
352
+
353
+ if tc .availableComponents != nil {
354
+ // the first message received should contain just the available component hash
355
+ availableComponents := msg .GetAvailableComponents ()
356
+ require .NotNil (t , availableComponents )
357
+ require .Nil (t , availableComponents .GetComponents ())
358
+ require .Equal (t , tc .availableComponents .GetHash (), availableComponents .GetHash ())
359
+
360
+ // add the flag asking for the full available component state to the response
361
+ resp .Flags = uint64 (protobufs .ServerToAgentFlags_ServerToAgentFlags_ReportAvailableComponents )
362
+ } else {
363
+ require .Nil (t , msg .GetAvailableComponents ())
364
+ }
365
+
366
+ return resp
367
+ }
368
+
369
+ if rcvCounter .Load () == 2 {
370
+ if tc .availableComponents != nil {
371
+ // the second message received should contain the full component state
372
+ availableComponents := msg .GetAvailableComponents ()
373
+ require .NotNil (t , availableComponents )
374
+ require .Equal (t , tc .availableComponents .GetComponents (), availableComponents .GetComponents ())
375
+ require .Equal (t , tc .availableComponents .GetHash (), availableComponents .GetHash ())
376
+ } else {
377
+ require .Nil (t , msg .GetAvailableComponents ())
378
+ }
379
+
380
+ return nil
381
+ }
382
+
383
+ // all subsequent messages should not have any available components
384
+ require .Nil (t , msg .GetAvailableComponents ())
385
+ return nil
386
+ }
387
+
388
+ // Start a client.
389
+ settings := types.StartSettings {}
390
+ settings .OpAMPServerURL = "http://" + srv .Endpoint
391
+ settings .Capabilities = tc .capabilities
392
+
393
+ client := NewHTTP (nil )
394
+ client .SetAvailableComponents (tc .availableComponents )
395
+ prepareClient (t , & settings , client )
396
+
397
+ startErr := client .Start (context .Background (), settings )
398
+ if tc .startErr == nil {
399
+ assert .NoError (t , startErr )
400
+ } else {
401
+ assert .ErrorIs (t , startErr , tc .startErr )
402
+ return
403
+ }
404
+
405
+ // Verify that status report is delivered.
406
+ eventually (t , func () bool {
407
+ return rcvCounter .Load () == 1
408
+ })
409
+
410
+ if tc .availableComponents != nil {
411
+ // Verify that status report is delivered again. Polling should ensure this.
412
+ eventually (t , func () bool {
413
+ return rcvCounter .Load () == 2
414
+ })
415
+ } else {
416
+ // Verify that no second status report is delivered (polling is too infrequent for this to happen in 50ms)
417
+ assert .Never (t , func () bool {
418
+ return rcvCounter .Load () == 2
419
+ }, 50 * time .Millisecond , 10 * time .Millisecond )
420
+ }
421
+
422
+ // Verify that no third status report is delivered (polling is too infrequent for this to happen in 50ms)
423
+ assert .Never (t , func () bool {
424
+ return rcvCounter .Load () == 3
425
+ }, 50 * time .Millisecond , 10 * time .Millisecond )
426
+
427
+ // Shutdown the Server.
428
+ srv .Close ()
429
+
430
+ // Shutdown the client.
431
+ err := client .Stop (context .Background ())
432
+ assert .NoError (t , err )
433
+ })
434
+ }
435
+ }
0 commit comments