github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/changestream/worker_test.go (about)

     1  // Copyright 2023 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  package changestream
     4  
     5  import (
     6  	"time"
     7  
     8  	"github.com/juju/clock"
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	"github.com/juju/worker/v3"
    12  	"github.com/juju/worker/v3/workertest"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	coredatabase "github.com/juju/juju/core/database"
    16  	"github.com/juju/juju/testing"
    17  )
    18  
    19  type workerSuite struct {
    20  	baseSuite
    21  }
    22  
    23  var _ = gc.Suite(&workerSuite{})
    24  
    25  func (s *workerSuite) TestValidateConfig(c *gc.C) {
    26  	defer s.setupMocks(c).Finish()
    27  
    28  	cfg := s.getConfig()
    29  	c.Check(cfg.Validate(), jc.ErrorIsNil)
    30  
    31  	cfg.Clock = nil
    32  	c.Check(errors.Is(cfg.Validate(), errors.NotValid), jc.IsTrue)
    33  
    34  	cfg = s.getConfig()
    35  	cfg.Logger = nil
    36  	c.Check(errors.Is(cfg.Validate(), errors.NotValid), jc.IsTrue)
    37  
    38  	cfg = s.getConfig()
    39  	cfg.DBGetter = nil
    40  	c.Check(errors.Is(cfg.Validate(), errors.NotValid), jc.IsTrue)
    41  
    42  	cfg = s.getConfig()
    43  	cfg.FileNotifyWatcher = nil
    44  	c.Check(errors.Is(cfg.Validate(), errors.NotValid), jc.IsTrue)
    45  
    46  	cfg = s.getConfig()
    47  	cfg.NewEventQueueWorker = nil
    48  	c.Check(errors.Is(cfg.Validate(), errors.NotValid), jc.IsTrue)
    49  }
    50  
    51  func (s *workerSuite) getConfig() WorkerConfig {
    52  	return WorkerConfig{
    53  		DBGetter:          s.dbGetter,
    54  		FileNotifyWatcher: s.fileNotifyWatcher,
    55  		Clock:             s.clock,
    56  		Logger:            s.logger,
    57  		NewEventQueueWorker: func(coredatabase.TrackedDB, FileNotifier, clock.Clock, Logger) (EventQueueWorker, error) {
    58  			return nil, nil
    59  		},
    60  	}
    61  }
    62  
    63  func (s *workerSuite) TestEventQueue(c *gc.C) {
    64  	defer s.setupMocks(c).Finish()
    65  
    66  	s.expectAnyLogs()
    67  	s.expectClock()
    68  
    69  	s.dbGetter.EXPECT().GetDB("controller").Return(s.TrackedDB(), nil)
    70  	s.eventQueueWorker.EXPECT().EventQueue().Return(s.eventQueue)
    71  	s.eventQueueWorker.EXPECT().Kill().AnyTimes()
    72  	s.eventQueueWorker.EXPECT().Wait().MinTimes(1)
    73  
    74  	w := s.newWorker(c, 1)
    75  	defer workertest.DirtyKill(c, w)
    76  
    77  	stream, ok := w.(ChangeStream)
    78  	c.Assert(ok, jc.IsTrue, gc.Commentf("worker does not implement ChangeStream"))
    79  
    80  	_, err := stream.EventQueue("controller")
    81  	c.Assert(err, jc.ErrorIsNil)
    82  
    83  	workertest.CleanKill(c, w)
    84  }
    85  
    86  func (s *workerSuite) TestEventQueueCalledTwice(c *gc.C) {
    87  	defer s.setupMocks(c).Finish()
    88  
    89  	s.expectAnyLogs()
    90  	s.expectClock()
    91  
    92  	done := make(chan struct{})
    93  
    94  	s.dbGetter.EXPECT().GetDB("controller").Return(s.TrackedDB(), nil)
    95  	s.eventQueueWorker.EXPECT().EventQueue().Return(s.eventQueue).Times(2)
    96  	s.eventQueueWorker.EXPECT().Kill().AnyTimes()
    97  	s.eventQueueWorker.EXPECT().Wait().DoAndReturn(func() error {
    98  		select {
    99  		case <-done:
   100  		case <-time.After(testing.LongWait):
   101  			c.Fatal("timed out waiting for Wait to be called")
   102  		}
   103  		return nil
   104  	})
   105  
   106  	w := s.newWorker(c, 1)
   107  	defer workertest.DirtyKill(c, w)
   108  
   109  	stream, ok := w.(ChangeStream)
   110  	c.Assert(ok, jc.IsTrue, gc.Commentf("worker does not implement ChangeStream"))
   111  
   112  	// Ensure that the event queue is only created once.
   113  	_, err := stream.EventQueue("controller")
   114  	c.Assert(err, jc.ErrorIsNil)
   115  
   116  	_, err = stream.EventQueue("controller")
   117  	c.Assert(err, jc.ErrorIsNil)
   118  
   119  	close(done)
   120  
   121  	workertest.CleanKill(c, w)
   122  }
   123  
   124  func (s *workerSuite) newWorker(c *gc.C, attempts int) worker.Worker {
   125  	cfg := WorkerConfig{
   126  		DBGetter:          s.dbGetter,
   127  		FileNotifyWatcher: s.fileNotifyWatcher,
   128  		Clock:             s.clock,
   129  		Logger:            s.logger,
   130  		NewEventQueueWorker: func(coredatabase.TrackedDB, FileNotifier, clock.Clock, Logger) (EventQueueWorker, error) {
   131  			attempts--
   132  			if attempts < 0 {
   133  				c.Fatal("NewEventQueueWorker called too many times")
   134  			}
   135  			return s.eventQueueWorker, nil
   136  		},
   137  	}
   138  
   139  	w, err := newWorker(cfg)
   140  	c.Assert(err, jc.ErrorIsNil)
   141  	return w
   142  }