~wallyworld/juju-core/unit-agent-knows-assigned-machine

« back to all changes in this revision

Viewing changes to state/presence/presence_test.go

  • Committer: Roger Peppe
  • Date: 2012-09-19 13:40:41 UTC
  • mto: This revision was merged to the branch mainline in revision 527.
  • Revision ID: roger.peppe@canonical.com-20120919134041-1rt4cg7ox52pt4os
mstate: rename to state

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package presence_test
2
 
 
3
 
import (
4
 
        . "launchpad.net/gocheck"
5
 
        "launchpad.net/gozk/zookeeper"
6
 
        "launchpad.net/juju-core/state/presence"
7
 
        "launchpad.net/juju-core/testing"
8
 
        stdtesting "testing"
9
 
        "time"
10
 
)
11
 
 
12
 
func TestPackage(t *stdtesting.T) {
13
 
        testing.ZkTestPackage(t)
14
 
}
15
 
 
16
 
type PresenceSuite struct {
17
 
        testing.ZkConnSuite
18
 
}
19
 
 
20
 
var _ = Suite(&PresenceSuite{})
21
 
 
22
 
var (
23
 
        path       = "/presence"
24
 
        period     = 500 * time.Millisecond
25
 
        longEnough = period * 6
26
 
)
27
 
 
28
 
func assertChange(c *C, watch <-chan bool, expectAlive bool) {
29
 
        select {
30
 
        case <-time.After(longEnough):
31
 
                c.Fatal("Liveness change not detected")
32
 
        case alive, ok := <-watch:
33
 
                c.Assert(ok, Equals, true)
34
 
                c.Assert(alive, Equals, expectAlive)
35
 
        }
36
 
}
37
 
 
38
 
func assertClose(c *C, watch <-chan bool) {
39
 
        select {
40
 
        case <-time.After(longEnough):
41
 
                c.Fatal("Connection loss not detected")
42
 
        case _, ok := <-watch:
43
 
                c.Assert(ok, Equals, false)
44
 
        }
45
 
}
46
 
 
47
 
func assertNoChange(c *C, watch <-chan bool) {
48
 
        select {
49
 
        case <-time.After(longEnough):
50
 
                return
51
 
        case <-watch:
52
 
                c.Fatal("Unexpected liveness change")
53
 
        }
54
 
}
55
 
 
56
 
func kill(c *C, p *presence.Pinger) {
57
 
        c.Assert(p.Kill(), IsNil)
58
 
}
59
 
 
60
 
func (s *PresenceSuite) TestStartPinger(c *C) {
61
 
        // Check not considered Alive before it exists.
62
 
        alive, err := presence.Alive(s.ZkConn, path)
63
 
        c.Assert(err, IsNil)
64
 
        c.Assert(alive, Equals, false)
65
 
 
66
 
        // Watch for life, and check the watch doesn't fire early.
67
 
        alive, watch, err := presence.AliveW(s.ZkConn, path)
68
 
        c.Assert(err, IsNil)
69
 
        c.Assert(alive, Equals, false)
70
 
        assertNoChange(c, watch)
71
 
 
72
 
        // Creating a Pinger does not automatically Start it.
73
 
        p := presence.NewPinger(s.ZkConn, path, period)
74
 
        c.Assert(err, IsNil)
75
 
        assertNoChange(c, watch)
76
 
 
77
 
        // Pinger Start should be detected on the change channel.
78
 
        err = p.Start()
79
 
        c.Assert(err, IsNil)
80
 
        assertChange(c, watch, true)
81
 
 
82
 
        // Check that Alive agrees.
83
 
        alive, err = presence.Alive(s.ZkConn, path)
84
 
        c.Assert(err, IsNil)
85
 
        c.Assert(alive, Equals, true)
86
 
 
87
 
        // Watch for life again, and check that agrees.
88
 
        alive, watch, err = presence.AliveW(s.ZkConn, path)
89
 
        c.Assert(err, IsNil)
90
 
        c.Assert(alive, Equals, true)
91
 
        assertNoChange(c, watch)
92
 
 
93
 
        // Starting the pinger when it is already running is not allowed.
94
 
        bad := func() { p.Start() }
95
 
        c.Assert(bad, PanicMatches, "pinger is already started")
96
 
 
97
 
        // Clean up.
98
 
        err = p.Kill()
99
 
        c.Assert(err, IsNil)
100
 
}
101
 
 
102
 
