launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/api/watcher/watcher_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package watcher_test
     5  
     6  import (
     7  	gc "launchpad.net/gocheck"
     8  	stdtesting "testing"
     9  	"time"
    10  
    11  	"launchpad.net/juju-core/juju/testing"
    12  	"launchpad.net/juju-core/state"
    13  	"launchpad.net/juju-core/state/api"
    14  	"launchpad.net/juju-core/state/api/params"
    15  	"launchpad.net/juju-core/state/api/watcher"
    16  	statetesting "launchpad.net/juju-core/state/testing"
    17  	coretesting "launchpad.net/juju-core/testing"
    18  )
    19  
    20  func TestAll(t *stdtesting.T) {
    21  	coretesting.MgoTestPackage(t)
    22  }
    23  
    24  type watcherSuite struct {
    25  	testing.JujuConnSuite
    26  
    27  	stateAPI *api.State
    28  
    29  	// These are raw State objects. Use them for setup and assertions, but
    30  	// should never be touched by the API calls themselves
    31  	rawMachine *state.Machine
    32  }
    33  
    34  var _ = gc.Suite(&watcherSuite{})
    35  
    36  func (s *watcherSuite) SetUpTest(c *gc.C) {
    37  	s.JujuConnSuite.SetUpTest(c)
    38  	s.stateAPI, s.rawMachine = s.OpenAPIAsNewMachine(c)
    39  }
    40  
    41  func (s *watcherSuite) TestWatchInitialEventConsumed(c *gc.C) {
    42  	// Machiner.Watch should send the initial event as part of the Watch
    43  	// call (for NotifyWatchers there is no state to be transmitted). So a
    44  	// call to Next() should not have anything to return.
    45  	var results params.NotifyWatchResults
    46  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag()}}}
    47  	err := s.stateAPI.Call("Machiner", "", "Watch", args, &results)
    48  	c.Assert(err, gc.IsNil)
    49  	c.Assert(results.Results, gc.HasLen, 1)
    50  	result := results.Results[0]
    51  	c.Assert(result.Error, gc.IsNil)
    52  
    53  	// We expect the Call() to "Next" to block, so run it in a goroutine.
    54  	done := make(chan error)
    55  	go func() {
    56  		ignored := struct{}{}
    57  		done <- s.stateAPI.Call("NotifyWatcher", result.NotifyWatcherId, "Next", nil, &ignored)
    58  	}()
    59  
    60  	select {
    61  	case err := <-done:
    62  		c.Errorf("Call(Next) did not block immediately after Watch(): err %v", err)
    63  	case <-time.After(coretesting.ShortWait):
    64  	}
    65  }
    66  
    67  func (s *watcherSuite) TestWatchMachine(c *gc.C) {
    68  	var results params.NotifyWatchResults
    69  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag()}}}
    70  	err := s.stateAPI.Call("Machiner", "", "Watch", args, &results)
    71  	c.Assert(err, gc.IsNil)
    72  	c.Assert(results.Results, gc.HasLen, 1)
    73  	result := results.Results[0]
    74  	c.Assert(result.Error, gc.IsNil)
    75  
    76  	// params.NotifyWatcher conforms to the state.NotifyWatcher interface
    77  	w := watcher.NewNotifyWatcher(s.stateAPI, result)
    78  	wc := statetesting.NewNotifyWatcherC(c, s.State, w)
    79  	wc.AssertOneChange()
    80  	statetesting.AssertStop(c, w)
    81  	wc.AssertClosed()
    82  }
    83  
    84  func (s *watcherSuite) TestNotifyWatcherStopsWithPendingSend(c *gc.C) {
    85  	var results params.NotifyWatchResults
    86  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag()}}}
    87  	err := s.stateAPI.Call("Machiner", "", "Watch", args, &results)
    88  	c.Assert(err, gc.IsNil)
    89  	c.Assert(results.Results, gc.HasLen, 1)
    90  	result := results.Results[0]
    91  	c.Assert(result.Error, gc.IsNil)
    92  
    93  	// params.NotifyWatcher conforms to the state.NotifyWatcher interface
    94  	w := watcher.NewNotifyWatcher(s.stateAPI, result)
    95  	wc := statetesting.NewNotifyWatcherC(c, s.State, w)
    96  
    97  	// Now, without reading any changes try stopping the watcher.
    98  	statetesting.AssertCanStopWhenSending(c, w)
    99  	wc.AssertClosed()
   100  }
   101  
   102  func (s *watcherSuite) TestWatchUnitsKeepsEvents(c *gc.C) {
   103  	// Create two services, relate them, and add one unit to each - a
   104  	// principal and a subordinate.
   105  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
   106  	logging := s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
   107  	eps, err := s.State.InferEndpoints([]string{"mysql", "logging"})
   108  	c.Assert(err, gc.IsNil)
   109  	rel, err := s.State.AddRelation(eps...)
   110  	c.Assert(err, gc.IsNil)
   111  	principal, err := mysql.AddUnit()
   112  	c.Assert(err, gc.IsNil)
   113  	err = principal.AssignToMachine(s.rawMachine)
   114  	c.Assert(err, gc.IsNil)
   115  	relUnit, err := rel.Unit(principal)
   116  	c.Assert(err, gc.IsNil)
   117  	err = relUnit.EnterScope(nil)
   118  	c.Assert(err, gc.IsNil)
   119  	subordinate, err := logging.Unit("logging/0")
   120  	c.Assert(err, gc.IsNil)
   121  
   122  	// Call the Deployer facade's WatchUnits for machine-0.
   123  	var results params.StringsWatchResults
   124  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag()}}}
   125  	err = s.stateAPI.Call("Deployer", "", "WatchUnits", args, &results)
   126  	c.Assert(err, gc.IsNil)
   127  	c.Assert(results.Results, gc.HasLen, 1)
   128  	result := results.Results[0]
   129  	c.Assert(result.Error, gc.IsNil)
   130  
   131  	// Start a StringsWatcher and check the initial event.
   132  	w := watcher.NewStringsWatcher(s.stateAPI, result)
   133  	wc := statetesting.NewStringsWatcherC(c, s.State, w)
   134  	wc.AssertChange("mysql/0", "logging/0")
   135  	wc.AssertNoChange()
   136  
   137  	// Now, without reading any changes advance the lifecycle of both
   138  	// units, inducing an update server-side after each two changes to
   139  	// ensure they're reported as separate events over the API.
   140  	err = subordinate.EnsureDead()
   141  	c.Assert(err, gc.IsNil)
   142  	s.BackingState.StartSync()
   143  	err = subordinate.Remove()
   144  	c.Assert(err, gc.IsNil)
   145  	err = principal.EnsureDead()
   146  	c.Assert(err, gc.IsNil)
   147  	s.BackingState.StartSync()
   148  
   149  	// Expect these changes as 2 separate events, so that
   150  	// nothing gets lost.
   151  	wc.AssertChange("logging/0")
   152  	wc.AssertChange("mysql/0")
   153  	wc.AssertNoChange()
   154  
   155  	statetesting.AssertStop(c, w)
   156  	wc.AssertClosed()
   157  }
   158  
   159  func (s *watcherSuite) TestStringsWatcherStopsWithPendingSend(c *gc.C) {
   160  	// Call the Deployer facade's WatchUnits for machine-0.
   161  	var results params.StringsWatchResults
   162  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag()}}}
   163  	err := s.stateAPI.Call("Deployer", "", "WatchUnits", args, &results)
   164  	c.Assert(err, gc.IsNil)
   165  	c.Assert(results.Results, gc.HasLen, 1)
   166  	result := results.Results[0]
   167  	c.Assert(result.Error, gc.IsNil)
   168  
   169  	// Start a StringsWatcher and check the initial event.
   170  	w := watcher.NewStringsWatcher(s.stateAPI, result)
   171  	wc := statetesting.NewStringsWatcherC(c, s.State, w)
   172  
   173  	// Create a service, deploy a unit of it on the machine.
   174  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
   175  	principal, err := mysql.AddUnit()
   176  	c.Assert(err, gc.IsNil)
   177  	err = principal.AssignToMachine(s.rawMachine)
   178  	c.Assert(err, gc.IsNil)
   179  
   180  	// Ensure the initial event is delivered. Then test the watcher
   181  	// can be stopped cleanly without reading the pending change.
   182  	s.BackingState.StartSync()
   183  	statetesting.AssertCanStopWhenSending(c, w)
   184  	wc.AssertClosed()
   185  }