func (s *TestSuite) TestConnectBackoff(t *C) { /** * Connect() should wait between attempts, using pct.Backoff (pct/backoff.go). */ ws, err := client.NewWebsocketClient(s.logger, s.api, "agent", nil) t.Assert(err, IsNil) ws.Connect() c := <-mock.ClientConnectChan <-ws.ConnectChan() defer ws.Disconnect() // 0s wait, connect, err="Lost connection", // 1s wait, connect, err="Lost connection", // 3s wait, connect, ok t0 := time.Now() for i := 0; i < 2; i++ { mock.DisconnectClient(c) ws.Connect() c = <-mock.ClientConnectChan <-ws.ConnectChan() // connect ack } d := time.Now().Sub(t0) if d < time.Duration(3*time.Second) { t.Errorf("Exponential backoff wait time between connect attempts: %s\n", d) } }
func (s *TestSuite) TestApiDisconnect(t *C) { /** * If using direct interface, Recv() should return error if API disconnects. */ ws, err := client.NewWebsocketClient(s.logger, s.api, "agent", nil) t.Assert(err, IsNil) ws.Connect() c := <-mock.ClientConnectChan <-ws.ConnectChan() // No error yet. got := test.WaitErr(ws.ErrorChan()) t.Assert(len(got), Equals, 0) mock.DisconnectClient(c) /** * I cannot provoke an error on websocket.Send(), only Receive(). * Perhaps errors (e.g. ws closed) are only reported on recv? * This only affect the logger since it's ws send-only: it will * need a goroutine blocking on Recieve() that, upon error, notifies * the sending goroutine to reconnect. */ var data interface{} err = ws.Recv(data, 5) t.Assert(err, NotNil) // EOF due to disconnect. }
func (s *TestSuite) TearDownTest(t *C) { // Disconnect all clients. for _, c := range mock.Clients { mock.DisconnectClient(c) } for _, c := range mock.ClientsWss { mock.DisconnectClientWss(c) } }
func (s *TestSuite) TestChannelsAfterReconnect(t *C) { /** * Client send/recv chans should work after disconnect and reconnect. */ ws, err := client.NewWebsocketClient(s.logger, s.api, "agent", nil) t.Assert(err, IsNil) ws.Start() defer ws.Stop() defer ws.Disconnect() ws.Connect() c := <-mock.ClientConnectChan <-ws.ConnectChan() // connect ack // Send cmd and wait for reply to ensure we're fully connected. cmd := &proto.Cmd{ User: "******", Ts: time.Now(), Cmd: "Status", } c.SendChan <- cmd got := test.WaitCmd(ws.RecvChan()) t.Assert(len(got), Equals, 1) reply := cmd.Reply(nil, nil) ws.SendChan() <- reply data := test.WaitData(c.RecvChan) t.Assert(len(data), Equals, 1) // Disconnect client. mock.DisconnectClient(c) <-ws.ConnectChan() // disconnect ack // Reconnect client and send/recv again. ws.Connect() c = <-mock.ClientConnectChan <-ws.ConnectChan() // connect ack c.SendChan <- cmd got = test.WaitCmd(ws.RecvChan()) t.Assert(len(got), Equals, 1) reply = cmd.Reply(nil, nil) ws.SendChan() <- reply data = test.WaitData(c.RecvChan) t.Assert(len(data), Equals, 1) }
func (s *TestSuite) TestErrorChan(t *C) { /** * When client disconnects due to send or recv error, * it should send the error on its ErrorChan(). */ ws, err := client.NewWebsocketClient(s.logger, s.api, "agent") t.Assert(err, IsNil) ws.Start() defer ws.Stop() ws.Connect() c := <-mock.ClientConnectChan <-ws.ConnectChan() // No error yet. got := test.WaitErr(ws.ErrorChan()) t.Assert(len(got), Equals, 0) // API sends Cmd to client. cmd := &proto.Cmd{ User: "******", Ts: time.Now(), Cmd: "Status", } c.SendChan <- cmd // No error yet. got = test.WaitErr(ws.ErrorChan()) t.Assert(len(got), Equals, 0) // Disconnect the client. mock.DisconnectClient(c) // Client should send error from disconnect. got = test.WaitErr(ws.ErrorChan()) t.Assert(len(got), Equals, 1) t.Assert(got[0], NotNil) err = ws.Disconnect() t.Assert(err, IsNil) }
func (s *TestSuite) TestChannelsApiDisconnect(t *C) { /** * If using chnanel interface, ErrorChan() should return error if API disconnects. */ ws, err := client.NewWebsocketClient(s.logger, s.api, "agent", nil) t.Assert(err, IsNil) var gotErr error doneChan := make(chan bool) go func() { gotErr = <-ws.ErrorChan() doneChan <- true }() ws.Start() defer ws.Stop() defer ws.Disconnect() ws.Connect() c := <-mock.ClientConnectChan <-ws.ConnectChan() // connect ack // No error yet. select { case <-doneChan: t.Error("No error yet") default: } mock.DisconnectClient(c) // Wait for error. select { case <-doneChan: t.Check(gotErr, NotNil) // EOF due to disconnect. case <-time.After(1 * time.Second): t.Error("Get error") } }