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