// This error will be delivered via C errno, since ZK unfortunately // only provides the handler back from zookeeper_init(). func (s *S) TestInitErrorThroughErrno(c *C) { conn, watch, err := zk.Dial("bad-domain-without-port", 5e9) if conn != nil { conn.Close() } if watch != nil { go func() { for { _, ok := <-watch if !ok { break } } }() } c.Assert(conn, IsNil) c.Assert(watch, IsNil) c.Assert(err, ErrorMatches, "zookeeper: dial: invalid argument") }
func (s *S) TestRecvTimeoutInitParameter(c *C) { conn, watch, err := zk.Dial(s.zkAddr, 0) c.Assert(err, IsNil) defer conn.Close() select { case <-watch: c.Fatal("Watch fired") default: } for i := 0; i != 1000; i++ { _, _, err := conn.Get("/zookeeper") if err != nil { c.Check(zk.IsError(err, zk.ZOPERATIONTIMEOUT), Equals, true, Commentf("%v", err)) c.SucceedNow() } } c.Fatal("Operation didn't timeout") }
func (s *S) init(c *C) (*zk.Conn, chan zk.Event) { c.Logf("init dialling %q", s.zkAddr) conn, watch, err := zk.Dial(s.zkAddr, 5e9) c.Assert(err, IsNil) s.handles = append(s.handles, conn) bufferedWatch := make(chan zk.Event, 256) select { case e, ok := <-watch: c.Assert(ok, Equals, true) c.Assert(e.Type, Equals, zk.EVENT_SESSION) c.Assert(e.State, Equals, zk.STATE_CONNECTED) bufferedWatch <- e case <-time.After(5e9): c.Fatalf("timeout dialling zookeeper addr %v", s.zkAddr) } s.liveWatches += 1 go func() { loop: for { select { case event, ok := <-watch: if !ok { close(bufferedWatch) break loop } select { case bufferedWatch <- event: default: panic("Too many events in buffered watch!") } } } s.deadWatches <- true }() return conn, bufferedWatch }
func (s *S) TestConcurrentClose(c *C) { // make sure the server is ready to receive connections. s.init(c) // Close should wait until all outstanding requests have // completed before returning. The idea of this test is that // any request that requests or changes a zookeeper node must // make at least one round trip to the server, so we interpose a // proxy between the client and the server which can stop all // incoming traffic on demand, thus blocking the request until // we want it to unblock. // // We assume that all requests take less than 0.1s to complete, // thus when we wait below, neither of the above goroutines // should complete within the allotted time (the request because // it's waiting for a reply from the server and the close // because it's waiting for the request to complete). If the // locking doesn't work, the Close will return early. If the // proxy blocking doesn't work, the request will return early. // // When we reenable incoming messages from the server, both // goroutines should complete. We can't tell which completes // first, but the fact that the close blocked is sufficient to // tell that the locking is working correctly. for i, f := range requestFuncs { c.Logf("iter %d", i) p := newProxy(c, s.zkAddr) conn, watch, err := zk.Dial(p.addr(), 5e9) c.Assert(err, IsNil) c.Assert((<-watch).Ok(), Equals, true) // sanity check that the connection is actually // up and running. _, err = conn.Exists("/nothing") c.Assert(err, IsNil) p.stopIncoming() reqDone := make(chan bool) closeDone := make(chan bool) go func() { f(conn, "/closetest") reqDone <- true }() go func() { // sleep for long enough for the request to be initiated and the read lock taken. time.Sleep(0.05e9) conn.Close() closeDone <- true }() select { case <-reqDone: c.Fatalf("request %d finished early", i) case <-closeDone: c.Fatalf("request %d close finished early", i) case <-time.After(0.1e9): } p.startIncoming() for reqDone != nil || closeDone != nil { select { case <-reqDone: reqDone = nil case <-closeDone: closeDone = nil case <-time.After(0.4e9): c.Fatalf("request %d timed out waiting for req (%p) and close(%p)", i, reqDone, closeDone) } } p.close() err = f(conn, "/closetest") c.Check(zk.IsError(err, zk.ZCLOSING), Equals, true, Commentf("%v", err)) } }