func TestServiceFutureSurvival(t *testing.T) { connect := connectPacket() connect.ClientID = "test" connect.CleanSession = false connack := connackPacket() connack.SessionPresent = true publish1 := packet.NewPublishPacket() publish1.Message.Topic = "test" publish1.Message.Payload = []byte("test") publish1.Message.QOS = 1 publish1.PacketID = 1 publish2 := packet.NewPublishPacket() publish2.Message.Topic = "test" publish2.Message.Payload = []byte("test") publish2.Message.QOS = 1 publish2.Dup = true publish2.PacketID = 1 puback := packet.NewPubackPacket() puback.PacketID = 1 broker1 := tools.NewFlow(). Receive(connect). Send(connack). Receive(publish1). Close() broker2 := tools.NewFlow(). Receive(connect). Send(connack). Receive(publish2). Send(puback). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker1, broker2) config := NewConfigWithClientID("tcp://localhost:"+port, "test") config.CleanSession = false s := NewService() s.Start(config) err := s.Publish("test", []byte("test"), 1, false).Wait() assert.NoError(t, err) s.Stop(true) <-done }
func TestClientFutureCancellation(t *testing.T) { publish := packet.NewPublishPacket() publish.Message.Topic = "test" publish.Message.Payload = []byte("test") publish.Message.QOS = 1 publish.PacketID = 1 broker := tools.NewFlow(). Receive(connectPacket()). Send(connackPacket()). Receive(publish). Close() done, port := fakeBroker(t, broker) c := New() c.Callback = func(msg *packet.Message, err error) { assert.Nil(t, msg) assert.Error(t, err) } connectFuture, err := c.Connect(NewConfig("tcp://localhost:" + port)) assert.NoError(t, err) assert.NoError(t, connectFuture.Wait()) assert.False(t, connectFuture.SessionPresent) assert.Equal(t, packet.ConnectionAccepted, connectFuture.ReturnCode) publishFuture, err := c.Publish("test", []byte("test"), 1, false) assert.NoError(t, err) assert.Equal(t, ErrFutureCanceled, publishFuture.Wait()) <-done }
func TestWebSocketCoalescedMessage(t *testing.T) { pkt := packet.NewPublishPacket() pkt.Message.Topic = "hello" pkt.Message.Payload = []byte("world") conn2, done := connectionPair("ws", func(conn1 Conn) { buf := make([]byte, pkt.Len()*2) pkt.Encode(buf) pkt.Encode(buf[pkt.Len():]) err := conn1.(*WebSocketConn).UnderlyingConn().WriteMessage(websocket.BinaryMessage, buf) assert.NoError(t, err) in, err := conn1.Receive() assert.Nil(t, in) assert.Equal(t, ConnectionClose, toError(err).Code()) }) in, err := conn2.Receive() assert.Nil(t, err) assert.Equal(t, pkt.String(), in.String()) in, err = conn2.Receive() assert.Nil(t, err) assert.Equal(t, pkt.String(), in.String()) err = conn2.Close() assert.NoError(t, err) in, err = conn2.Receive() assert.Nil(t, in) assert.Equal(t, NetworkError, toError(err).Code()) <-done }
func TestReceiveMessage(t *testing.T) { subscribe := packet.NewSubscribePacket() subscribe.PacketID = 1 subscribe.Subscriptions = []packet.Subscription{ {Topic: "test"}, } suback := packet.NewSubackPacket() suback.PacketID = 1 suback.ReturnCodes = []uint8{0} publish := packet.NewPublishPacket() publish.Message = packet.Message{ Topic: "test", Payload: []byte("test"), Retain: true, } broker := tools.NewFlow(). Receive(connectPacket()). Send(connackPacket()). Receive(subscribe). Send(suback). Send(publish). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker) msg, err := ReceiveMessage(NewConfig("tcp://localhost:"+port), "test", 0) assert.NoError(t, err) assert.Equal(t, publish.Message.String(), msg.String()) <-done }
func TestServiceCommandsInCallback(t *testing.T) { subscribe := packet.NewSubscribePacket() subscribe.Subscriptions = []packet.Subscription{{Topic: "test"}} subscribe.PacketID = 1 suback := packet.NewSubackPacket() suback.ReturnCodes = []uint8{0} suback.PacketID = 1 publish := packet.NewPublishPacket() publish.Message.Topic = "test" publish.Message.Payload = []byte("test") broker := tools.NewFlow(). Receive(connectPacket()). Send(connackPacket()). Receive(subscribe). Send(suback). Receive(publish). Send(publish). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker) message := make(chan struct{}) offline := make(chan struct{}) s := NewService() s.OnlineCallback = func(resumed bool) { assert.False(t, resumed) s.Subscribe("test", 0) s.Publish("test", []byte("test"), 0, false) } s.OfflineCallback = func() { close(offline) } s.MessageCallback = func(msg *packet.Message) { assert.Equal(t, "test", msg.Topic) assert.Equal(t, []byte("test"), msg.Payload) assert.Equal(t, uint8(0), msg.QOS) assert.False(t, msg.Retain) close(message) } s.Start(NewConfig("tcp://localhost:" + port)) <-message s.Stop(true) <-offline <-done }
func TestClientLogger(t *testing.T) { subscribe := packet.NewSubscribePacket() subscribe.Subscriptions = []packet.Subscription{{Topic: "test"}} subscribe.PacketID = 1 suback := packet.NewSubackPacket() suback.ReturnCodes = []uint8{0} suback.PacketID = 1 publish := packet.NewPublishPacket() publish.Message.Topic = "test" publish.Message.Payload = []byte("test") broker := tools.NewFlow(). Receive(connectPacket()). Send(connackPacket()). Receive(subscribe). Send(suback). Receive(publish). Send(publish). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker) wait := make(chan struct{}) c := New() c.Callback = func(msg *packet.Message, err error) { close(wait) } var counter uint32 c.Logger = func(msg string) { atomic.AddUint32(&counter, 1) } future, _ := c.Connect(NewConfig("tcp://localhost:" + port)) future.Wait() subscribeFuture, _ := c.Subscribe("test", 0) subscribeFuture.Wait() publishFuture, _ := c.Publish("test", []byte("test"), 0, false) publishFuture.Wait() <-wait c.Disconnect() <-done assert.Equal(t, uint32(8), counter) }
func TestClientSessionResumption(t *testing.T) { connect := connectPacket() connect.ClientID = "test" connect.CleanSession = false publish1 := packet.NewPublishPacket() publish1.Message.Topic = "test" publish1.Message.Payload = []byte("test") publish1.Message.QOS = 1 publish1.PacketID = 1 puback1 := packet.NewPubackPacket() puback1.PacketID = 1 broker := tools.NewFlow(). Receive(connect). Send(connackPacket()). Receive(publish1). Send(puback1). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker) c := New() c.Session.SavePacket(outgoing, publish1) c.Session.PacketID() c.Callback = errorCallback(t) config := NewConfig("tcp://localhost:" + port) config.ClientID = "test" config.CleanSession = false connectFuture, err := c.Connect(config) assert.NoError(t, err) assert.NoError(t, connectFuture.Wait()) assert.False(t, connectFuture.SessionPresent) assert.Equal(t, packet.ConnectionAccepted, connectFuture.ReturnCode) time.Sleep(20 * time.Millisecond) err = c.Disconnect() assert.NoError(t, err) <-done pkts, err := c.Session.AllPackets(outgoing) assert.NoError(t, err) assert.Equal(t, 0, len(pkts)) }
func TestClientDisconnectWithTimeout(t *testing.T) { publish := packet.NewPublishPacket() publish.Message.Topic = "test" publish.Message.Payload = []byte("test") publish.Message.QOS = 1 publish.PacketID = 1 puback := packet.NewPubackPacket() puback.PacketID = 1 wait := func() { time.Sleep(100 * time.Millisecond) } broker := tools.NewFlow(). Receive(connectPacket()). Send(connackPacket()). Receive(publish). Run(wait). Send(puback). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker) c := New() c.Callback = errorCallback(t) connectFuture, err := c.Connect(NewConfig("tcp://localhost:" + port)) assert.NoError(t, err) assert.NoError(t, connectFuture.Wait()) assert.False(t, connectFuture.SessionPresent) assert.Equal(t, packet.ConnectionAccepted, connectFuture.ReturnCode) publishFuture, err := c.Publish("test", []byte("test"), 1, false) assert.NoError(t, err) assert.NotNil(t, publishFuture) err = c.Disconnect(10 * time.Second) assert.NoError(t, err) <-done assert.NoError(t, publishFuture.Wait()) list, err := c.Session.AllPackets(outgoing) assert.NoError(t, err) assert.Equal(t, 0, len(list)) }
func TestClientHardDisconnect(t *testing.T) { connect := connectPacket() connect.ClientID = "test" connect.CleanSession = false publish := packet.NewPublishPacket() publish.Message.Topic = "test" publish.Message.Payload = []byte("test") publish.Message.QOS = 1 publish.PacketID = 1 broker := tools.NewFlow(). Receive(connect). Send(connackPacket()). Receive(publish). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker) c := New() c.Callback = errorCallback(t) config := NewConfig("tcp://localhost:" + port) config.ClientID = "test" config.CleanSession = false connectFuture, err := c.Connect(config) assert.NoError(t, err) assert.NoError(t, connectFuture.Wait()) assert.False(t, connectFuture.SessionPresent) assert.Equal(t, packet.ConnectionAccepted, connectFuture.ReturnCode) publishFuture, err := c.Publish("test", []byte("test"), 1, false) assert.NoError(t, err) assert.NotNil(t, publishFuture) err = c.Disconnect() assert.NoError(t, err) assert.Equal(t, ErrFutureCanceled, publishFuture.Wait()) <-done list, err := c.Session.AllPackets(outgoing) assert.NoError(t, err) assert.Equal(t, 1, len(list)) }
func TestWebSocketNotBinaryMessage(t *testing.T) { pkt := packet.NewPublishPacket() pkt.Message.Topic = "hello" pkt.Message.Payload = []byte("world") conn2, done := connectionPair("ws", func(conn1 Conn) { err := conn1.(*WebSocketConn).UnderlyingConn().WriteMessage(websocket.TextMessage, []byte("hello")) assert.NoError(t, err) }) in, err := conn2.Receive() assert.Equal(t, NetworkError, toError(err).Code()) assert.Nil(t, in) <-done }
// PublishMessage will send a PublishPacket containing the passed message. It will // return a PublishFuture that gets completed once the quality of service flow // has been completed. func (c *Client) PublishMessage(msg *packet.Message) (*PublishFuture, error) { c.mutex.Lock() defer c.mutex.Unlock() // check if connected if c.state.get() != clientConnected { return nil, ErrClientNotConnected } // allocate packet publish := packet.NewPublishPacket() publish.Message = *msg // set packet id if msg.QOS > 0 { publish.PacketID = c.Session.PacketID() } // create future future := &PublishFuture{} future.initialize() // store future c.futureStore.put(publish.PacketID, future) // store packet if at least qos 1 if msg.QOS > 0 { err := c.Session.SavePacket(outgoing, publish) if err != nil { return nil, c.cleanup(err, true, false) } } // send packet err := c.send(publish, true) if err != nil { return nil, c.cleanup(err, false, false) } // complete and remove qos 0 future if msg.QOS == 0 { future.complete() c.futureStore.del(publish.PacketID) } return future, nil }
func TestMemorySessionPacketStore(t *testing.T) { session := NewMemorySession() publish := packet.NewPublishPacket() publish.PacketID = 1 pkt, err := session.LookupPacket(incoming, 1) assert.NoError(t, err) assert.Nil(t, pkt) err = session.SavePacket(incoming, publish) assert.NoError(t, err) pkt, err = session.LookupPacket(incoming, 1) assert.NoError(t, err) assert.Equal(t, publish, pkt) list, err := session.AllPackets(incoming) assert.NoError(t, err) assert.Equal(t, 1, len(list)) err = session.DeletePacket(incoming, 1) assert.NoError(t, err) pkt, err = session.LookupPacket(incoming, 1) assert.NoError(t, err) assert.Nil(t, pkt) list, err = session.AllPackets(incoming) assert.NoError(t, err) assert.Equal(t, 0, len(list)) err = session.SavePacket(outgoing, publish) assert.NoError(t, err) list, err = session.AllPackets(outgoing) assert.NoError(t, err) assert.Equal(t, 1, len(list)) err = session.Reset() assert.NoError(t, err) list, err = session.AllPackets(outgoing) assert.NoError(t, err) assert.Equal(t, 0, len(list)) }
func abstractConnBigBufferedSendAfterCloseTest(t *testing.T, protocol string) { conn2, done := connectionPair(protocol, func(conn1 Conn) { err := conn1.Close() assert.NoError(t, err) }) pkt, err := conn2.Receive() assert.Nil(t, pkt) assert.Equal(t, ConnectionClose, toError(err).Code()) pub := packet.NewPublishPacket() pub.Message.Topic = "hello" pub.Message.Payload = make([]byte, 6400) // <- bigger than write buffer err = conn2.BufferedSend(pub) assert.Equal(t, NetworkError, toError(err).Code()) <-done }
func TestClearRetainedMessage(t *testing.T) { publish := packet.NewPublishPacket() publish.Message.Topic = "test" publish.Message.Payload = nil publish.Message.Retain = true broker := tools.NewFlow(). Receive(connectPacket()). Send(connackPacket()). Receive(publish). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker) err := ClearRetainedMessage(NewConfig("tcp://localhost:"+port), "test") assert.NoError(t, err) <-done }
func TestNetConnReadTimeoutAfterDetect(t *testing.T) { conn2, done := connectionPair("tcp", func(conn1 Conn) { pkt := packet.NewPublishPacket() pkt.Message.Topic = "foo/bar/baz" buf := make([]byte, pkt.Len()) pkt.Encode(buf) netConn := conn1.(*NetConn) _, err := netConn.UnderlyingConn().Write(buf[0 : len(buf)-1]) // <- not all of the bytes assert.NoError(t, err) }) conn2.SetReadTimeout(10 * time.Millisecond) pkt, err := conn2.Receive() assert.Nil(t, pkt) assert.Equal(t, NetworkError, toError(err).Code()) assert.Equal(t, ErrReadTimeout, toError(err).Err()) <-done }
func TestNetConnCloseWhileReadError(t *testing.T) { conn2, done := connectionPair("tcp", func(conn1 Conn) { pkt := packet.NewPublishPacket() pkt.Message.Topic = "foo/bar/baz" buf := make([]byte, pkt.Len()) pkt.Encode(buf) netConn := conn1.(*NetConn) _, err := netConn.UnderlyingConn().Write(buf[0:7]) // <- incomplete packet assert.NoError(t, err) err = netConn.UnderlyingConn().Close() assert.NoError(t, err) }) pkt, err := conn2.Receive() assert.Nil(t, pkt) assert.Equal(t, NetworkError, toError(err).Code()) <-done }
func TestPublishMessage(t *testing.T) { publish := packet.NewPublishPacket() publish.Message = packet.Message{ Topic: "test", Payload: []byte("test"), Retain: true, } broker := tools.NewFlow(). Receive(connectPacket()). Send(connackPacket()). Receive(publish). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker) err := PublishMessage(NewConfig("tcp://localhost:"+port), &publish.Message) assert.NoError(t, err) <-done }
func BenchmarkWebSocketConnBuffered(b *testing.B) { pkt := packet.NewPublishPacket() pkt.Message.Topic = "foo/bar/baz" conn2, done := connectionPair("ws", func(conn1 Conn) { for i := 0; i < b.N; i++ { err := conn1.BufferedSend(pkt) if err != nil { panic(err) } } }) for i := 0; i < b.N; i++ { _, err := conn2.Receive() if err != nil { panic(err) } } b.SetBytes(int64(pkt.Len() * 2)) <-done }
func TestClientPublishSubscribeQOS2(t *testing.T) { subscribe := packet.NewSubscribePacket() subscribe.Subscriptions = []packet.Subscription{{Topic: "test", QOS: 2}} subscribe.PacketID = 1 suback := packet.NewSubackPacket() suback.ReturnCodes = []uint8{2} suback.PacketID = 1 publish := packet.NewPublishPacket() publish.Message.Topic = "test" publish.Message.Payload = []byte("test") publish.Message.QOS = 2 publish.PacketID = 2 pubrec := packet.NewPubrecPacket() pubrec.PacketID = 2 pubrel := packet.NewPubrelPacket() pubrel.PacketID = 2 pubcomp := packet.NewPubcompPacket() pubcomp.PacketID = 2 broker := tools.NewFlow(). Receive(connectPacket()). Send(connackPacket()). Receive(subscribe). Send(suback). Receive(publish). Send(pubrec). Receive(pubrel). Send(pubcomp). Send(publish). Receive(pubrec). Send(pubrel). Receive(pubcomp). Receive(disconnectPacket()). End() done, port := fakeBroker(t, broker) wait := make(chan struct{}) c := New() c.Callback = func(msg *packet.Message, err error) { assert.NoError(t, err) assert.Equal(t, "test", msg.Topic) assert.Equal(t, []byte("test"), msg.Payload) assert.Equal(t, uint8(2), msg.QOS) assert.False(t, msg.Retain) close(wait) } future, err := c.Connect(NewConfig("tcp://localhost:" + port)) assert.NoError(t, err) assert.NoError(t, future.Wait()) assert.False(t, future.SessionPresent) assert.Equal(t, packet.ConnectionAccepted, future.ReturnCode) subscribeFuture, err := c.Subscribe("test", 2) assert.NoError(t, err) assert.NoError(t, subscribeFuture.Wait()) assert.Equal(t, []uint8{2}, subscribeFuture.ReturnCodes) publishFuture, err := c.Publish("test", []byte("test"), 2, false) assert.NoError(t, err) assert.NoError(t, publishFuture.Wait()) <-wait err = c.Disconnect() assert.NoError(t, err) <-done in, err := c.Session.AllPackets(incoming) assert.NoError(t, err) assert.Equal(t, 0, len(in)) out, err := c.Session.AllPackets(outgoing) assert.NoError(t, err) assert.Equal(t, 0, len(out)) }