github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils/clock"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	coretesting "github.com/juju/juju/testing"
    17  	"github.com/juju/juju/worker"
    18  	"github.com/juju/juju/worker/meterstatus"
    19  	"github.com/juju/juju/worker/uniter/runner/context"
    20  )
    21  
    22  const (
    23  	AmberGracePeriod = time.Minute
    24  	RedGracePeriod   = time.Minute * 5
    25  )
    26  
    27  type IsolatedWorkerSuite struct {
    28  	coretesting.BaseSuite
    29  
    30  	stub *testing.Stub
    31  
    32  	dataDir string
    33  	clk     *testing.Clock
    34  
    35  	hookRan         chan struct{}
    36  	triggersCreated chan struct{}
    37  
    38  	worker worker.Worker
    39  }
    40  
    41  var _ = gc.Suite(&IsolatedWorkerSuite{})
    42  
    43  func (s *IsolatedWorkerSuite) SetUpTest(c *gc.C) {
    44  	s.BaseSuite.SetUpTest(c)
    45  	s.stub = &testing.Stub{}
    46  
    47  	s.dataDir = c.MkDir()
    48  
    49  	s.hookRan = make(chan struct{})
    50  	s.triggersCreated = make(chan struct{})
    51  
    52  	triggerFactory := func(state meterstatus.WorkerState, status string, disconectedAt time.Time, clk clock.Clock, amber time.Duration, red time.Duration) (<-chan time.Time, <-chan time.Time) {
    53  		select {
    54  		case s.triggersCreated <- struct{}{}:
    55  		case <-time.After(coretesting.LongWait):
    56  			c.Fatalf("failed to signal trigger creation")
    57  		}
    58  		return meterstatus.GetTriggers(state, status, disconectedAt, clk, amber, red)
    59  	}
    60  
    61  	s.clk = testing.NewClock(time.Now())
    62  	wrk, err := meterstatus.NewIsolatedStatusWorker(
    63  		meterstatus.IsolatedConfig{
    64  			Runner:           &stubRunner{stub: s.stub, ran: s.hookRan},
    65  			StateFile:        meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
    66  			Clock:            s.clk,
    67  			AmberGracePeriod: AmberGracePeriod,
    68  			RedGracePeriod:   RedGracePeriod,
    69  			TriggerFactory:   triggerFactory,
    70  		})
    71  	c.Assert(err, jc.ErrorIsNil)
    72  	c.Assert(wrk, gc.NotNil)
    73  	s.worker = wrk
    74  }
    75  
    76  func (s *IsolatedWorkerSuite) TearDownTest(c *gc.C) {
    77  	s.worker.Kill()
    78  	err := s.worker.Wait()
    79  	c.Assert(err, jc.ErrorIsNil)
    80  }
    81  
    82  func (s *IsolatedWorkerSuite) TestConfigValidation(c *gc.C) {
    83  	tests := []struct {
    84  		cfg      meterstatus.IsolatedConfig
    85  		expected string
    86  	}{{
    87  		cfg: meterstatus.IsolatedConfig{
    88  			Runner:    &stubRunner{stub: s.stub},
    89  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
    90  		},
    91  		expected: "clock not provided",
    92  	}, {
    93  		cfg: meterstatus.IsolatedConfig{
    94  			Clock:     testing.NewClock(time.Now()),
    95  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
    96  		},
    97  		expected: "hook runner not provided",
    98  	}, {
    99  		cfg: meterstatus.IsolatedConfig{
   100  			Clock:  testing.NewClock(time.Now()),
   101  			Runner: &stubRunner{stub: s.stub},
   102  		},
   103  		expected: "state file not provided",
   104  	}}
   105  	for i, test := range tests {
   106  		c.Logf("running test %d", i)
   107  		err := test.cfg.Validate()
   108  		c.Assert(err, gc.ErrorMatches, test.expected)
   109  	}
   110  }
   111  
   112  func (s *IsolatedWorkerSuite) TestTriggering(c *gc.C) {
   113  	assertSignal(c, s.triggersCreated)
   114  	s.clk.Advance(AmberGracePeriod + time.Second)
   115  	assertSignal(c, s.hookRan)
   116  	s.clk.Advance(RedGracePeriod + time.Second)
   117  	assertSignal(c, s.hookRan)
   118  
   119  	s.stub.CheckCallNames(c, "RunHook", "RunHook")
   120  }
   121  
   122  // TestMissingHookError tests that errors caused by missing hooks do not stop the worker.
   123  func (s *IsolatedWorkerSuite) TestMissingHookError(c *gc.C) {
   124  	s.stub.SetErrors(context.NewMissingHookError("meter-status-changed"))
   125  
   126  	assertSignal(c, s.triggersCreated)
   127  	s.clk.Advance(AmberGracePeriod + time.Second)
   128  	assertSignal(c, s.hookRan)
   129  
   130  	s.stub.CheckCallNames(c, "RunHook")
   131  }
   132  
   133  // TestRandomHookError tests that errors returned by hooks do not stop the worker.
   134  func (s *IsolatedWorkerSuite) TestRandomHookError(c *gc.C) {
   135  	s.stub.SetErrors(fmt.Errorf("blah"))
   136  
   137  	assertSignal(c, s.triggersCreated)
   138  	s.clk.Advance(AmberGracePeriod + time.Second)
   139  	assertSignal(c, s.hookRan)
   140  
   141  	s.stub.CheckCallNames(c, "RunHook")
   142  }