github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/worker/modelworkermanager/modelworkermanager_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package modelworkermanager_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  	"gopkg.in/tomb.v1"
    14  
    15  	"github.com/juju/juju/state"
    16  	coretesting "github.com/juju/juju/testing"
    17  	"github.com/juju/juju/worker"
    18  	"github.com/juju/juju/worker/modelworkermanager"
    19  	"github.com/juju/juju/worker/workertest"
    20  )
    21  
    22  var _ = gc.Suite(&suite{})
    23  
    24  type suite struct {
    25  	testing.IsolationSuite
    26  	workerC chan *mockWorker
    27  }
    28  
    29  func (s *suite) SetUpTest(c *gc.C) {
    30  	s.IsolationSuite.SetUpTest(c)
    31  	s.workerC = make(chan *mockWorker, 100)
    32  }
    33  
    34  func (s *suite) TestStartEmpty(c *gc.C) {
    35  	s.runTest(c, func(_ worker.Worker, backend *mockBackend) {
    36  		backend.sendModelChange()
    37  
    38  		s.assertNoWorkers(c)
    39  	})
    40  }
    41  
    42  func (s *suite) TestStartsInitialWorker(c *gc.C) {
    43  	s.runTest(c, func(_ worker.Worker, backend *mockBackend) {
    44  		backend.sendModelChange("uuid")
    45  
    46  		s.assertStarts(c, "uuid")
    47  	})
    48  }
    49  
    50  func (s *suite) TestStartsLaterWorker(c *gc.C) {
    51  	s.runTest(c, func(_ worker.Worker, backend *mockBackend) {
    52  		backend.sendModelChange()
    53  		backend.sendModelChange("uuid")
    54  
    55  		s.assertStarts(c, "uuid")
    56  	})
    57  }
    58  
    59  func (s *suite) TestStartsMultiple(c *gc.C) {
    60  	s.runTest(c, func(_ worker.Worker, backend *mockBackend) {
    61  		backend.sendModelChange("uuid1")
    62  		backend.sendModelChange("uuid2", "uuid3")
    63  		backend.sendModelChange("uuid4")
    64  
    65  		s.assertStarts(c, "uuid1", "uuid2", "uuid3", "uuid4")
    66  	})
    67  }
    68  
    69  func (s *suite) TestIgnoresRepetition(c *gc.C) {
    70  	s.runTest(c, func(_ worker.Worker, backend *mockBackend) {
    71  		backend.sendModelChange("uuid")
    72  		backend.sendModelChange("uuid", "uuid")
    73  		backend.sendModelChange("uuid")
    74  
    75  		s.assertStarts(c, "uuid")
    76  	})
    77  }
    78  
    79  func (s *suite) TestRestartsErrorWorker(c *gc.C) {
    80  	s.runTest(c, func(w worker.Worker, backend *mockBackend) {
    81  		backend.sendModelChange("uuid")
    82  		workers := s.waitWorkers(c, 1)
    83  		workers[0].tomb.Kill(errors.New("blaf"))
    84  
    85  		s.assertStarts(c, "uuid")
    86  		workertest.CheckAlive(c, w)
    87  	})
    88  }
    89  
    90  func (s *suite) TestRestartsFinishedWorker(c *gc.C) {
    91  	// It must be possible to restart the workers for a model due to
    92  	// model migrations: a model can be migrated away from a
    93  	// controller and then migrated back later.
    94  	s.runTest(c, func(w worker.Worker, backend *mockBackend) {
    95  		backend.sendModelChange("uuid")
    96  		workers := s.waitWorkers(c, 1)
    97  		workertest.CleanKill(c, workers[0])
    98  
    99  		s.assertNoWorkers(c)
   100  
   101  		backend.sendModelChange("uuid")
   102  		workertest.CheckAlive(c, w)
   103  		s.waitWorkers(c, 1)
   104  	})
   105  }
   106  
   107  func (s *suite) TestKillsManagers(c *gc.C) {
   108  	s.runTest(c, func(w worker.Worker, backend *mockBackend) {
   109  		backend.sendModelChange("uuid1", "uuid2")
   110  		workers := s.waitWorkers(c, 2)
   111  
   112  		workertest.CleanKill(c, w)
   113  		for _, worker := range workers {
   114  			workertest.CheckKilled(c, worker)
   115  		}
   116  		s.assertNoWorkers(c)
   117  	})
   118  }
   119  
   120  func (s *suite) TestClosedChangesChannel(c *gc.C) {
   121  	s.runDirtyTest(c, func(w worker.Worker, backend *mockBackend) {
   122  		backend.sendModelChange("uuid1", "uuid2")
   123  		workers := s.waitWorkers(c, 2)
   124  
   125  		close(backend.envWatcher.changes)
   126  		err := workertest.CheckKilled(c, w)
   127  		c.Check(err, gc.ErrorMatches, "changes stopped")
   128  		for _, worker := range workers {
   129  			workertest.CheckKilled(c, worker)
   130  		}
   131  		s.assertNoWorkers(c)
   132  	})
   133  }
   134  
   135  type testFunc func(worker.Worker, *mockBackend)
   136  type killFunc func(*gc.C, worker.Worker)
   137  
   138  func (s *suite) runTest(c *gc.C, test testFunc) {
   139  	s.runKillTest(c, workertest.CleanKill, test)
   140  }
   141  
   142  func (s *suite) runDirtyTest(c *gc.C, test testFunc) {
   143  	s.runKillTest(c, workertest.DirtyKill, test)
   144  }
   145  
   146  func (s *suite) runKillTest(c *gc.C, kill killFunc, test testFunc) {
   147  	backend := newMockBackend()
   148  	config := modelworkermanager.Config{
   149  		ControllerUUID: coretesting.ControllerTag.Id(),
   150  		Backend:        backend,
   151  		NewWorker:      s.startModelWorker,
   152  		ErrorDelay:     time.Millisecond,
   153  	}
   154  	w, err := modelworkermanager.New(config)
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	defer kill(c, w)
   157  	test(w, backend)
   158  }
   159  
   160  func (s *suite) startModelWorker(controllerUUID, modelUUID string) (worker.Worker, error) {
   161  	worker := newMockWorker(controllerUUID, modelUUID)
   162  	s.workerC <- worker
   163  	return worker, nil
   164  }
   165  
   166  func (s *suite) assertStarts(c *gc.C, expect ...string) {
   167  	count := len(expect)
   168  	actual := make([]string, count)
   169  	workers := s.waitWorkers(c, count)
   170  	for i, worker := range workers {
   171  		actual[i] = worker.uuid
   172  	}
   173  	c.Assert(actual, jc.SameContents, expect)
   174  }
   175  
   176  func (s *suite) waitWorkers(c *gc.C, expectedCount int) []*mockWorker {
   177  	if expectedCount < 1 {
   178  		c.Fatal("expectedCount must be >= 1")
   179  	}
   180  	workers := make([]*mockWorker, 0, expectedCount)
   181  	for {
   182  		select {
   183  		case worker := <-s.workerC:
   184  			workers = append(workers, worker)
   185  			if len(workers) == expectedCount {
   186  				s.assertNoWorkers(c)
   187  				return workers
   188  			}
   189  		case <-time.After(coretesting.LongWait):
   190  			c.Fatal("timed out waiting for workers to be started")
   191  		}
   192  	}
   193  }
   194  
   195  func (s *suite) assertNoWorkers(c *gc.C) {
   196  	select {
   197  	case worker := <-s.workerC:
   198  		c.Fatalf("saw unexpected worker: %s", worker.uuid)
   199  	case <-time.After(coretesting.ShortWait):
   200  	}
   201  }
   202  
   203  func newMockWorker(_, modelUUID string) *mockWorker {
   204  	w := &mockWorker{uuid: modelUUID}
   205  	go func() {
   206  		defer w.tomb.Done()
   207  		<-w.tomb.Dying()
   208  	}()
   209  	return w
   210  }
   211  
   212  type mockWorker struct {
   213  	tomb tomb.Tomb
   214  	uuid string
   215  }
   216  
   217  func (mock *mockWorker) Kill() {
   218  	mock.tomb.Kill(nil)
   219  }
   220  
   221  func (mock *mockWorker) Wait() error {
   222  	return mock.tomb.Wait()
   223  }
   224  
   225  func newMockBackend() *mockBackend {
   226  	return &mockBackend{
   227  		envWatcher: &mockEnvWatcher{
   228  			Worker:  workertest.NewErrorWorker(nil),
   229  			changes: make(chan []string),
   230  		},
   231  	}
   232  }
   233  
   234  type mockBackend struct {
   235  	envWatcher *mockEnvWatcher
   236  }
   237  
   238  func (mock *mockBackend) WatchModels() state.StringsWatcher {
   239  	return mock.envWatcher
   240  }
   241  
   242  func (mock *mockBackend) sendModelChange(uuids ...string) {
   243  	mock.envWatcher.changes <- uuids
   244  }
   245  
   246  type mockEnvWatcher struct {
   247  	worker.Worker
   248  	changes chan []string
   249  }
   250  
   251  func (w *mockEnvWatcher) Err() error {
   252  	panic("not used")
   253  }
   254  
   255  func (w *mockEnvWatcher) Stop() error {
   256  	return worker.Stop(w)
   257  }
   258  
   259  func (w *mockEnvWatcher) Changes() <-chan []string {
   260  	return w.changes
   261  }