github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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  	"github.com/juju/names"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/apiserver/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  		tag:        names.NewMachineTag("99"),
    61  		instanceId: "i1234",
    62  		life:       params.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(tag names.MachineTag) (machine, error) {
    81  			c.Check(tag, jc.DeepEquals, m.tag)
    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, jc.ErrorIsNil)
   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) (params.StatusResult, error) {
   125  		// Signal that we're in Status.
   126  		waitStatus <- struct{}{}
   127  		return params.StatusResult{
   128  			Status: params.StatusPending,
   129  			Info:   "",
   130  			Data:   map[string]interface{}{},
   131  			Since:  nil,
   132  		}, nil
   133  	})
   134  	m := &testMachine{
   135  		tag:        names.NewMachineTag("99"),
   136  		instanceId: "manual:1234",
   137  		life:       params.Alive,
   138  	}
   139  	dyingc := make(chan struct{})
   140  	context := &testUpdaterContext{
   141  		dyingc: dyingc,
   142  		newMachineContextFunc: func() machineContext {
   143  			return &testMachineContext{
   144  				getInstanceInfo: instanceInfoGetter(c, "manual:1234", testAddrs, "running", nil),
   145  				dyingc:          dyingc,
   146  			}
   147  		},
   148  		getMachineFunc: func(tag names.MachineTag) (machine, error) {
   149  			c.Check(tag, jc.DeepEquals, m.tag)
   150  			return m, nil
   151  		},
   152  	}
   153  	watcher := &testMachinesWatcher{
   154  		changes: make(chan []string),
   155  	}
   156  	done := make(chan error)
   157  	go func() {
   158  		done <- watchMachinesLoop(context, watcher)
   159  	}()
   160  	// Send a change to start the machineLoop;
   161  	watcher.changes <- []string{"99"}
   162  	select {
   163  	case <-waitStatus:
   164  		c.Fatalf("poller called Status")
   165  	case <-time.After(coretesting.ShortWait):
   166  		c.Logf("status not called")
   167  	}
   168  	close(context.dyingc)
   169  	select {
   170  	case err := <-done:
   171  		c.Assert(err, jc.ErrorIsNil)
   172  	case <-time.After(coretesting.LongWait):
   173  		c.Fatalf("timed out waiting for watchMachinesLoop to terminate")
   174  	}
   175  	c.Assert(watcher.stopped, jc.IsTrue)
   176  }
   177  
   178  type testUpdaterContext struct {
   179  	newMachineContextFunc func() machineContext
   180  	getMachineFunc        func(tag names.MachineTag) (machine, error)
   181  	dyingc                chan struct{}
   182  }
   183  
   184  func (context *testUpdaterContext) newMachineContext() machineContext {
   185  	return context.newMachineContextFunc()
   186  }
   187  
   188  func (context *testUpdaterContext) getMachine(tag names.MachineTag) (machine, error) {
   189  	return context.getMachineFunc(tag)
   190  }
   191  
   192  func (context *testUpdaterContext) dying() <-chan struct{} {
   193  	return context.dyingc
   194  }
   195  
   196  type testMachinesWatcher struct {
   197  	stopped bool
   198  	changes chan []string
   199  	err     error
   200  }
   201  
   202  func (w *testMachinesWatcher) Changes() <-chan []string {
   203  	return w.changes
   204  }
   205  
   206  func (w *testMachinesWatcher) Stop() error {
   207  	w.stopped = true
   208  	return w.err
   209  }
   210  
   211  func (w *testMachinesWatcher) Err() error {
   212  	return w.err
   213  }