github.com/netdata/go.d.plugin@v0.58.1/agent/discovery/manager_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package discovery
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/netdata/go.d.plugin/agent/confgroup"
    13  	"github.com/netdata/go.d.plugin/agent/discovery/file"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestNewManager(t *testing.T) {
    19  	tests := map[string]struct {
    20  		cfg     Config
    21  		wantErr bool
    22  	}{
    23  		"valid config": {
    24  			cfg: Config{
    25  				Registry: confgroup.Registry{"module1": confgroup.Default{}},
    26  				File:     file.Config{Read: []string{"path"}},
    27  			},
    28  		},
    29  		"invalid config, registry not set": {
    30  			cfg: Config{
    31  				File: file.Config{Read: []string{"path"}},
    32  			},
    33  			wantErr: true,
    34  		},
    35  		"invalid config, discoverers not set": {
    36  			cfg: Config{
    37  				Registry: confgroup.Registry{"module1": confgroup.Default{}},
    38  			},
    39  			wantErr: true,
    40  		},
    41  	}
    42  
    43  	for name, test := range tests {
    44  		t.Run(name, func(t *testing.T) {
    45  			mgr, err := NewManager(test.cfg)
    46  
    47  			if test.wantErr {
    48  				assert.Error(t, err)
    49  			} else {
    50  				require.NoError(t, err)
    51  				assert.NotNil(t, mgr)
    52  			}
    53  		})
    54  	}
    55  }
    56  
    57  func TestManager_Run(t *testing.T) {
    58  	tests := map[string]func() discoverySim{
    59  		"several discoverers, unique groups with delayed collect": func() discoverySim {
    60  			const numGroups, numCfgs = 2, 2
    61  			d1 := prepareMockDiscoverer("test1", numGroups, numCfgs)
    62  			d2 := prepareMockDiscoverer("test2", numGroups, numCfgs)
    63  			mgr := prepareManager(d1, d2)
    64  			expected := combineGroups(d1.groups, d2.groups)
    65  
    66  			sim := discoverySim{
    67  				mgr:            mgr,
    68  				collectDelay:   mgr.sendEvery + time.Second,
    69  				expectedGroups: expected,
    70  			}
    71  			return sim
    72  		},
    73  		"several discoverers, unique groups": func() discoverySim {
    74  			const numGroups, numCfgs = 2, 2
    75  			d1 := prepareMockDiscoverer("test1", numGroups, numCfgs)
    76  			d2 := prepareMockDiscoverer("test2", numGroups, numCfgs)
    77  			mgr := prepareManager(d1, d2)
    78  			expected := combineGroups(d1.groups, d2.groups)
    79  			sim := discoverySim{
    80  				mgr:            mgr,
    81  				expectedGroups: expected,
    82  			}
    83  			return sim
    84  		},
    85  		"several discoverers, same groups": func() discoverySim {
    86  			const numGroups, numTargets = 2, 2
    87  			d1 := prepareMockDiscoverer("test1", numGroups, numTargets)
    88  			mgr := prepareManager(d1, d1)
    89  			expected := combineGroups(d1.groups)
    90  
    91  			sim := discoverySim{
    92  				mgr:            mgr,
    93  				expectedGroups: expected,
    94  			}
    95  			return sim
    96  		},
    97  		"several discoverers, empty groups": func() discoverySim {
    98  			const numGroups, numCfgs = 1, 0
    99  			d1 := prepareMockDiscoverer("test1", numGroups, numCfgs)
   100  			d2 := prepareMockDiscoverer("test2", numGroups, numCfgs)
   101  			mgr := prepareManager(d1, d2)
   102  			expected := combineGroups(d1.groups, d2.groups)
   103  
   104  			sim := discoverySim{
   105  				mgr:            mgr,
   106  				expectedGroups: expected,
   107  			}
   108  			return sim
   109  		},
   110  		"several discoverers, nil groups": func() discoverySim {
   111  			const numGroups, numCfgs = 0, 0
   112  			d1 := prepareMockDiscoverer("test1", numGroups, numCfgs)
   113  			d2 := prepareMockDiscoverer("test2", numGroups, numCfgs)
   114  			mgr := prepareManager(d1, d2)
   115  
   116  			sim := discoverySim{
   117  				mgr:            mgr,
   118  				expectedGroups: nil,
   119  			}
   120  			return sim
   121  		},
   122  	}
   123  
   124  	for name, sim := range tests {
   125  		t.Run(name, func(t *testing.T) { sim().run(t) })
   126  	}
   127  }
   128  
   129  func prepareMockDiscoverer(source string, groups, configs int) mockDiscoverer {
   130  	d := mockDiscoverer{}
   131  
   132  	for i := 0; i < groups; i++ {
   133  		group := confgroup.Group{
   134  			Source: fmt.Sprintf("%s_group_%d", source, i+1),
   135  		}
   136  		for j := 0; j < configs; j++ {
   137  			group.Configs = append(group.Configs,
   138  				confgroup.Config{"name": fmt.Sprintf("%s_group_%d_target_%d", source, i+1, j+1)})
   139  		}
   140  		d.groups = append(d.groups, &group)
   141  	}
   142  	return d
   143  }
   144  
   145  func prepareManager(discoverers ...discoverer) *Manager {
   146  	mgr := &Manager{
   147  		send:        make(chan struct{}, 1),
   148  		sendEvery:   2 * time.Second,
   149  		discoverers: discoverers,
   150  		cache:       newCache(),
   151  		mux:         &sync.RWMutex{},
   152  	}
   153  	return mgr
   154  }
   155  
   156  type mockDiscoverer struct {
   157  	groups []*confgroup.Group
   158  }
   159  
   160  func (md mockDiscoverer) Run(ctx context.Context, out chan<- []*confgroup.Group) {
   161  	for {
   162  		select {
   163  		case <-ctx.Done():
   164  			return
   165  		case out <- md.groups:
   166  			return
   167  		}
   168  	}
   169  }
   170  
   171  func combineGroups(groups ...[]*confgroup.Group) (combined []*confgroup.Group) {
   172  	for _, set := range groups {
   173  		combined = append(combined, set...)
   174  	}
   175  	return combined
   176  }