github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  	"launchpad.net/tomb"
    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) TestNeverRestartsFinishedWorker(c *gc.C) {
    91  	s.runTest(c, func(w worker.Worker, backend *mockBackend) {
    92  		backend.sendModelChange("uuid")
    93  		workers := s.waitWorkers(c, 1)
    94  		workers[0].tomb.Kill(nil)
    95  
    96  		// even when we get a change for it
    97  		backend.sendModelChange("uuid")
    98  		workertest.CheckAlive(c, w)
    99  		s.assertNoWorkers(c)
   100  	})
   101  }
   102  
   103  func (s *suite) TestKillsManagers(c *gc.C) {
   104  	s.runTest(c, func(w worker.Worker, backend *mockBackend) {
   105  		backend.sendModelChange("uuid1", "uuid2")
   106  		workers := s.waitWorkers(c, 2)
   107  
   108  		workertest.CleanKill(c, w)
   109  		for _, worker := range workers {
   110  			workertest.CheckKilled(c, worker)
   111  		}
   112  		s.assertNoWorkers(c)
   113  	})
   114  }
   115  
   116  func (s *suite) TestClosedChangesChannel(c *gc.C) {
   117  	s.runDirtyTest(c, func(w worker.Worker, backend *mockBackend) {
   118  		backend.sendModelChange("uuid1", "uuid2")
   119  		workers := s.waitWorkers(c, 2)
   120  
   121  		close(backend.envWatcher.changes)
   122  		err := workertest.CheckKilled(c, w)
   123  		c.Check(err, gc.ErrorMatches, "changes stopped")
   124  		for _, worker := range workers {
   125  			workertest.CheckKilled(c, worker)
   126  		}
   127  		s.assertNoWorkers(c)
   128  	})
   129  }
   130  
   131  type testFunc func(worker.Worker, *mockBackend)
   132  type killFunc func(*gc.C, worker.Worker)
   133  
   134  func (s *suite) runTest(c *gc.C, test testFunc) {
   135  	s.runKillTest(c, workertest.CleanKill, test)
   136  }
   137  
   138  func (s *suite) runDirtyTest(c *gc.C, test testFunc) {
   139  	s.runKillTest(c, workertest.DirtyKill, test)
   140  }
   141  
   142  func (s *suite) runKillTest(c *gc.C, kill killFunc, test testFunc) {
   143  	backend := newMockBackend()
   144  	config := modelworkermanager.Config{
   145  		Backend:    backend,
   146  		NewWorker:  s.startModelWorker,
   147  		ErrorDelay: time.Millisecond,
   148  	}
   149  	w, err := modelworkermanager.New(config)
   150  	c.Assert(err, jc.ErrorIsNil)
   151  	defer kill(c, w)
   152  	test(w, backend)
   153  }
   154  
   155  func (s *suite) startModelWorker(uuid string) (worker.Worker, error) {
   156  	worker := newMockWorker(uuid)
   157  	s.workerC <- worker
   158  	return worker, nil
   159  }
   160  
   161  func (s *suite) assertStarts(c *gc.C, expect ...string) {
   162  	count := len(expect)
   163  	actual := make([]string, count)
   164  	workers := s.waitWorkers(c, count)
   165  	for i, worker := range workers {
   166  		actual[i] = worker.uuid
   167  	}
   168  	c.Assert(actual, jc.SameContents, expect)
   169  }
   170  
   171  func (s *suite) waitWorkers(c *gc.C, expectedCount int) []*mockWorker {
   172  	if expectedCount < 1 {
   173  		c.Fatal("expectedCount must be >= 1")
   174  	}
   175  	workers := make([]*mockWorker, 0, expectedCount)
   176  	for {
   177  		select {
   178  		case worker := <-s.workerC:
   179  			workers = append(workers, worker)
   180  			if len(workers) == expectedCount {
   181  				s.assertNoWorkers(c)
   182  				return workers
   183  			}
   184  		case <-time.After(coretesting.LongWait):
   185  			c.Fatal("timed out waiting for workers to be started")
   186  		}
   187  	}
   188  }
   189  
   190  func (s *suite) assertNoWorkers(c *gc.C) {
   191  	select {
   192  	case worker := <-s.workerC:
   193  		c.Fatalf("saw unexpected worker: %s", worker.uuid)
   194  	case <-time.After(coretesting.ShortWait):
   195  	}
   196  }
   197  
   198  func newMockWorker(uuid string) *mockWorker {
   199  	w := &mockWorker{uuid: uuid}
   200  	go func() {
   201  		defer w.tomb.Done()
   202  		<-w.tomb.Dying()
   203  	}()
   204  	return w
   205  }
   206  
   207  type mockWorker struct {
   208  	tomb tomb.Tomb
   209  	uuid string
   210  }
   211  
   212  func (mock *mockWorker) Kill() {
   213  	mock.tomb.Kill(nil)
   214  }
   215  
   216  func (mock *mockWorker) Wait() error {
   217  	return mock.tomb.Wait()
   218  }
   219  
   220  func newMockBackend() *mockBackend {
   221  	return &mockBackend{
   222  		envWatcher: &mockEnvWatcher{
   223  			Worker:  workertest.NewErrorWorker(nil),
   224  			changes: make(chan []string),
   225  		},
   226  	}
   227  }
   228  
   229  type mockBackend struct {
   230  	envWatcher *mockEnvWatcher
   231  }
   232  
   233  func (mock *mockBackend) WatchModels() state.StringsWatcher {
   234  	return mock.envWatcher
   235  }
   236  
   237  func (mock *mockBackend) sendModelChange(uuids ...string) {
   238  	mock.envWatcher.changes <- uuids
   239  }
   240  
   241  type mockEnvWatcher struct {
   242  	worker.Worker
   243  	changes chan []string
   244  }
   245  
   246  func (w *mockEnvWatcher) Err() error {
   247  	panic("not used")
   248  }
   249  
   250  func (w *mockEnvWatcher) Stop() error {
   251  	return worker.Stop(w)
   252  }
   253  
   254  func (w *mockEnvWatcher) Changes() <-chan []string {
   255  	return w.changes
   256  }