func (s *PresenceSuite) TestKillPinger(c *C) {
103
 
        // Start a Pinger and a watch, and check sanity.
104
 
        p, err := presence.StartPinger(s.ZkConn, path, period)
105
 
        c.Assert(err, IsNil)
106
 
        defer kill(c, p)
107
 
        alive, watch, err := presence.AliveW(s.ZkConn, path)
108
 
        c.Assert(err, IsNil)
109
 
        c.Assert(alive, Equals, true)
110
 
        assertNoChange(c, watch)
111
 
 
112
 
        // Kill the Pinger; check the watch fires and Alive agrees.
113
 
        err = p.Kill()
114
 
        c.Assert(err, IsNil)
115
 
        assertChange(c, watch, false)
116
 
        alive, err = presence.Alive(s.ZkConn, path)
117
 
        c.Assert(err, IsNil)
118
 
        c.Assert(alive, Equals, false)
119
 
 
120
 
        // Check that the pinger's node was deleted.
121
 
        stat, err := s.ZkConn.Exists(path)
122
 
        c.Assert(err, IsNil)
123
 
        c.Assert(stat, IsNil)
124
 
 
125
 
        // Check the pinger can no longer be used:
126
 
        bad := func() { p.Start() }
127
 
        c.Assert(bad, PanicMatches, "pinger has been killed")
128
 
        bad = func() { p.Stop() }
129
 
        c.Assert(bad, PanicMatches, "pinger has been killed")
130
 
}
131
 
 
132
 
func (s *PresenceSuite) TestStopPinger(c *C) {
133
 
        // Start a Pinger and a watch, and check sanity.
134
 
        p, err := presence.StartPinger(s.ZkConn, path, period)
135
 
        c.Assert(err, IsNil)
136
 
        defer kill(c, p)
137
 
        alive, watch, err := presence.AliveW(s.ZkConn, path)
138
 
        c.Assert(err, IsNil)
139
 
        c.Assert(alive, Equals, true)
140
 
        assertNoChange(c, watch)
141
 
 
142
 
        // Stop the Pinger; check the watch fires and Alive agrees.
143
 
        err = p.Stop()
144
 
        c.Assert(err, IsNil)
145
 
        assertChange(c, watch, false)
146
 
        alive, watch, err = presence.AliveW(s.ZkConn, path)
147
 
        c.Assert(err, IsNil)
148
 
        c.Assert(alive, Equals, false)
149
 
 
150
 
        // Check that we can Stop again.
151
 
        err = p.Stop()
152
 
        c.Assert(err, IsNil)
153
 
 
154
 
        // Check that the pinger's node is still present, but no changes have been seen.
155
 
        stat, err := s.ZkConn.Exists(path)
156
 
        c.Assert(err, IsNil)
157
 
        c.Assert(stat, NotNil)
158
 
        assertNoChange(c, watch)
159
 
 
160
 
        // Start the Pinger again, and check the change is detected.
161
 
        err = p.Start()
162
 
        c.Assert(err, IsNil)
163
 
        assertChange(c, watch, true)
164
 
}
165
 
 
166
 
func (s *PresenceSuite) TestWatchDeadnessChange(c *C) {
167
 
        // Create a stale node.
168
 
        p, err := presence.StartPinger(s.ZkConn, path, period)
169
 
        c.Assert(err, IsNil)
170
 
        err = p.Stop()
171
 
        c.Assert(err, IsNil)
172
 
        time.Sleep(longEnough)
173
 
 
174
 
        // Start watching for liveness.
175
 
        alive, watch, err := presence.AliveW(s.ZkConn, path)
176
 
        c.Assert(err, IsNil)
177
 
        c.Assert(alive, Equals, false)
178
 
 
179
 
        // Delete the node and check the watch doesn't fire.
180
 
        err = s.ZkConn.Delete(path, -1)
181
 
        c.Assert(err, IsNil)
182
 
        assertNoChange(c, watch)
183
 
 
184
 
        // Start a new Pinger and check the watch does fire.
185
 
        p, err = presence.StartPinger(s.ZkConn, path, period)
186
 
        c.Assert(err, IsNil)
187
 
        defer kill(c, p)
188
 
        assertChange(c, watch, true)
189
 
}
190
 
 
191
 
func (s *PresenceSuite) TestBadData(c *C) {
192
 
        // Create a node that contains inappropriate data.
193
 
        _, err := s.ZkConn.Create(path, "roflcopter", 0, zookeeper.WorldACL(zookeeper.PERM_ALL))
194
 
        c.Assert(err, IsNil)
195
 
 
196
 
        // Check it is not interpreted as a presence node by Alive.
197
 
        _, err = presence.Alive(s.ZkConn, path)
198
 
        c.Assert(err, ErrorMatches, `/presence presence node has bad data: "roflcopter"`)
199
 
 
200
 
        // Check it is not interpreted as a presence node by Watch.
201
 
        _, watch, err := presence.AliveW(s.ZkConn, path)
202
 
        c.Assert(watch, IsNil)
203
 
        c.Assert(err, ErrorMatches, `/presence presence node has bad data: "roflcopter"`)
204
 
}
205
 
 
206
 
