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