github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/meterstatus/connected_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/fslock"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	coretesting "github.com/juju/juju/testing"
    17  	"github.com/juju/juju/worker/meterstatus"
    18  	"github.com/juju/juju/worker/uniter/runner/context"
    19  )
    20  
    21  type ConnectedWorkerSuite struct {
    22  	coretesting.BaseSuite
    23  
    24  	stub *testing.Stub
    25  
    26  	dataDir  string
    27  	lock     *fslock.Lock
    28  	msClient *stubMeterStatusClient
    29  }
    30  
    31  var _ = gc.Suite(&ConnectedWorkerSuite{})
    32  
    33  func (s *ConnectedWorkerSuite) SetUpTest(c *gc.C) {
    34  	s.BaseSuite.SetUpTest(c)
    35  	s.stub = &testing.Stub{}
    36  
    37  	s.dataDir = c.MkDir()
    38  
    39  	s.msClient = newStubMeterStatusClient(s.stub)
    40  }
    41  
    42  func assertSignal(c *gc.C, signal <-chan struct{}) {
    43  	select {
    44  	case <-signal:
    45  	case <-time.After(coretesting.LongWait):
    46  		c.Fatal("timed out waiting for signal")
    47  	}
    48  }
    49  
    50  func assertNoSignal(c *gc.C, signal <-chan struct{}) {
    51  	select {
    52  	case <-signal:
    53  		c.Fatal("unexpected signal")
    54  	case <-time.After(coretesting.ShortWait):
    55  	}
    56  }
    57  
    58  func (s *ConnectedWorkerSuite) TestConfigValidation(c *gc.C) {
    59  	tests := []struct {
    60  		cfg      meterstatus.ConnectedConfig
    61  		expected string
    62  	}{{
    63  		cfg: meterstatus.ConnectedConfig{
    64  			Status:    s.msClient,
    65  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
    66  		},
    67  		expected: "hook runner not provided",
    68  	}, {
    69  		cfg: meterstatus.ConnectedConfig{
    70  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
    71  			Runner:    &stubRunner{stub: s.stub},
    72  		},
    73  		expected: "meter status API client not provided",
    74  	}, {
    75  		cfg: meterstatus.ConnectedConfig{
    76  			Status: s.msClient,
    77  			Runner: &stubRunner{stub: s.stub},
    78  		},
    79  		expected: "state file not provided",
    80  	}}
    81  	for i, test := range tests {
    82  		c.Logf("running test %d", i)
    83  		err := test.cfg.Validate()
    84  		c.Assert(err, gc.ErrorMatches, test.expected)
    85  	}
    86  }
    87  
    88  // TestStatusHandlerDoesNotRerunNoChange ensures that the handler does not execute the hook if it
    89  // detects no actual meter status change.
    90  func (s *ConnectedWorkerSuite) TestStatusHandlerDoesNotRerunNoChange(c *gc.C) {
    91  	handler, err := meterstatus.NewConnectedStatusHandler(
    92  		meterstatus.ConnectedConfig{
    93  			Runner:    &stubRunner{stub: s.stub},
    94  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
    95  			Status:    s.msClient,
    96  		})
    97  	c.Assert(err, jc.ErrorIsNil)
    98  	c.Assert(handler, gc.NotNil)
    99  	_, err = handler.SetUp()
   100  	c.Assert(err, jc.ErrorIsNil)
   101  
   102  	err = handler.Handle(nil)
   103  	c.Assert(err, jc.ErrorIsNil)
   104  	err = handler.Handle(nil)
   105  	c.Assert(err, jc.ErrorIsNil)
   106  
   107  	s.stub.CheckCallNames(c, "WatchMeterStatus", "MeterStatus", "RunHook", "MeterStatus")
   108  }
   109  
   110  // TestStatusHandlerRunsHookOnChanges ensures that the handler runs the meter-status-changed hook
   111  // if an actual meter status change is detected.
   112  func (s *ConnectedWorkerSuite) TestStatusHandlerRunsHookOnChanges(c *gc.C) {
   113  	handler, err := meterstatus.NewConnectedStatusHandler(
   114  		meterstatus.ConnectedConfig{
   115  			Runner:    &stubRunner{stub: s.stub},
   116  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
   117  			Status:    s.msClient,
   118  		})
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	c.Assert(handler, gc.NotNil)
   121  	_, err = handler.SetUp()
   122  	c.Assert(err, jc.ErrorIsNil)
   123  
   124  	handler.Handle(nil)
   125  	s.msClient.SetStatus("RED")
   126  	handler.Handle(nil)
   127  
   128  	c.Assert(err, jc.ErrorIsNil)
   129  	s.stub.CheckCallNames(c, "WatchMeterStatus", "MeterStatus", "RunHook", "MeterStatus", "RunHook")
   130  }
   131  
   132  // TestStatusHandlerHandlesHookMissingError tests that the handler does not report errors
   133  // caused by a missing meter-status-changed hook.
   134  func (s *ConnectedWorkerSuite) TestStatusHandlerHandlesHookMissingError(c *gc.C) {
   135  	s.stub.SetErrors(context.NewMissingHookError("meter-status-changed"))
   136  	handler, err := meterstatus.NewConnectedStatusHandler(
   137  		meterstatus.ConnectedConfig{
   138  			Runner:    &stubRunner{stub: s.stub},
   139  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
   140  			Status:    s.msClient,
   141  		})
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	c.Assert(handler, gc.NotNil)
   144  	_, err = handler.SetUp()
   145  	c.Assert(err, jc.ErrorIsNil)
   146  
   147  	err = handler.Handle(nil)
   148  	c.Assert(err, jc.ErrorIsNil)
   149  	s.stub.CheckCallNames(c, "WatchMeterStatus", "MeterStatus", "RunHook")
   150  }
   151  
   152  // TestStatusHandlerHandlesRandomHookError tests that the meter status handler does not return
   153  // errors encountered while executing the hook.
   154  func (s *ConnectedWorkerSuite) TestStatusHandlerHandlesRandomHookError(c *gc.C) {
   155  	s.stub.SetErrors(fmt.Errorf("blah"))
   156  	handler, err := meterstatus.NewConnectedStatusHandler(
   157  		meterstatus.ConnectedConfig{
   158  			Runner:    &stubRunner{stub: s.stub},
   159  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
   160  			Status:    s.msClient,
   161  		})
   162  	c.Assert(err, jc.ErrorIsNil)
   163  	c.Assert(handler, gc.NotNil)
   164  	_, err = handler.SetUp()
   165  	c.Assert(err, jc.ErrorIsNil)
   166  
   167  	err = handler.Handle(nil)
   168  	c.Assert(err, jc.ErrorIsNil)
   169  
   170  	s.stub.CheckCallNames(c, "WatchMeterStatus", "MeterStatus", "RunHook")
   171  }
   172  
   173  // TestStatusHandlerDoesNotRerunAfterRestart tests that the status handler will not rerun a meter-status-changed
   174  // hook if it is restarted, but no actual changes are recorded.
   175  func (s *ConnectedWorkerSuite) TestStatusHandlerDoesNotRerunAfterRestart(c *gc.C) {
   176  	handler, err := meterstatus.NewConnectedStatusHandler(
   177  		meterstatus.ConnectedConfig{
   178  			Runner:    &stubRunner{stub: s.stub},
   179  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
   180  			Status:    s.msClient,
   181  		})
   182  	c.Assert(err, jc.ErrorIsNil)
   183  	c.Assert(handler, gc.NotNil)
   184  	_, err = handler.SetUp()
   185  	c.Assert(err, jc.ErrorIsNil)
   186  
   187  	err = handler.Handle(nil)
   188  	c.Assert(err, jc.ErrorIsNil)
   189  
   190  	s.stub.CheckCallNames(c, "WatchMeterStatus", "MeterStatus", "RunHook")
   191  	s.stub.ResetCalls()
   192  
   193  	// Create a new handler (imitating worker restart).
   194  	handler, err = meterstatus.NewConnectedStatusHandler(
   195  		meterstatus.ConnectedConfig{
   196  			Runner:    &stubRunner{stub: s.stub},
   197  			StateFile: meterstatus.NewStateFile(path.Join(s.dataDir, "meter-status.yaml")),
   198  			Status:    s.msClient})
   199  	c.Assert(err, jc.ErrorIsNil)
   200  	c.Assert(handler, gc.NotNil)
   201  	_, err = handler.SetUp()
   202  	c.Assert(err, jc.ErrorIsNil)
   203  
   204  	err = handler.Handle(nil)
   205  	c.Assert(err, jc.ErrorIsNil)
   206  
   207  	s.stub.CheckCallNames(c, "WatchMeterStatus", "MeterStatus")
   208  }