~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/worker/modelworkermanager/modelworkermanager_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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) 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
                Backend:    backend,
 
150
                NewWorker:  s.startModelWorker,
 
151
                ErrorDelay: time.Millisecond,
 
152
        }
 
153
        w, err := modelworkermanager.New(config)
 
154
        c.Assert(err, jc.ErrorIsNil)
 
155
        defer kill(c, w)
 
156
        test(w, backend)
 
157
}
 
158
 
 
159
func (s *suite) startModelWorker(uuid string) (worker.Worker, error) {
 
160
        worker := newMockWorker(uuid)
 
161
        s.workerC <- worker
 
162
        return worker, nil
 
163
}
 
164
 
 
165
func (s *suite) assertStarts(c *gc.C, expect ...string) {
 
166
        count := len(expect)
 
167
        actual := make([]string, count)
 
168
        workers := s.waitWorkers(c, count)
 
169
        for i, worker := range workers {
 
170
                actual[i] = worker.uuid
 
171
        }
 
172
        c.Assert(actual, jc.SameContents, expect)
 
173
}
 
174
 
 
175
func (s *suite) waitWorkers(c *gc.C, expectedCount int) []*mockWorker {
 
176
        if expectedCount < 1 {
 
177
                c.Fatal("expectedCount must be >= 1")
 
178
        }
 
179
        workers := make([]*mockWorker, 0, expectedCount)
 
180
        for {
 
181
                select {
 
182
                case worker := <-s.workerC:
 
183
                        workers = append(workers, worker)
 
184
                        if len(workers) == expectedCount {
 
185
                                s.assertNoWorkers(c)
 
186
                                return workers
 
187
                        }
 
188
                case <-time.After(coretesting.LongWait):
 
189
                        c.Fatal("timed out waiting for workers to be started")
 
190
                }
 
191
        }
 
192
}
 
193
 
 
194
func (s *suite) assertNoWorkers(c *gc.C) {
 
195
        select {
 
196
        case worker := <-s.workerC:
 
197
                c.Fatalf("saw unexpected worker: %s", worker.uuid)
 
198
        case <-time.After(coretesting.ShortWait):
 
199
        }
 
200
}
 
201
 
 
202
func newMockWorker(uuid string) *mockWorker {
 
203
        w := &mockWorker{uuid: uuid}
 
204
        go func() {
 
205
                defer w.tomb.Done()
 
206
                <-w.tomb.Dying()
 
207
        }()
 
208
        return w
 
209
}
 
210
 
 
211
type mockWorker struct {
 
212
        tomb tomb.Tomb
 
213
        uuid string
 
214
}
 
215
 
 
216
func (mock *mockWorker) Kill() {
 
217
        mock.tomb.Kill(nil)
 
218
}
 
219
 
 
220
func (mock *mockWorker) Wait() error {
 
221
        return mock.tomb.Wait()
 
222
}
 
223
 
 
224
func newMockBackend() *mockBackend {
 
225
        return &mockBackend{
 
226
                envWatcher: &mockEnvWatcher{
 
227
                        Worker:  workertest.NewErrorWorker(nil),
 
228
                        changes: make(chan []string),
 
229
                },
 
230
        }
 
231
}
 
232
 
 
233
type mockBackend struct {
 
234
        envWatcher *mockEnvWatcher
 
235
}
 
236
 
 
237
func (mock *mockBackend) WatchModels() state.StringsWatcher {
 
238
        return mock.envWatcher
 
239
}
 
240
 
 
241
func (mock *mockBackend) sendModelChange(uuids ...string) {
 
242
        mock.envWatcher.changes <- uuids
 
243
}
 
244
 
 
245
type mockEnvWatcher struct {
 
246
        worker.Worker
 
247
        changes chan []string
 
248
}
 
249
 
 
250
func (w *mockEnvWatcher) Err() error {
 
251
        panic("not used")
 
252
}
 
253
 
 
254
func (w *mockEnvWatcher) Stop() error {
 
255
        return worker.Stop(w)
 
256
}
 
257
 
 
258
func (w *mockEnvWatcher) Changes() <-chan []string {
 
259
        return w.changes
 
260
}