func (s *PresenceSuite) TestDisconnectDeadWatch(c *C) {
207
 
        // Create a target node.
208
 
        p, err := presence.StartPinger(s.ZkConn, path, period)
209
 
        c.Assert(err, IsNil)
210
 
        err = p.Stop()
211
 
        c.Assert(err, IsNil)
212
 
 
213
 
        // Start an alternate connection and ensure the node is stale.
214
 
        altConn := testing.ZkConnect()
215
 
        time.Sleep(longEnough)
216
 
 
217
 
        // Start a watch using the alternate connection.
218
 
        alive, watch, err := presence.AliveW(altConn, path)
219
 
        c.Assert(err, IsNil)
220
 
        c.Assert(alive, Equals, false)
221
 
 
222
 
        // Kill the watch connection and check it's alerted.
223
 
        altConn.Close()
224
 
        assertClose(c, watch)
225
 
}
226
 
 
227
 
func (s *PresenceSuite) TestDisconnectMissingWatch(c *C) {
228
 
        // Don't even create a target node.
229
 
 
230
 
        // Start watching on an alternate connection.
231
 
        altConn := testing.ZkConnect()
232
 
        alive, watch, err := presence.AliveW(altConn, path)
233
 
        c.Assert(err, IsNil)
234
 
        c.Assert(alive, Equals, false)
235
 
 
236
 
        // Kill the watch's connection and check it's alerted.
237
 
        altConn.Close()
238
 
        assertClose(c, watch)
239
 
}
240
 
 
241
 
func (s *PresenceSuite) TestDisconnectAliveWatch(c *C) {
242
 
        // Start a Pinger on the main connection
243
 
        p, err := presence.StartPinger(s.ZkConn, path, period)
244
 
        c.Assert(err, IsNil)
245
 
        defer kill(c, p)
246
 
 
247
 
        // Start watching on an alternate connection.
248
 
        altConn := testing.ZkConnect()
249
 
        alive, watch, err := presence.AliveW(altConn, path)
250
 
        c.Assert(err, IsNil)
251
 
        c.Assert(alive, Equals, true)
252
 
 
253
 
        // Kill the watch's connection and check it's alerted.
254
 
        altConn.Close()
255
 
        assertClose(c, watch)
256
 
}
257
 
 
258
 
func (s *PresenceSuite) TestDisconnectPinger(c *C) {
259
 
        // Start a Pinger on an alternate connection.
260
 
        altConn := testing.ZkConnect()
261
 
        p, err := presence.StartPinger(altConn, path, period)
262
 
        c.Assert(err, IsNil)
263
 
        defer p.Kill()
264
 
 
265
 
        // Watch on the "main" connection.
266
 
        alive, watch, err := presence.AliveW(s.ZkConn, path)
267
 
        c.Assert(err, IsNil)
268
 
        c.Assert(alive, Equals, true)
269
 
 
270
 
        // Kill the pinger connection and check the watch notices.
271
 
        altConn.Close()
272
 
        assertChange(c, watch, false)
273
 
 
274
 
        // Stop the pinger anyway; check we still get an error.
275
 
        err = p.Stop()
276
 
        c.Assert(err, NotNil)
277
 
}
278
 
 
279
 
func (s *PresenceSuite) TestWaitAlive(c *C) {
280
 
        err := presence.WaitAlive(s.ZkConn, path, longEnough)
281
 
        c.Assert(err, ErrorMatches, "presence: still not alive after timeout")
282
 
 
283
 
        dying := make(chan struct{})
284
 
        dead := make(chan struct{})
285
 
 
286
 
        // Start a pinger with a short delay so that WaitAlive() has to wait.
287
 
        go func() {
288
 
                time.Sleep(period * 2)
289
 
                p, err := presence.StartPinger(s.ZkConn, path, period)
290
 
                c.Assert(err, IsNil)
291
 
                <-dying
292
 
                err = p.Kill()
293
 
                c.Assert(err, IsNil)
294
 
                close(dead)
295
 
        }()
296
 
 
297
 
        // Wait for, and check, liveness.
298
 
        err = presence.WaitAlive(s.ZkConn, path, longEnough)
299
 
        c.Assert(err, IsNil)
300
 
        close(dying)
301
 
        <-dead
302
 
}
303
 
 
304
 
