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