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