github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/meterstatus/isolated_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package meterstatus_test
     5  
     6  import (
     7  	"fmt"
     8  	"path"
     9  	"time"
    10  
    11  	"github.com/juju/clock/testclock"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/loggo"
    14  	"github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	"github.com/juju/worker/v3"
    17  	"github.com/juju/worker/v3/workertest"
    18  	gc "gopkg.in/check.v1"
    19  
    20  	coretesting "github.com/juju/juju/testing"
    21  	"github.com/juju/juju/worker/common/charmrunner"
    22  	"github.com/juju/juju/worker/meterstatus"
    23  )
    24  
    25  const (
    26  	AmberGracePeriod = time.Minute
    27  	RedGracePeriod   = time.Minute * 5
    28  )
    29  
    30  type IsolatedWorkerConfigSuite struct {
    31  	coretesting.BaseSuite
    32  
    33  	config meterstatus.IsolatedConfig
    34  }
    35  
    36  var _ = gc.Suite(&IsolatedWorkerConfigSuite{})
    37  
    38  func (s *IsolatedWorkerConfigSuite) SetUpTest(c *gc.C) {
    39  	s.BaseSuite.SetUpTest(c)
    40  	s.config = meterstatus.IsolatedConfig{
    41  		Runner:           struct{ meterstatus.HookRunner }{},
    42  		StateReadWriter:  struct{ meterstatus.StateReadWriter }{},
    43  		Clock:            struct{ meterstatus.Clock }{},
    44  		Logger:           struct{ meterstatus.Logger }{},
    45  		AmberGracePeriod: AmberGracePeriod,
    46  		RedGracePeriod:   RedGracePeriod,
    47  		TriggerFactory:   meterstatus.GetTriggers,
    48  	}
    49  }
    50  
    51  func (s *IsolatedWorkerConfigSuite) TestConfigValid(c *gc.C) {
    52  	c.Assert(s.config.Validate(), jc.ErrorIsNil)
    53  }
    54  
    55  func (s *IsolatedWorkerConfigSuite) TestMissingRunner(c *gc.C) {
    56  	s.config.Runner = nil
    57  	err := s.config.Validate()
    58  	c.Assert(err, jc.Satisfies, errors.IsNotValid)
    59  	c.Assert(err.Error(), gc.Equals, "missing Runner not valid")
    60  }
    61  
    62  func (s *IsolatedWorkerConfigSuite) TestMissingStateReadWriter(c *gc.C) {
    63  	s.config.StateReadWriter = nil
    64  	err := s.config.Validate()
    65  	c.Assert(err, jc.Satisfies, errors.IsNotValid)
    66  	c.Assert(err.Error(), gc.Equals, "missing StateReadWriter not valid")
    67  }
    68  
    69  func (s *IsolatedWorkerConfigSuite) TestMissingClock(c *gc.C) {
    70  	s.config.Clock = nil
    71  	err := s.config.Validate()
    72  	c.Assert(err, jc.Satisfies, errors.IsNotValid)
    73  	c.Assert(err.Error(), gc.Equals, "missing Clock not valid")
    74  }
    75  
    76  func (s *IsolatedWorkerConfigSuite) TestMissingLogger(c *gc.C) {
    77  	s.config.Logger = nil
    78  	err := s.config.Validate()
    79  	c.Assert(err, jc.Satisfies, errors.IsNotValid)
    80  	c.Assert(err.Error(), gc.Equals, "missing Logger not valid")
    81  }
    82  
    83  func (s *IsolatedWorkerConfigSuite) TestMissingAmberGracePeriod(c *gc.C) {
    84  	s.config.AmberGracePeriod = 0
    85  	err := s.config.Validate()
    86  	c.Assert(err, jc.Satisfies, errors.IsNotValid)
    87  	c.Assert(err.Error(), gc.Equals, "amber grace period not valid")
    88  }
    89  
    90  func (s *IsolatedWorkerConfigSuite) TestMissingRedGracePeriod(c *gc.C) {
    91  	s.config.RedGracePeriod = 0
    92  	err := s.config.Validate()
    93  	c.Assert(err, jc.Satisfies, errors.IsNotValid)
    94  	c.Assert(err.Error(), gc.Equals, "red grace period not valid")
    95  }
    96  
    97  func (s *IsolatedWorkerConfigSuite) TestMissingAmberEqualRed(c *gc.C) {
    98  	s.config.RedGracePeriod = s.config.AmberGracePeriod
    99  	err := s.config.Validate()
   100  	c.Assert(err.Error(), gc.Equals, "amber grace period must be shorter than the red grace period")
   101  }
   102  
   103  type IsolatedWorkerSuite struct {
   104  	coretesting.BaseSuite
   105  
   106  	stub *testing.Stub
   107  
   108  	dataDir string
   109  	clk     *testclock.Clock
   110  
   111  	hookRan         chan struct{}
   112  	triggersCreated chan struct{}
   113  
   114  	worker worker.Worker
   115  }
   116  
   117  var _ = gc.Suite(&IsolatedWorkerSuite{})
   118  
   119  func (s *IsolatedWorkerSuite) SetUpTest(c *gc.C) {
   120  	s.BaseSuite.SetUpTest(c)
   121  	s.stub = &testing.Stub{}
   122  
   123  	s.dataDir = c.MkDir()
   124  
   125  	s.hookRan = make(chan struct{})
   126  	s.triggersCreated = make(chan struct{})
   127  
   128  	triggerFactory := func(state meterstatus.WorkerState, status string, disconectedAt time.Time, clk meterstatus.Clock, amber time.Duration, red time.Duration) (<-chan time.Time, <-chan time.Time) {
   129  		select {
   130  		case s.triggersCreated <- struct{}{}:
   131  		case <-time.After(coretesting.LongWait):
   132  			c.Fatalf("failed to signal trigger creation")
   133  		}
   134  		return meterstatus.GetTriggers(state, status, disconectedAt, clk, amber, red)
   135  	}
   136  
   137  	s.clk = testclock.NewClock(time.Now())
   138  	wrk, err := meterstatus.NewIsolatedStatusWorker(
   139  		meterstatus.IsolatedConfig{
   140  			Runner:           &stubRunner{stub: s.stub, ran: s.hookRan},
   141  			StateReadWriter:  meterstatus.NewDiskBackedState(path.Join(s.dataDir, "meter-status.yaml")),
   142  			Clock:            s.clk,
   143  			Logger:           loggo.GetLogger("test"),
   144  			AmberGracePeriod: AmberGracePeriod,
   145  			RedGracePeriod:   RedGracePeriod,
   146  			TriggerFactory:   triggerFactory,
   147  		})
   148  	c.Assert(err, jc.ErrorIsNil)
   149  	c.Assert(wrk, gc.NotNil)
   150  	s.worker = wrk
   151  }
   152  
   153  func (s *IsolatedWorkerSuite) TearDownTest(c *gc.C) {
   154  	workertest.CleanKill(c, s.worker)
   155  }
   156  
   157  func (s *IsolatedWorkerSuite) TestTriggering(c *gc.C) {
   158  	assertSignal(c, s.triggersCreated)
   159  
   160  	// Wait on the red and amber timers.
   161  	c.Assert(s.clk.WaitAdvance(AmberGracePeriod+time.Second, testing.ShortWait, 2), jc.ErrorIsNil)
   162  	assertSignal(c, s.hookRan)
   163  
   164  	// Don't need to ensure the timers here, we did it for both above.
   165  	s.clk.Advance(RedGracePeriod + time.Second)
   166  	assertSignal(c, s.hookRan)
   167  
   168  	s.stub.CheckCallNames(c, "RunHook", "RunHook")
   169  }
   170  
   171  // TestMissingHookError tests that errors caused by missing hooks do not stop the worker.
   172  func (s *IsolatedWorkerSuite) TestMissingHookError(c *gc.C) {
   173  	s.stub.SetErrors(charmrunner.NewMissingHookError("meter-status-changed"))
   174  
   175  	assertSignal(c, s.triggersCreated)
   176  	c.Assert(s.clk.WaitAdvance(AmberGracePeriod+time.Second, testing.ShortWait, 2), jc.ErrorIsNil)
   177  	assertSignal(c, s.hookRan)
   178  
   179  	s.stub.CheckCallNames(c, "RunHook")
   180  }
   181  
   182  // TestRandomHookError tests that errors returned by hooks do not stop the worker.
   183  func (s *IsolatedWorkerSuite) TestRandomHookError(c *gc.C) {
   184  	s.stub.SetErrors(fmt.Errorf("blah"))
   185  
   186  	assertSignal(c, s.triggersCreated)
   187  	c.Assert(s.clk.WaitAdvance(AmberGracePeriod+time.Second, testing.ShortWait, 2), jc.ErrorIsNil)
   188  	assertSignal(c, s.hookRan)
   189  
   190  	s.stub.CheckCallNames(c, "RunHook")
   191  }