4
. "launchpad.net/gocheck"
5
"launchpad.net/gozk/zookeeper"
6
"launchpad.net/juju-core/state/presence"
7
"launchpad.net/juju-core/testing"
12
func TestPackage(t *stdtesting.T) {
13
testing.ZkTestPackage(t)
16
type PresenceSuite struct {
20
var _ = Suite(&PresenceSuite{})
24
period = 500 * time.Millisecond
25
longEnough = period * 6
28
func assertChange(c *C, watch <-chan bool, expectAlive bool) {
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)
38
func assertClose(c *C, watch <-chan bool) {
40
case <-time.After(longEnough):
41
c.Fatal("Connection loss not detected")
42
case _, ok := <-watch:
43
c.Assert(ok, Equals, false)
47
func assertNoChange(c *C, watch <-chan bool) {
49
case <-time.After(longEnough):
52
c.Fatal("Unexpected liveness change")
56
func kill(c *C, p *presence.Pinger) {
57
c.Assert(p.Kill(), IsNil)
60
func (s *PresenceSuite) TestStartPinger(c *C) {
61
// Check not considered Alive before it exists.
62
alive, err := presence.Alive(s.ZkConn, path)
64
c.Assert(alive, Equals, false)
66
// Watch for life, and check the watch doesn't fire early.
67
alive, watch, err := presence.AliveW(s.ZkConn, path)
69
c.Assert(alive, Equals, false)
70
assertNoChange(c, watch)
72
// Creating a Pinger does not automatically Start it.
73
p := presence.NewPinger(s.ZkConn, path, period)
75
assertNoChange(c, watch)
77
// Pinger Start should be detected on the change channel.
80
assertChange(c, watch, true)
82
// Check that Alive agrees.
83
alive, err = presence.Alive(s.ZkConn, path)
85
c.Assert(alive, Equals, true)
87
// Watch for life again, and check that agrees.
88
alive, watch, err = presence.AliveW(s.ZkConn, path)
90
c.Assert(alive, Equals, true)
91
assertNoChange(c, watch)
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")
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)
107
alive, watch, err := presence.AliveW(s.ZkConn, path)
109
c.Assert(alive, Equals, true)
110
assertNoChange(c, watch)
112
// Kill the Pinger; check the watch fires and Alive agrees.
115
assertChange(c, watch, false)
116
alive, err = presence.Alive(s.ZkConn, path)
118
c.Assert(alive, Equals, false)
120
// Check that the pinger's node was deleted.
121
stat, err := s.ZkConn.Exists(path)
123
c.Assert(stat, IsNil)
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")
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)
137
alive, watch, err := presence.AliveW(s.ZkConn, path)
139
c.Assert(alive, Equals, true)
140
assertNoChange(c, watch)
142
// Stop the Pinger; check the watch fires and Alive agrees.
145
assertChange(c, watch, false)
146
alive, watch, err = presence.AliveW(s.ZkConn, path)
148
c.Assert(alive, Equals, false)
150
// Check that we can Stop again.
154
// Check that the pinger's node is still present, but no changes have been seen.
155
stat, err := s.ZkConn.Exists(path)
157
c.Assert(stat, NotNil)
158
assertNoChange(c, watch)
160
// Start the Pinger again, and check the change is detected.
163
assertChange(c, watch, true)
166
func (s *PresenceSuite) TestWatchDeadnessChange(c *C) {
167
// Create a stale node.
168
p, err := presence.StartPinger(s.ZkConn, path, period)
172
time.Sleep(longEnough)
174
// Start watching for liveness.
175
alive, watch, err := presence.AliveW(s.ZkConn, path)
177
c.Assert(alive, Equals, false)
179
// Delete the node and check the watch doesn't fire.
180
err = s.ZkConn.Delete(path, -1)
182
assertNoChange(c, watch)
184
// Start a new Pinger and check the watch does fire.
185
p, err = presence.StartPinger(s.ZkConn, path, period)
188
assertChange(c, watch, true)
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))
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"`)
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"`)
206
func (s *PresenceSuite) TestDisconnectDeadWatch(c *C) {
207
// Create a target node.
208
p, err := presence.StartPinger(s.ZkConn, path, period)
213
// Start an alternate connection and ensure the node is stale.
214
altConn := testing.ZkConnect()
215
time.Sleep(longEnough)
217
// Start a watch using the alternate connection.
218
alive, watch, err := presence.AliveW(altConn, path)
220
c.Assert(alive, Equals, false)
222
// Kill the watch connection and check it's alerted.
224
assertClose(c, watch)
227
func (s *PresenceSuite) TestDisconnectMissingWatch(c *C) {
228
// Don't even create a target node.
230
// Start watching on an alternate connection.
231
altConn := testing.ZkConnect()
232
alive, watch, err := presence.AliveW(altConn, path)
234
c.Assert(alive, Equals, false)
236
// Kill the watch's connection and check it's alerted.
238
assertClose(c, watch)
241
func (s *PresenceSuite) TestDisconnectAliveWatch(c *C) {
242
// Start a Pinger on the main connection
243
p, err := presence.StartPinger(s.ZkConn, path, period)
247
// Start watching on an alternate connection.
248
altConn := testing.ZkConnect()
249
alive, watch, err := presence.AliveW(altConn, path)
251
c.Assert(alive, Equals, true)
253
// Kill the watch's connection and check it's alerted.
255
assertClose(c, watch)
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)
265
// Watch on the "main" connection.
266
alive, watch, err := presence.AliveW(s.ZkConn, path)
268
c.Assert(alive, Equals, true)
270
// Kill the pinger connection and check the watch notices.
272
assertChange(c, watch, false)
274
// Stop the pinger anyway; check we still get an error.
276
c.Assert(err, NotNil)
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")
283
dying := make(chan struct{})
284
dead := make(chan struct{})
286
// Start a pinger with a short delay so that WaitAlive() has to wait.
288
time.Sleep(period * 2)
289
p, err := presence.StartPinger(s.ZkConn, path, period)
297
// Wait for, and check, liveness.
298
err = presence.WaitAlive(s.ZkConn, path, longEnough)
304
func (s *PresenceSuite) TestDisconnectWaitAlive(c *C) {
305
// Start a new connection with a short lifespan.
306
altConn := testing.ZkConnect()
308
time.Sleep(period * 2)
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")
317
func (s *PresenceSuite) TestChildrenWatcher(c *C) {
318
w := presence.NewChildrenWatcher(s.ZkConn, "/nodes")
320
// Check initial event.
321
assertChange := func(added, removed []string) {
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")
331
assertChange(nil, nil)
332
assertNoChange := func() {
334
case ch := <-w.Changes():
335
c.Fatalf("got unexpected change: %#v", ch)
336
case <-time.After(longEnough):
341
// Create the node we're watching, check no change.
342
_, err := s.ZkConn.Create("/nodes", "", 0, zookeeper.WorldACL(zookeeper.PERM_ALL))
346
// Add a pinger, check it's noticed.
347
p1, err := presence.StartPinger(s.ZkConn, "/nodes/p1", period)
350
assertChange([]string{"p1"}, nil)
353
// Add another pinger, check it's noticed.
354
p2, err := presence.StartPinger(s.ZkConn, "/nodes/p2", period)
357
assertChange([]string{"p2"}, nil)
359
// Stop watcher, check closed.
362
assertClosed := func() {
364
case _, ok := <-w.Changes():
365
c.Assert(ok, Equals, false)
366
case <-time.After(longEnough):
367
c.Fatalf("changes channel not closed")
372
// Stop a pinger, wait long enough for it to be considered dead.
375
<-time.After(longEnough)
377
// Start a new watcher, check initial event.
378
w = presence.NewChildrenWatcher(s.ZkConn, "/nodes")
379
assertChange([]string{"p2"}, nil)
382
// Kill the remaining pinger, check it's noticed.
384
assertChange(nil, []string{"p2"})
387
// A few times, initially starting with p1 abandoned and subsequently
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)
394
assertChange([]string{"p1"}, nil)
397
// ...and so is its absence.
399
assertChange(nil, []string{"p1"})
403
// Stop the watcher, check closed again.