github.com/netdata/go.d.plugin@v0.58.1/agent/discovery/sd/kubernetes/sim_test.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package kubernetes 4 5 import ( 6 "context" 7 "sort" 8 "testing" 9 "time" 10 11 "github.com/netdata/go.d.plugin/agent/discovery/sd/model" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 "k8s.io/client-go/tools/cache" 16 ) 17 18 const ( 19 startWaitTimeout = time.Second * 3 20 finishWaitTimeout = time.Second * 5 21 ) 22 23 type discoverySim struct { 24 td *KubeDiscoverer 25 runAfterSync func(ctx context.Context) 26 sortBeforeVerify bool 27 wantTargetGroups []model.TargetGroup 28 } 29 30 func (sim discoverySim) run(t *testing.T) []model.TargetGroup { 31 t.Helper() 32 require.NotNil(t, sim.td) 33 require.NotEmpty(t, sim.wantTargetGroups) 34 35 in, out := make(chan []model.TargetGroup), make(chan []model.TargetGroup) 36 go sim.collectTargetGroups(t, in, out) 37 38 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 39 defer cancel() 40 go sim.td.Discover(ctx, in) 41 42 select { 43 case <-sim.td.started: 44 case <-time.After(startWaitTimeout): 45 t.Fatalf("td %s filed to start in %s", sim.td.discoverers, startWaitTimeout) 46 } 47 48 synced := cache.WaitForCacheSync(ctx.Done(), sim.td.hasSynced) 49 require.Truef(t, synced, "td %s failed to sync", sim.td.discoverers) 50 51 if sim.runAfterSync != nil { 52 sim.runAfterSync(ctx) 53 } 54 55 groups := <-out 56 57 if sim.sortBeforeVerify { 58 sortTargetGroups(groups) 59 } 60 61 sim.verifyResult(t, groups) 62 return groups 63 } 64 65 func (sim discoverySim) collectTargetGroups(t *testing.T, in, out chan []model.TargetGroup) { 66 var tggs []model.TargetGroup 67 loop: 68 for { 69 select { 70 case inGroups := <-in: 71 if tggs = append(tggs, inGroups...); len(tggs) >= len(sim.wantTargetGroups) { 72 break loop 73 } 74 case <-time.After(finishWaitTimeout): 75 t.Logf("td %s timed out after %s, got %d groups, expected %d, some events are skipped", 76 sim.td.discoverers, finishWaitTimeout, len(tggs), len(sim.wantTargetGroups)) 77 break loop 78 } 79 } 80 out <- tggs 81 } 82 83 func (sim discoverySim) verifyResult(t *testing.T, result []model.TargetGroup) { 84 var expected, actual any 85 86 if len(sim.wantTargetGroups) == len(result) { 87 expected = sim.wantTargetGroups 88 actual = result 89 } else { 90 want := make(map[string]model.TargetGroup) 91 for _, group := range sim.wantTargetGroups { 92 want[group.Source()] = group 93 } 94 got := make(map[string]model.TargetGroup) 95 for _, group := range result { 96 got[group.Source()] = group 97 } 98 expected, actual = want, got 99 } 100 101 assert.Equal(t, expected, actual) 102 } 103 104 type hasSynced interface { 105 hasSynced() bool 106 } 107 108 var ( 109 _ hasSynced = &KubeDiscoverer{} 110 _ hasSynced = &podDiscoverer{} 111 _ hasSynced = &serviceDiscoverer{} 112 ) 113 114 func (d *KubeDiscoverer) hasSynced() bool { 115 for _, disc := range d.discoverers { 116 v, ok := disc.(hasSynced) 117 if !ok || !v.hasSynced() { 118 return false 119 } 120 } 121 return true 122 } 123 124 func (p *podDiscoverer) hasSynced() bool { 125 return p.podInformer.HasSynced() && p.cmapInformer.HasSynced() && p.secretInformer.HasSynced() 126 } 127 128 func (s *serviceDiscoverer) hasSynced() bool { 129 return s.informer.HasSynced() 130 } 131 132 func sortTargetGroups(tggs []model.TargetGroup) { 133 if len(tggs) == 0 { 134 return 135 } 136 sort.Slice(tggs, func(i, j int) bool { return tggs[i].Source() < tggs[j].Source() }) 137 }