github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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  	"github.com/juju/juju/storage"
    20  	"github.com/juju/juju/storage/provider/dummy"
    21  	"github.com/juju/juju/storage/provider/registry"
    22  	coretesting "github.com/juju/juju/testing"
    23  	"github.com/juju/juju/testing/factory"
    24  )
    25  
    26  func TestAll(t *stdtesting.T) {
    27  	coretesting.MgoTestPackage(t)
    28  }
    29  
    30  type watcherSuite struct {
    31  	testing.JujuConnSuite
    32  
    33  	stateAPI api.Connection
    34  
    35  	// These are raw State objects. Use them for setup and assertions, but
    36  	// should never be touched by the API calls themselves
    37  	rawMachine *state.Machine
    38  }
    39  
    40  var _ = gc.Suite(&watcherSuite{})
    41  
    42  func (s *watcherSuite) SetUpTest(c *gc.C) {
    43  	s.JujuConnSuite.SetUpTest(c)
    44  	s.stateAPI, s.rawMachine = s.OpenAPIAsNewMachine(c, state.JobManageEnviron, state.JobHostUnits)
    45  }
    46  
    47  func (s *watcherSuite) TestWatchInitialEventConsumed(c *gc.C) {
    48  	// Machiner.Watch should send the initial event as part of the Watch
    49  	// call (for NotifyWatchers there is no state to be transmitted). So a
    50  	// call to Next() should not have anything to return.
    51  	var results params.NotifyWatchResults
    52  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}}
    53  	err := s.stateAPI.APICall("Machiner", s.stateAPI.BestFacadeVersion("Machiner"), "", "Watch", args, &results)
    54  	c.Assert(err, jc.ErrorIsNil)
    55  	c.Assert(results.Results, gc.HasLen, 1)
    56  	result := results.Results[0]
    57  	c.Assert(result.Error, gc.IsNil)
    58  
    59  	// We expect the Call() to "Next" to block, so run it in a goroutine.
    60  	done := make(chan error)
    61  	go func() {
    62  		ignored := struct{}{}
    63  		done <- s.stateAPI.APICall("NotifyWatcher", s.stateAPI.BestFacadeVersion("NotifyWatcher"), result.NotifyWatcherId, "Next", nil, &ignored)
    64  	}()
    65  
    66  	select {
    67  	case err := <-done:
    68  		c.Errorf("Call(Next) did not block immediately after Watch(): err %v", err)
    69  	case <-time.After(coretesting.ShortWait):
    70  	}
    71  }
    72  
    73  func (s *watcherSuite) TestWatchMachine(c *gc.C) {
    74  	var results params.NotifyWatchResults
    75  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}}
    76  	err := s.stateAPI.APICall("Machiner", s.stateAPI.BestFacadeVersion("Machiner"), "", "Watch", args, &results)
    77  	c.Assert(err, jc.ErrorIsNil)
    78  	c.Assert(results.Results, gc.HasLen, 1)
    79  	result := results.Results[0]
    80  	c.Assert(result.Error, gc.IsNil)
    81  
    82  	// params.NotifyWatcher conforms to the state.NotifyWatcher interface
    83  	w := watcher.NewNotifyWatcher(s.stateAPI, result)
    84  	wc := statetesting.NewNotifyWatcherC(c, s.State, w)
    85  	wc.AssertOneChange()
    86  	statetesting.AssertStop(c, w)
    87  	wc.AssertClosed()
    88  }
    89  
    90  func (s *watcherSuite) TestNotifyWatcherStopsWithPendingSend(c *gc.C) {
    91  	var results params.NotifyWatchResults
    92  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}}
    93  	err := s.stateAPI.APICall("Machiner", s.stateAPI.BestFacadeVersion("Machiner"), "", "Watch", args, &results)
    94  	c.Assert(err, jc.ErrorIsNil)
    95  	c.Assert(results.Results, gc.HasLen, 1)
    96  	result := results.Results[0]
    97  	c.Assert(result.Error, gc.IsNil)
    98  
    99  	// params.NotifyWatcher conforms to the state.NotifyWatcher interface
   100  	w := watcher.NewNotifyWatcher(s.stateAPI, result)
   101  	wc := statetesting.NewNotifyWatcherC(c, s.State, w)
   102  
   103  	// Now, without reading any changes try stopping the watcher.
   104  	statetesting.AssertCanStopWhenSending(c, w)
   105  	wc.AssertClosed()
   106  }
   107  
   108  func (s *watcherSuite) TestWatchUnitsKeepsEvents(c *gc.C) {
   109  	// Create two services, relate them, and add one unit to each - a
   110  	// principal and a subordinate.
   111  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
   112  	s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
   113  	eps, err := s.State.InferEndpoints("mysql", "logging")
   114  	c.Assert(err, jc.ErrorIsNil)
   115  	rel, err := s.State.AddRelation(eps...)
   116  	c.Assert(err, jc.ErrorIsNil)
   117  	principal, err := mysql.AddUnit()
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	err = principal.AssignToMachine(s.rawMachine)
   120  	c.Assert(err, jc.ErrorIsNil)
   121  	relUnit, err := rel.Unit(principal)
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	err = relUnit.EnterScope(nil)
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	subordinate, err := s.State.Unit("logging/0")
   126  	c.Assert(err, jc.ErrorIsNil)
   127  
   128  	// Call the Deployer facade's WatchUnits for machine-0.
   129  	var results params.StringsWatchResults
   130  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}}
   131  	err = s.stateAPI.APICall("Deployer", s.stateAPI.BestFacadeVersion("Deployer"), "", "WatchUnits", args, &results)
   132  	c.Assert(err, jc.ErrorIsNil)
   133  	c.Assert(results.Results, gc.HasLen, 1)
   134  	result := results.Results[0]
   135  	c.Assert(result.Error, gc.IsNil)
   136  
   137  	// Start a StringsWatcher and check the initial event.
   138  	w := watcher.NewStringsWatcher(s.stateAPI, result)
   139  	wc := statetesting.NewStringsWatcherC(c, s.State, w)
   140  	wc.AssertChange("mysql/0", "logging/0")
   141  	wc.AssertNoChange()
   142  
   143  	// Now, without reading any changes advance the lifecycle of both
   144  	// units, inducing an update server-side after each two changes to
   145  	// ensure they're reported as separate events over the API.
   146  	err = subordinate.EnsureDead()
   147  	c.Assert(err, jc.ErrorIsNil)
   148  	s.BackingState.StartSync()
   149  	err = subordinate.Remove()
   150  	c.Assert(err, jc.ErrorIsNil)
   151  	err = principal.EnsureDead()
   152  	c.Assert(err, jc.ErrorIsNil)
   153  	s.BackingState.StartSync()
   154  
   155  	// Expect these changes as 2 separate events, so that
   156  	// nothing gets lost.
   157  	wc.AssertChange("logging/0")
   158  	wc.AssertChange("mysql/0")
   159  	wc.AssertNoChange()
   160  
   161  	statetesting.AssertStop(c, w)
   162  	wc.AssertClosed()
   163  }
   164  
   165  func (s *watcherSuite) TestStringsWatcherStopsWithPendingSend(c *gc.C) {
   166  	// Call the Deployer facade's WatchUnits for machine-0.
   167  	var results params.StringsWatchResults
   168  	args := params.Entities{Entities: []params.Entity{{Tag: s.rawMachine.Tag().String()}}}
   169  	err := s.stateAPI.APICall("Deployer", s.stateAPI.BestFacadeVersion("Deployer"), "", "WatchUnits", args, &results)
   170  	c.Assert(err, jc.ErrorIsNil)
   171  	c.Assert(results.Results, gc.HasLen, 1)
   172  	result := results.Results[0]
   173  	c.Assert(result.Error, gc.IsNil)
   174  
   175  	// Start a StringsWatcher and check the initial event.
   176  	w := watcher.NewStringsWatcher(s.stateAPI, result)
   177  	wc := statetesting.NewStringsWatcherC(c, s.State, w)
   178  
   179  	// Create a service, deploy a unit of it on the machine.
   180  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
   181  	principal, err := mysql.AddUnit()
   182  	c.Assert(err, jc.ErrorIsNil)
   183  	err = principal.AssignToMachine(s.rawMachine)
   184  	c.Assert(err, jc.ErrorIsNil)
   185  
   186  	// Ensure the initial event is delivered. Then test the watcher
   187  	// can be stopped cleanly without reading the pending change.
   188  	s.BackingState.StartSync()
   189  	statetesting.AssertCanStopWhenSending(c, w)
   190  	wc.AssertClosed()
   191  }
   192  
   193  func (s *watcherSuite) TestWatchMachineStorage(c *gc.C) {
   194  	registry.RegisterProvider(
   195  		"envscoped",
   196  		&dummy.StorageProvider{
   197  			StorageScope: storage.ScopeEnviron,
   198  		},
   199  	)
   200  	registry.RegisterEnvironStorageProviders("dummy", "envscoped")
   201  	defer registry.RegisterProvider("envscoped", nil)
   202  
   203  	f := factory.NewFactory(s.BackingState)
   204  	f.MakeMachine(c, &factory.MachineParams{
   205  		Volumes: []state.MachineVolumeParams{{
   206  			Volume: state.VolumeParams{
   207  				Pool: "envscoped",
   208  				Size: 1024,
   209  			},
   210  		}},
   211  	})
   212  
   213  	var results params.MachineStorageIdsWatchResults
   214  	args := params.Entities{Entities: []params.Entity{{
   215  		Tag: s.State.EnvironTag().String(),
   216  	}}}
   217  	err := s.stateAPI.APICall(
   218  		"StorageProvisioner",
   219  		s.stateAPI.BestFacadeVersion("StorageProvisioner"),
   220  		"", "WatchVolumeAttachments", args, &results)
   221  	c.Assert(err, jc.ErrorIsNil)
   222  	c.Assert(results.Results, gc.HasLen, 1)
   223  	result := results.Results[0]
   224  	c.Assert(result.Error, gc.IsNil)
   225  
   226  	w := watcher.NewVolumeAttachmentsWatcher(s.stateAPI, result)
   227  	select {
   228  	case changes, ok := <-w.Changes():
   229  		c.Assert(ok, jc.IsTrue)
   230  		c.Assert(changes, jc.SameContents, []params.MachineStorageId{{
   231  			MachineTag:    "machine-1",
   232  			AttachmentTag: "volume-0",
   233  		}})
   234  	case <-time.After(coretesting.LongWait):
   235  		c.Fatalf("timed out waiting for change")
   236  	}
   237  	select {
   238  	case <-w.Changes():
   239  		c.Fatalf("received unexpected change")
   240  	case <-time.After(coretesting.ShortWait):
   241  	}
   242  
   243  	statetesting.AssertStop(c, w)
   244  	select {
   245  	case _, ok := <-w.Changes():
   246  		c.Assert(ok, jc.IsFalse)
   247  	case <-time.After(coretesting.LongWait):
   248  		c.Fatalf("timed out waiting for watcher channel to be closed")
   249  	}
   250  }