github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/worker/instancepoller/updater_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // TODO(wallyworld) - move to instancepoller_test
     5  package instancepoller
     6  
     7  import (
     8  	"errors"
     9  	stdtesting "testing"
    10  	"time"
    11  
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "launchpad.net/gocheck"
    14  
    15  	"github.com/juju/juju/state"
    16  	"github.com/juju/juju/state/api/params"
    17  	coretesting "github.com/juju/juju/testing"
    18  )
    19  
    20  func TestPackage(t *stdtesting.T) {
    21  	coretesting.MgoTestPackage(t)
    22  }
    23  
    24  var _ = gc.Suite(&updaterSuite{})
    25  
    26  type updaterSuite struct {
    27  	coretesting.BaseSuite
    28  }
    29  
    30  func (*updaterSuite) TestStopsWatcher(c *gc.C) {
    31  	context := &testUpdaterContext{
    32  		dyingc: make(chan struct{}),
    33  	}
    34  	expectErr := errors.New("some error")
    35  	watcher := &testMachinesWatcher{
    36  		changes: make(chan []string),
    37  		err:     expectErr,
    38  	}
    39  	done := make(chan error)
    40  	go func() {
    41  		done <- watchMachinesLoop(context, watcher)
    42  	}()
    43  	close(context.dyingc)
    44  	select {
    45  	case err := <-done:
    46  		c.Assert(err, gc.ErrorMatches, ".*"+expectErr.Error())
    47  	case <-time.After(coretesting.LongWait):
    48  		c.Fatalf("timed out waiting for watchMachinesLoop to terminate")
    49  	}
    50  	c.Assert(watcher.stopped, jc.IsTrue)
    51  }
    52  
    53  func (*updaterSuite) TestWatchMachinesWaitsForMachinePollers(c *gc.C) {
    54  	// We can't see that the machine pollers are still alive directly,
    55  	// but we can make the machine's Refresh method block,
    56  	// and test that watchMachinesLoop only terminates
    57  	// when it unblocks.
    58  	waitRefresh := make(chan struct{})
    59  	m := &testMachine{
    60  		id:         "99",
    61  		instanceId: "i1234",
    62  		life:       state.Alive,
    63  		refresh: func() error {
    64  			// Signal that we're in Refresh.
    65  			waitRefresh <- struct{}{}
    66  			// Wait to be unblocked.
    67  			<-waitRefresh
    68  			return nil
    69  		},
    70  	}
    71  	dyingc := make(chan struct{})
    72  	context := &testUpdaterContext{
    73  		dyingc: dyingc,
    74  		newMachineContextFunc: func() machineContext {
    75  			return &testMachineContext{
    76  				getInstanceInfo: instanceInfoGetter(c, "i1234", testAddrs, "running", nil),
    77  				dyingc:          dyingc,
    78  			}
    79  		},
    80  		getMachineFunc: func(id string) (machine, error) {
    81  			c.Check(id, gc.Equals, m.id)
    82  			return m, nil
    83  		},
    84  	}
    85  	watcher := &testMachinesWatcher{
    86  		changes: make(chan []string),
    87  	}
    88  	done := make(chan error)
    89  	go func() {
    90  		done <- watchMachinesLoop(context, watcher)
    91  	}()
    92  	// Send two changes; the first one should start the machineLoop;
    93  	// the second should call Refresh.
    94  	watcher.changes <- []string{"99"}
    95  	watcher.changes <- []string{"99"}
    96  	// Wait for the machineLoop to call Refresh
    97  	select {
    98  	case <-waitRefresh:
    99  		c.Logf("poller called Refresh")
   100  	case <-time.After(coretesting.LongWait):
   101  		c.Fatalf("timed out waiting for machine to be refreshed")
   102  	}
   103  	close(context.dyingc)
   104  	// Wait a little while to be sure that watchMachinesLoop is
   105  	// actually waiting for its machine poller to finish.
   106  	select {
   107  	case err := <-done:
   108  		c.Fatalf("watchMachinesLoop terminated prematurely: %v", err)
   109  	case <-time.After(coretesting.ShortWait):
   110  	}
   111  
   112  	waitRefresh <- struct{}{}
   113  	select {
   114  	case err := <-done:
   115  		c.Assert(err, gc.IsNil)
   116  	case <-time.After(coretesting.LongWait):
   117  		c.Fatalf("timed out waiting for watchMachinesLoop to terminate")
   118  	}
   119  	c.Assert(watcher.stopped, jc.IsTrue)
   120  }
   121  
   122  func (s *updaterSuite) TestManualMachinesIgnored(c *gc.C) {
   123  	waitStatus := make(chan struct{})
   124  	s.PatchValue(&MachineStatus, func(m *testMachine) (status params.Status, info string, data params.StatusData, err error) {
   125  		// Signal that we're in Status.
   126  		waitStatus <- struct{}{}
   127  		return params.StatusPending, "", params.StatusData{}, nil
   128  	})
   129  	m := &testMachine{
   130  		id:         "99",
   131  		instanceId: "manual:1234",
   132  		life:       state.Alive,
   133  	}
   134  	dyingc := make(chan struct{})
   135  	context := &testUpdaterContext{
   136  		dyingc: dyingc,
   137  		newMachineContextFunc: func() machineContext {
   138  			return &testMachineContext{
   139  				getInstanceInfo: instanceInfoGetter(c, "manual:1234", testAddrs, "running", nil),
   140  				dyingc:          dyingc,
   141  			}
   142  		},
   143  		getMachineFunc: func(id string) (machine, error) {
   144  			c.Check(id, gc.Equals, m.id)
   145  			return m, nil
   146  		},
   147  	}
   148  	watcher := &testMachinesWatcher{
   149  		changes: make(chan []string),
   150  	}
   151  	done := make(chan error)
   152  	go func() {
   153  		done <- watchMachinesLoop(context, watcher)
   154  	}()
   155  	// Send a change to start the machineLoop;
   156  	watcher.changes <- []string{"99"}
   157  	select {
   158  	case <-waitStatus:
   159  		c.Fatalf("poller called Status")
   160  	case <-time.After(coretesting.ShortWait):
   161  		c.Logf("status not called")
   162  	}
   163  	close(context.dyingc)
   164  	select {
   165  	case err := <-done:
   166  		c.Assert(err, gc.IsNil)
   167  	case <-time.After(coretesting.LongWait):
   168  		c.Fatalf("timed out waiting for watchMachinesLoop to terminate")
   169  	}
   170  	c.Assert(watcher.stopped, jc.IsTrue)
   171  }
   172  
   173  type testUpdaterContext struct {
   174  	newMachineContextFunc func() machineContext
   175  	getMachineFunc        func(id string) (machine, error)
   176  	dyingc                chan struct{}
   177  }
   178  
   179  func (context *testUpdaterContext) newMachineContext() machineContext {
   180  	return context.newMachineContextFunc()
   181  }
   182  
   183  func (context *testUpdaterContext) getMachine(id string) (machine, error) {
   184  	return context.getMachineFunc(id)
   185  }
   186  
   187  func (context *testUpdaterContext) dying() <-chan struct{} {
   188  	return context.dyingc
   189  }
   190  
   191  type testMachinesWatcher struct {
   192  	stopped bool
   193  	changes chan []string
   194  	err     error
   195  }
   196  
   197  func (w *testMachinesWatcher) Changes() <-chan []string {
   198  	return w.changes
   199  }
   200  
   201  func (w *testMachinesWatcher) Stop() error {
   202  	w.stopped = true
   203  	return w.err
   204  }
   205  
   206  func (w *testMachinesWatcher) Err() error {
   207  	return w.err
   208  }