func (s *PresenceSuite) TestDisconnectWaitAlive(c *C) {
305
 
        // Start a new connection with a short lifespan.
306
 
        altConn := testing.ZkConnect()
307
 
        go func() {
308
 
                time.Sleep(period * 2)
309
 
                altConn.Close()
310
 
        }()
311
 
 
312
 
        // Check that WaitAlive returns an appropriate error.
313
 
        err := presence.WaitAlive(altConn, path, longEnough)
314
 
        c.Assert(err, ErrorMatches, "presence: channel closed while waiting")
315
 
}
316
 
 
317
 
func (s *PresenceSuite) TestChildrenWatcher(c *C) {
318
 
        w := presence.NewChildrenWatcher(s.ZkConn, "/nodes")
319
 
 
320
 
        // Check initial event.
321
 
        assertChange := func(added, removed []string) {
322
 
                select {
323
 
                case ch, ok := <-w.Changes():
324
 
                        c.Assert(ok, Equals, true)
325
 
                        c.Assert(ch.Added, DeepEquals, added)
326
 
                        c.Assert(ch.Removed, DeepEquals, removed)
327
 
                case <-time.After(longEnough):
328
 
                        c.Fatalf("expected change, got none")
329
 
                }
330
 
        }
331
 
        assertChange(nil, nil)
332
 
        assertNoChange := func() {
333
 
                select {
334
 
                case ch := <-w.Changes():
335
 
                        c.Fatalf("got unexpected change: %#v", ch)
336
 
                case <-time.After(longEnough):
337
 
                }
338
 
        }
339
 
        assertNoChange()
340
 
 
341
 
        // Create the node we're watching, check no change.
342
 
        _, err := s.ZkConn.Create("/nodes", "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL))
343
 
        c.Assert(err, IsNil)
344
 
        assertNoChange()
345
 
 
346
 
        // Add a pinger, check it's noticed.
347
 
        p1, err := presence.StartPinger(s.ZkConn, "/nodes/p1", period)
348
 
        c.Assert(err, IsNil)
349
 
        defer kill(c, p1)
350
 
        assertChange([]string{"p1"}, nil)
351
 
        assertNoChange()
352
 
 
353
 
        // Add another pinger, check it's noticed.
354
 
        p2, err := presence.StartPinger(s.ZkConn, "/nodes/p2", period)
355
 
        c.Assert(err, IsNil)
356
 
        defer kill(c, p2)
357
 
        assertChange([]string{"p2"}, nil)
358
 
 
359
 
        // Stop watcher, check closed.
360
 
        err = w.Stop()
361
 
        c.Assert(err, IsNil)
362
 
        assertClosed := func() {
363
 
                select {
364
 
                case _, ok := <-w.Changes():
365
 
                        c.Assert(ok, Equals, false)
366
 
                case <-time.After(longEnough):
367
 
                        c.Fatalf("changes channel not closed")
368
 
                }
369
 
        }
370
 
        assertClosed()
371
 
 
372
 
        // Stop a pinger, wait long enough for it to be considered dead.
373
 
        err = p1.Stop()
374
 
        c.Assert(err, IsNil)
375
 
        <-time.After(longEnough)
376
 
 
377
 
        // Start a new watcher, check initial event.
378
 
        w = presence.NewChildrenWatcher(s.ZkConn, "/nodes")
379
 
        assertChange([]string{"p2"}, nil)
380
 
        assertNoChange()
381
 
 
382
 
        // Kill the remaining pinger, check it's noticed.
383
 
        err = p2.Kill()
384
 
        assertChange(nil, []string{"p2"})
385
 
        assertNoChange()
386
 
 
387
 
        // A few times, initially starting with p1 abandoned and subsequently
388
 
        // with it deleted:
389
 
        for i := 0; i < 3; i++ {
390
 
                // Start a new pinger on p1 and check its presence is noted...
391
 
                p1, err = presence.StartPinger(s.ZkConn, "/nodes/p1", period)
392
 
                c.Assert(err, IsNil)
393
 
                defer kill(c, p1)
394
 
                assertChange([]string{"p1"}, nil)
395
 
                assertNoChange()
396
 
 
397
 
                // ...and so is its absence.
398
 
                err = p1.Kill()
399
 
                assertChange(nil, []string{"p1"})
400
 
                assertNoChange()
401
 
        }
402
 
 
403
 
        // Stop the watcher, check closed again.
404
 
        err = w.Stop()
405
 
        c.Assert(err, IsNil)
406
 
        assertClosed()
407
 
}