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