1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
4
package modelworkermanager_test
9
"github.com/juju/errors"
10
"github.com/juju/testing"
11
jc "github.com/juju/testing/checkers"
12
gc "gopkg.in/check.v1"
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"
22
var _ = gc.Suite(&suite{})
25
testing.IsolationSuite
26
workerC chan *mockWorker
29
func (s *suite) SetUpTest(c *gc.C) {
30
s.IsolationSuite.SetUpTest(c)
31
s.workerC = make(chan *mockWorker, 100)
34
func (s *suite) TestStartEmpty(c *gc.C) {
35
s.runTest(c, func(_ worker.Worker, backend *mockBackend) {
36
backend.sendModelChange()
42
func (s *suite) TestStartsInitialWorker(c *gc.C) {
43
s.runTest(c, func(_ worker.Worker, backend *mockBackend) {
44
backend.sendModelChange("uuid")
46
s.assertStarts(c, "uuid")
50
func (s *suite) TestStartsLaterWorker(c *gc.C) {
51
s.runTest(c, func(_ worker.Worker, backend *mockBackend) {
52
backend.sendModelChange()
53
backend.sendModelChange("uuid")
55
s.assertStarts(c, "uuid")
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")
65
s.assertStarts(c, "uuid1", "uuid2", "uuid3", "uuid4")
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")
75
s.assertStarts(c, "uuid")
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"))
85
s.assertStarts(c, "uuid")
86
workertest.CheckAlive(c, w)
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])
101
backend.sendModelChange("uuid")
102
workertest.CheckAlive(c, w)
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)
112
workertest.CleanKill(c, w)
113
for _, worker := range workers {
114
workertest.CheckKilled(c, worker)
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)
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)
135
type testFunc func(worker.Worker, *mockBackend)
136
type killFunc func(*gc.C, worker.Worker)
138
func (s *suite) runTest(c *gc.C, test testFunc) {
139
s.runKillTest(c, workertest.CleanKill, test)
142
func (s *suite) runDirtyTest(c *gc.C, test testFunc) {
143
s.runKillTest(c, workertest.DirtyKill, test)
146
func (s *suite) runKillTest(c *gc.C, kill killFunc, test testFunc) {
147
backend := newMockBackend()
148
config := modelworkermanager.Config{
150
NewWorker: s.startModelWorker,
151
ErrorDelay: time.Millisecond,
153
w, err := modelworkermanager.New(config)
154
c.Assert(err, jc.ErrorIsNil)
159
func (s *suite) startModelWorker(uuid string) (worker.Worker, error) {
160
worker := newMockWorker(uuid)
165
func (s *suite) assertStarts(c *gc.C, expect ...string) {
167
actual := make([]string, count)
168
workers := s.waitWorkers(c, count)
169
for i, worker := range workers {
170
actual[i] = worker.uuid
172
c.Assert(actual, jc.SameContents, expect)
175
func (s *suite) waitWorkers(c *gc.C, expectedCount int) []*mockWorker {
176
if expectedCount < 1 {
177
c.Fatal("expectedCount must be >= 1")
179
workers := make([]*mockWorker, 0, expectedCount)
182
case worker := <-s.workerC:
183
workers = append(workers, worker)
184
if len(workers) == expectedCount {
188
case <-time.After(coretesting.LongWait):
189
c.Fatal("timed out waiting for workers to be started")
194
func (s *suite) assertNoWorkers(c *gc.C) {
196
case worker := <-s.workerC:
197
c.Fatalf("saw unexpected worker: %s", worker.uuid)
198
case <-time.After(coretesting.ShortWait):
202
func newMockWorker(uuid string) *mockWorker {
203
w := &mockWorker{uuid: uuid}
211
type mockWorker struct {
216
func (mock *mockWorker) Kill() {
220
func (mock *mockWorker) Wait() error {
221
return mock.tomb.Wait()
224
func newMockBackend() *mockBackend {
226
envWatcher: &mockEnvWatcher{
227
Worker: workertest.NewErrorWorker(nil),
228
changes: make(chan []string),
233
type mockBackend struct {
234
envWatcher *mockEnvWatcher
237
func (mock *mockBackend) WatchModels() state.StringsWatcher {
238
return mock.envWatcher
241
func (mock *mockBackend) sendModelChange(uuids ...string) {
242
mock.envWatcher.changes <- uuids
245
type mockEnvWatcher struct {
247
changes chan []string
250
func (w *mockEnvWatcher) Err() error {
254
func (w *mockEnvWatcher) Stop() error {
255
return worker.Stop(w)
258
func (w *mockEnvWatcher) Changes() <-chan []string {