Example #1
0
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)
	}
}
Example #2
0
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.
}
Example #3
0
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)
	}
}
Example #4
0
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)
}
Example #6
0
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")
	}
}