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

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package sd
     4  
     5  import (
     6  	"context"
     7  	"errors"
     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/sd/pipeline"
    14  	"github.com/netdata/go.d.plugin/logger"
    15  
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  var lock = &sync.Mutex{}
    20  
    21  type discoverySim struct {
    22  	configs       []ConfigFile
    23  	wantPipelines []*mockPipeline
    24  }
    25  
    26  func (sim *discoverySim) run(t *testing.T) {
    27  	fact := &mockFactory{}
    28  	mgr := &ServiceDiscovery{
    29  		Logger:    logger.New(),
    30  		sdFactory: fact,
    31  		confProv: &mockConfigProvider{
    32  			configs: sim.configs,
    33  			ch:      make(chan ConfigFile),
    34  		},
    35  		confCache: make(map[string]uint64),
    36  		pipelines: make(map[string]func()),
    37  	}
    38  
    39  	in := make(chan<- []*confgroup.Group)
    40  	done := make(chan struct{})
    41  	ctx, cancel := context.WithCancel(context.Background())
    42  
    43  	go func() { defer close(done); mgr.Run(ctx, in) }()
    44  
    45  	time.Sleep(time.Second * 3)
    46  
    47  	lock.Lock()
    48  	assert.Equalf(t, sim.wantPipelines, fact.pipelines, "before stop")
    49  	lock.Unlock()
    50  
    51  	cancel()
    52  
    53  	timeout := time.Second * 5
    54  
    55  	select {
    56  	case <-done:
    57  		lock.Lock()
    58  		for _, pl := range fact.pipelines {
    59  			assert.Truef(t, pl.stopped, "pipeline '%s' is not stopped after cancel()", pl.name)
    60  		}
    61  		lock.Unlock()
    62  	case <-time.After(timeout):
    63  		t.Errorf("sd failed to exit in %s", timeout)
    64  	}
    65  }
    66  
    67  type mockConfigProvider struct {
    68  	configs []ConfigFile
    69  	ch      chan ConfigFile
    70  }
    71  
    72  func (m *mockConfigProvider) Run(ctx context.Context) {
    73  	for _, conf := range m.configs {
    74  		select {
    75  		case <-ctx.Done():
    76  			return
    77  		case m.ch <- conf:
    78  		}
    79  	}
    80  	<-ctx.Done()
    81  }
    82  
    83  func (m *mockConfigProvider) Configs() chan ConfigFile {
    84  	return m.ch
    85  }
    86  
    87  type mockFactory struct {
    88  	pipelines []*mockPipeline
    89  }
    90  
    91  func (m *mockFactory) create(cfg pipeline.Config) (sdPipeline, error) {
    92  	lock.Lock()
    93  	defer lock.Unlock()
    94  
    95  	if cfg.Name == "invalid" {
    96  		return nil, errors.New("mock sdPipelineFactory.create() error")
    97  	}
    98  
    99  	pl := mockPipeline{name: cfg.Name}
   100  	m.pipelines = append(m.pipelines, &pl)
   101  
   102  	return &pl, nil
   103  }
   104  
   105  type mockPipeline struct {
   106  	name    string
   107  	started bool
   108  	stopped bool
   109  }
   110  
   111  func (m *mockPipeline) Run(ctx context.Context, _ chan<- []*confgroup.Group) {
   112  	lock.Lock()
   113  	m.started = true
   114  	lock.Unlock()
   115  	defer func() { lock.Lock(); m.stopped = true; lock.Unlock() }()
   116  	<-ctx.Done()
   117  }