mqtt/server/internal/clients/clients_test.go

1098 lines
24 KiB
Go
Raw Normal View History

2022-08-15 23:06:20 +03:00
package clients
import (
"errors"
"io"
"io/ioutil"
"net"
"sync/atomic"
"testing"
"time"
"github.com/mochi-co/mqtt/server/events"
"github.com/mochi-co/mqtt/server/internal/circ"
"github.com/mochi-co/mqtt/server/internal/packets"
"github.com/mochi-co/mqtt/server/listeners/auth"
"github.com/mochi-co/mqtt/server/system"
"github.com/stretchr/testify/require"
)
var testClientStop = errors.New("test stop")
func genClient() *Client {
c, _ := net.Pipe()
return NewClient(c, circ.NewReader(128, 8), circ.NewWriter(128, 8), new(system.Info))
}
func TestNewClients(t *testing.T) {
cl := New()
require.NotNil(t, cl.internal)
}
func BenchmarkNewClients(b *testing.B) {
for n := 0; n < b.N; n++ {
New()
}
}
func TestClientsAdd(t *testing.T) {
cl := New()
cl.Add(&Client{ID: "t1"})
require.Contains(t, cl.internal, "t1")
}
func BenchmarkClientsAdd(b *testing.B) {
cl := New()
client := &Client{ID: "t1"}
for n := 0; n < b.N; n++ {
cl.Add(client)
}
}
func TestClientsGet(t *testing.T) {
cl := New()
cl.Add(&Client{ID: "t1"})
cl.Add(&Client{ID: "t2"})
require.Contains(t, cl.internal, "t1")
require.Contains(t, cl.internal, "t2")
client, ok := cl.Get("t1")
require.Equal(t, true, ok)
require.Equal(t, "t1", client.ID)
}
func BenchmarkClientsGet(b *testing.B) {
cl := New()
cl.Add(&Client{ID: "t1"})
for n := 0; n < b.N; n++ {
cl.Get("t1")
}
}
func TestClientsLen(t *testing.T) {
cl := New()
cl.Add(&Client{ID: "t1"})
cl.Add(&Client{ID: "t2"})
require.Contains(t, cl.internal, "t1")
require.Contains(t, cl.internal, "t2")
require.Equal(t, 2, cl.Len())
}
func BenchmarkClientsLen(b *testing.B) {
cl := New()
cl.Add(&Client{ID: "t1"})
for n := 0; n < b.N; n++ {
cl.Len()
}
}
func TestClientsDelete(t *testing.T) {
cl := New()
cl.Add(&Client{ID: "t1"})
require.Contains(t, cl.internal, "t1")
cl.Delete("t1")
_, ok := cl.Get("t1")
require.Equal(t, false, ok)
require.Nil(t, cl.internal["t1"])
}
func BenchmarkClientsDelete(b *testing.B) {
cl := New()
cl.Add(&Client{ID: "t1"})
for n := 0; n < b.N; n++ {
cl.Delete("t1")
}
}
func TestClientsGetByListener(t *testing.T) {
cl := New()
cl.Add(&Client{ID: "t1", Listener: "tcp1"})
cl.Add(&Client{ID: "t2", Listener: "ws1"})
require.Contains(t, cl.internal, "t1")
require.Contains(t, cl.internal, "t2")
clients := cl.GetByListener("tcp1")
require.NotEmpty(t, clients)
require.Equal(t, 1, len(clients))
require.Equal(t, "tcp1", clients[0].Listener)
}
func BenchmarkClientsGetByListener(b *testing.B) {
cl := New()
cl.Add(&Client{ID: "t1", Listener: "tcp1"})
cl.Add(&Client{ID: "t2", Listener: "ws1"})
for n := 0; n < b.N; n++ {
cl.GetByListener("tcp1")
}
}
func TestNewClient(t *testing.T) {
cl := genClient()
require.NotNil(t, cl)
require.NotNil(t, cl.Inflight.internal)
require.NotNil(t, cl.Subscriptions)
require.NotNil(t, cl.R)
require.NotNil(t, cl.W)
require.Nil(t, cl.StopCause())
}
func TestClientInfoUnknown(t *testing.T) {
cl := genClient()
cl.ID = "testid"
cl.Listener = "testlistener"
cl.conn = nil
require.Equal(t, events.Client{
ID: "testid",
Remote: "unknown",
Listener: "testlistener",
}, cl.Info())
}
func TestClientInfoKnown(t *testing.T) {
c1, c2 := net.Pipe()
defer c1.Close()
defer c2.Close()
cl := genClient()
cl.ID = "ID"
cl.Listener = "L"
cl.conn = c1
require.Equal(t, events.Client{
ID: "ID",
Remote: c1.RemoteAddr().String(),
Listener: "L",
}, cl.Info())
}
func BenchmarkNewClient(b *testing.B) {
c, _ := net.Pipe()
for n := 0; n < b.N; n++ {
NewClient(c, circ.NewReader(16, 4), circ.NewWriter(16, 4), nil)
}
}
func TestNewClientStub(t *testing.T) {
cl := NewClientStub(nil)
require.NotNil(t, cl)
require.NotNil(t, cl.Inflight.internal)
require.NotNil(t, cl.Subscriptions)
}
func BenchmarkNewClientStub(b *testing.B) {
for n := 0; n < b.N; n++ {
NewClientStub(nil)
}
}
func TestClientIdentify(t *testing.T) {
cl := genClient()
pk := packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Connect,
Remaining: 16,
},
ProtocolName: []byte{'M', 'Q', 'T', 'T'},
ProtocolVersion: 4,
CleanSession: true,
Keepalive: 60,
ClientIdentifier: "mochi",
}
cl.Identify("tcp1", pk, new(auth.Allow))
require.Equal(t, pk.Keepalive, cl.keepalive)
require.Equal(t, pk.CleanSession, cl.CleanSession)
require.Equal(t, pk.ClientIdentifier, cl.ID)
}
func BenchmarkClientIdentify(b *testing.B) {
cl := genClient()
pk := packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Connect,
Remaining: 16,
},
ProtocolName: []byte{'M', 'Q', 'T', 'T'},
ProtocolVersion: 4,
CleanSession: true,
Keepalive: 60,
ClientIdentifier: "mochi",
}
for n := 0; n < b.N; n++ {
cl.Identify("tcp1", pk, new(auth.Allow))
}
}
func TestClientIdentifyNoID(t *testing.T) {
cl := genClient()
pk := packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Connect,
Remaining: 16,
},
ProtocolName: []byte{'M', 'Q', 'T', 'T'},
ProtocolVersion: 4,
CleanSession: true,
Keepalive: 60,
}
cl.Identify("tcp1", pk, new(auth.Allow))
require.NotEmpty(t, cl.ID)
}
func TestClientIdentifyLWT(t *testing.T) {
cl := genClient()
pk := packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Connect,
Remaining: 16,
},
ProtocolName: []byte{'M', 'Q', 'T', 'T'},
ProtocolVersion: 4,
CleanSession: true,
Keepalive: 60,
ClientIdentifier: "mochi",
WillFlag: true,
WillTopic: "lwt",
WillMessage: []byte("lol gg"),
WillQos: 1,
WillRetain: false,
}
cl.Identify("tcp1", pk, new(auth.Allow))
require.Equal(t, pk.WillTopic, cl.LWT.Topic)
require.Equal(t, pk.WillMessage, cl.LWT.Message)
require.Equal(t, pk.WillQos, cl.LWT.Qos)
require.Equal(t, pk.WillRetain, cl.LWT.Retain)
}
func TestClientNextPacketID(t *testing.T) {
cl := genClient()
require.Equal(t, uint32(1), cl.NextPacketID())
require.Equal(t, uint32(2), cl.NextPacketID())
cl.packetID = uint32(65534)
require.Equal(t, uint32(65535), cl.NextPacketID())
require.Equal(t, uint32(1), cl.NextPacketID())
}
func BenchmarkClientNextPacketID(b *testing.B) {
cl := genClient()
for n := 0; n < b.N; n++ {
cl.NextPacketID()
}
}
func TestClientNoteSubscription(t *testing.T) {
cl := genClient()
cl.NoteSubscription("a/b/c", 0)
require.Contains(t, cl.Subscriptions, "a/b/c")
require.Equal(t, byte(0), cl.Subscriptions["a/b/c"])
}
func BenchmarkClientNoteSubscription(b *testing.B) {
cl := genClient()
for n := 0; n < b.N; n++ {
cl.NoteSubscription("a/b/c", 0)
}
}
func TestClientForgetSubscription(t *testing.T) {
cl := genClient()
require.NotNil(t, cl)
cl.Subscriptions = map[string]byte{
"a/b/c/": 1,
}
cl.ForgetSubscription("a/b/c/")
require.Empty(t, cl.Subscriptions["a/b/c"])
}
func BenchmarkClientForgetSubscription(b *testing.B) {
cl := genClient()
for n := 0; n < b.N; n++ {
cl.NoteSubscription("a/b/c", 0)
cl.ForgetSubscription("a/b/c/")
}
}
func TestClientRefreshDeadline(t *testing.T) {
cl := genClient()
cl.refreshDeadline(10)
// How do we check net.Conn deadline?
require.NotNil(t, cl.conn)
}
func BenchmarkClientRefreshDeadline(b *testing.B) {
cl := genClient()
for n := 0; n < b.N; n++ {
cl.refreshDeadline(10)
}
}
func TestClientStart(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
time.Sleep(time.Millisecond)
require.Equal(t, uint32(1), atomic.LoadUint32(&cl.R.State))
require.Equal(t, uint32(2), atomic.LoadUint32(&cl.W.State))
}
func BenchmarkClientStart(b *testing.B) {
cl := genClient()
defer cl.Stop(testClientStop)
for n := 0; n < b.N; n++ {
cl.Start()
}
}
func TestClientReadFixedHeader(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
cl.R.Set([]byte{packets.Connect << 4, 0x00}, 0, 2)
cl.R.SetPos(0, 2)
fh := new(packets.FixedHeader)
err := cl.ReadFixedHeader(fh)
require.NoError(t, err)
require.Equal(t, int64(2), atomic.LoadInt64(&cl.systemInfo.BytesRecv))
tail, head := cl.R.GetPos()
require.Equal(t, int64(2), tail)
require.Equal(t, int64(2), head)
}
func TestClientReadFixedHeaderDecodeError(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
o := make(chan error)
go func() {
fh := new(packets.FixedHeader)
cl.R.Set([]byte{packets.Connect<<4 | 1<<1, 0x00, 0x00}, 0, 2)
cl.R.SetPos(0, 2)
o <- cl.ReadFixedHeader(fh)
}()
time.Sleep(time.Millisecond)
require.Error(t, <-o)
}
func TestClientReadFixedHeaderReadEOF(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
o := make(chan error)
go func() {
fh := new(packets.FixedHeader)
cl.R.Set([]byte{packets.Connect << 4, 0x00}, 0, 2)
cl.R.SetPos(0, 1)
o <- cl.ReadFixedHeader(fh)
}()
time.Sleep(time.Millisecond)
cl.R.Stop()
err := <-o
require.Error(t, err)
require.Equal(t, io.EOF, err)
}
func TestClientReadFixedHeaderNoLengthTerminator(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
o := make(chan error)
go func() {
fh := new(packets.FixedHeader)
err := cl.R.Set([]byte{packets.Connect << 4, 0xd5, 0x86, 0xf9, 0x9e, 0x01}, 0, 5)
require.NoError(t, err)
cl.R.SetPos(0, 5)
o <- cl.ReadFixedHeader(fh)
}()
time.Sleep(time.Millisecond)
require.Error(t, <-o)
}
func TestClientReadOK(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
// Two packets in a row...
b := []byte{
byte(packets.Publish << 4), 18, // Fixed header
0, 5, // Topic Name - LSB+MSB
'a', '/', 'b', '/', 'c', // Topic Name
'h', 'e', 'l', 'l', 'o', ' ', 'm', 'o', 'c', 'h', 'i', // Payload,
byte(packets.Publish << 4), 11, // Fixed header
0, 5, // Topic Name - LSB+MSB
'd', '/', 'e', '/', 'f', // Topic Name
'y', 'e', 'a', 'h', // Payload
}
err := cl.R.Set(b, 0, len(b))
require.NoError(t, err)
cl.R.SetPos(0, int64(len(b)))
o := make(chan error)
var pks []packets.Packet
go func() {
o <- cl.Read(func(cl *Client, pk packets.Packet) error {
pks = append(pks, pk)
return nil
})
}()
time.Sleep(time.Millisecond)
cl.R.Stop()
err = <-o
require.Error(t, err)
require.Equal(t, io.EOF, err)
require.Equal(t, 2, len(pks))
require.Equal(t, pks, []packets.Packet{
{
FixedHeader: packets.FixedHeader{
Type: packets.Publish,
Remaining: 18,
},
TopicName: "a/b/c",
Payload: []byte("hello mochi"),
},
{
FixedHeader: packets.FixedHeader{
Type: packets.Publish,
Remaining: 11,
},
TopicName: "d/e/f",
Payload: []byte("yeah"),
},
})
require.Equal(t, int64(len(b)), atomic.LoadInt64(&cl.systemInfo.BytesRecv))
require.Equal(t, int64(2), atomic.LoadInt64(&cl.systemInfo.MessagesRecv))
}
func TestClientClearBuffers(t *testing.T) {
cl := genClient()
cl.Start()
cl.Stop(testClientStop)
cl.ClearBuffers()
require.Nil(t, cl.W)
require.Nil(t, cl.R)
}
func TestClientReadDone(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
cl.State.Done = 1
err := cl.Read(func(cl *Client, pk packets.Packet) error {
return nil
})
require.NoError(t, err)
}
func TestClientReadPacketError(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
b := []byte{
0, 18,
0, 5,
'a', '/', 'b', '/', 'c',
'h', 'e', 'l', 'l', 'o', ' ', 'm', 'o', 'c', 'h', 'i',
}
err := cl.R.Set(b, 0, len(b))
require.NoError(t, err)
cl.R.SetPos(0, int64(len(b)))
o := make(chan error)
go func() {
o <- cl.Read(func(cl *Client, pk packets.Packet) error {
return nil
})
}()
require.Error(t, <-o)
}
func TestClientReadPacketEOF(t *testing.T) {
cl := genClient()
cl.Start()
b := []byte{
0, 18,
0, 5,
'a', '/', 'b', '/', 'c',
'h', 'e', 'l', 'l', 'o', ' ', 'm', 'o', 'c', 'h', // missing 1 byte
}
err := cl.R.Set(b, 0, len(b))
require.NoError(t, err)
cl.R.SetPos(0, int64(len(b)))
o := make(chan error)
go func() {
o <- cl.Read(func(cl *Client, pk packets.Packet) error {
return nil
})
}()
cl.R.Stop()
cl.Stop(testClientStop)
require.Error(t, <-o)
require.True(t, errors.Is(cl.StopCause(), testClientStop))
}
func TestClientReadHandlerErr(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
b := []byte{
byte(packets.Publish << 4), 11, // Fixed header
0, 5, // Topic Name - LSB+MSB
'd', '/', 'e', '/', 'f', // Topic Name
'y', 'e', 'a', 'h', // Payload
}
err := cl.R.Set(b, 0, len(b))
require.NoError(t, err)
cl.R.SetPos(0, int64(len(b)))
err = cl.Read(func(cl *Client, pk packets.Packet) error {
return errors.New("test")
})
require.Error(t, err)
}
func TestClientReadPacketOK(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
err := cl.R.Set([]byte{
byte(packets.Publish << 4), 11, // Fixed header
0, 5,
'd', '/', 'e', '/', 'f',
'y', 'e', 'a', 'h',
}, 0, 13)
require.NoError(t, err)
cl.R.SetPos(0, 13)
fh := new(packets.FixedHeader)
err = cl.ReadFixedHeader(fh)
require.NoError(t, err)
pk, err := cl.ReadPacket(fh)
require.NoError(t, err)
require.NotNil(t, pk)
require.Equal(t, packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Publish,
Remaining: 11,
},
TopicName: "d/e/f",
Payload: []byte("yeah"),
}, pk)
}
func TestClientReadPacket(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
for i, tt := range pkTable {
err := cl.R.Set(tt.bytes, 0, len(tt.bytes))
require.NoError(t, err)
cl.R.SetPos(0, int64(len(tt.bytes)))
fh := new(packets.FixedHeader)
err = cl.ReadFixedHeader(fh)
require.NoError(t, err)
pk, err := cl.ReadPacket(fh)
require.NoError(t, err)
require.NotNil(t, pk)
require.Equal(t, tt.packet, pk, "Mismatched packet: [i:%d] %d", i, tt.bytes[0])
if tt.packet.FixedHeader.Type == packets.Publish {
require.Equal(t, int64(1), atomic.LoadInt64(&cl.systemInfo.PublishRecv))
}
}
}
func TestClientReadPacketReadingError(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
err := cl.R.Set([]byte{
0, 11, // Fixed header
0, 5,
'd', '/', 'e', '/', 'f',
'y', 'e', 'a', 'h',
}, 0, 13)
require.NoError(t, err)
cl.R.SetPos(2, 13)
_, err = cl.ReadPacket(&packets.FixedHeader{
Type: 0,
Remaining: 11,
})
require.Error(t, err)
}
func TestClientReadPacketReadError(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
cl.R.Stop()
_, err := cl.ReadPacket(&packets.FixedHeader{
Remaining: 1,
})
require.Error(t, err)
require.Equal(t, io.EOF, err)
}
func TestClientReadPacketReadUnknown(t *testing.T) {
cl := genClient()
cl.Start()
defer cl.Stop(testClientStop)
cl.R.Stop()
_, err := cl.ReadPacket(&packets.FixedHeader{
Remaining: 1,
})
require.Error(t, err)
}
func TestClientWritePacket(t *testing.T) {
for i, tt := range pkTable {
r, w := net.Pipe()
cl := NewClient(r, circ.NewReader(128, 8), circ.NewWriter(128, 8), new(system.Info))
cl.Start()
o := make(chan []byte)
go func() {
buf, err := ioutil.ReadAll(w)
require.NoError(t, err)
o <- buf
}()
n, err := cl.WritePacket(tt.packet)
require.NoError(t, err, "Error [i:%d] %d", i, tt.packet)
require.Equal(t, len(tt.bytes), n, "Mismatched written [i:%d] %d", i, tt.packet)
time.Sleep(2 * time.Millisecond)
r.Close()
require.Equal(t, tt.bytes, <-o, "Mismatched packet: [i:%d] %d", i, tt.bytes[0])
cl.Stop(testClientStop)
// The stop cause is either the test error, EOF, or a
// closed pipe, depending on which goroutine runs first.
err = cl.StopCause()
time.Sleep(time.Millisecond * 5)
require.True(t,
errors.Is(err, testClientStop) ||
errors.Is(err, io.EOF) ||
errors.Is(err, io.ErrClosedPipe))
require.Equal(t, int64(n), atomic.LoadInt64(&cl.systemInfo.BytesSent))
require.Equal(t, int64(1), atomic.LoadInt64(&cl.systemInfo.MessagesSent))
if tt.packet.FixedHeader.Type == packets.Publish {
require.Equal(t, int64(1), atomic.LoadInt64(&cl.systemInfo.PublishSent))
}
}
}
func TestClientWritePacketWriteNoConn(t *testing.T) {
c, _ := net.Pipe()
cl := NewClient(c, circ.NewReader(16, 4), circ.NewWriter(16, 4), new(system.Info))
cl.W.SetPos(0, 16)
cl.Stop(testClientStop)
_, err := cl.WritePacket(pkTable[1].packet)
require.Error(t, err)
require.Equal(t, ErrConnectionClosed, err)
}
func TestClientWritePacketWriteError(t *testing.T) {
c, _ := net.Pipe()
cl := NewClient(c, circ.NewReader(16, 4), circ.NewWriter(16, 4), new(system.Info))
cl.W.SetPos(0, 16)
cl.W.Stop()
_, err := cl.WritePacket(pkTable[1].packet)
require.Error(t, err)
}
func TestClientWritePacketInvalidPacket(t *testing.T) {
c, _ := net.Pipe()
cl := NewClient(c, circ.NewReader(16, 4), circ.NewWriter(16, 4), new(system.Info))
cl.Start()
_, err := cl.WritePacket(packets.Packet{})
require.Error(t, err)
}
/////
func TestInflightSet(t *testing.T) {
cl := genClient()
q := cl.Inflight.Set(1, InflightMessage{Packet: packets.Packet{}, Sent: 0})
require.Equal(t, true, q)
require.NotNil(t, cl.Inflight.internal[1])
require.NotEqual(t, 0, cl.Inflight.internal[1].Sent)
q = cl.Inflight.Set(1, InflightMessage{Packet: packets.Packet{}, Sent: 0})
require.Equal(t, false, q)
}
func BenchmarkInflightSet(b *testing.B) {
cl := genClient()
in := InflightMessage{Packet: packets.Packet{}, Sent: 0}
for n := 0; n < b.N; n++ {
cl.Inflight.Set(1, in)
}
}
func TestInflightGet(t *testing.T) {
cl := genClient()
cl.Inflight.Set(2, InflightMessage{Packet: packets.Packet{}, Sent: 0})
msg, ok := cl.Inflight.Get(2)
require.Equal(t, true, ok)
require.NotEqual(t, 0, msg.Sent)
}
func BenchmarkInflightGet(b *testing.B) {
cl := genClient()
cl.Inflight.Set(2, InflightMessage{Packet: packets.Packet{}, Sent: 0})
for n := 0; n < b.N; n++ {
cl.Inflight.Get(2)
}
}
func TestInflightGetAll(t *testing.T) {
cl := genClient()
cl.Inflight.Set(2, InflightMessage{})
m := cl.Inflight.GetAll()
o := map[uint16]InflightMessage{
2: {},
}
require.Equal(t, o, m)
}
func BenchmarkInflightGetAll(b *testing.B) {
cl := genClient()
cl.Inflight.Set(2, InflightMessage{Packet: packets.Packet{}, Sent: 0})
for n := 0; n < b.N; n++ {
cl.Inflight.Get(2)
}
}
func TestInflightLen(t *testing.T) {
cl := genClient()
cl.Inflight.Set(2, InflightMessage{Packet: packets.Packet{}, Sent: 0})
require.Equal(t, 1, cl.Inflight.Len())
}
func BenchmarkInflightLen(b *testing.B) {
cl := genClient()
cl.Inflight.Set(2, InflightMessage{Packet: packets.Packet{}, Sent: 0})
for n := 0; n < b.N; n++ {
cl.Inflight.Len()
}
}
func TestInflightDelete(t *testing.T) {
cl := genClient()
cl.Inflight.Set(3, InflightMessage{Packet: packets.Packet{}, Sent: 0})
require.NotNil(t, cl.Inflight.internal[3])
q := cl.Inflight.Delete(3)
require.Equal(t, true, q)
require.Equal(t, int64(0), cl.Inflight.internal[3].Sent)
_, ok := cl.Inflight.Get(3)
require.Equal(t, false, ok)
q = cl.Inflight.Delete(3)
require.Equal(t, false, q)
}
func BenchmarkInflightDelete(b *testing.B) {
cl := genClient()
for n := 0; n < b.N; n++ {
cl.Inflight.Set(4, InflightMessage{Packet: packets.Packet{}, Sent: 0})
cl.Inflight.Delete(4)
}
}
var (
pkTable = []struct {
bytes []byte
packet packets.Packet
}{
{
bytes: []byte{
byte(packets.Connect << 4), 16, // Fixed header
0, 4, // Protocol Name - MSB+LSB
'M', 'Q', 'T', 'T', // Protocol Name
4, // Protocol Version
0, // Packet Flags
0, 60, // Keepalive
0, 4, // Client ID - MSB+LSB
'z', 'e', 'n', '3',
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Connect,
Remaining: 16,
},
ProtocolName: []byte("MQTT"),
ProtocolVersion: 4,
CleanSession: false,
Keepalive: 60,
ClientIdentifier: "zen3",
},
},
{
bytes: []byte{
byte(packets.Connack << 4), 2,
0,
packets.Accepted,
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Connack,
Remaining: 2,
},
SessionPresent: false,
ReturnCode: packets.Accepted,
},
},
{
bytes: []byte{
byte(packets.Publish << 4), 18,
0, 5,
'a', '/', 'b', '/', 'c',
'h', 'e', 'l', 'l', 'o', ' ', 'm', 'o', 'c', 'h', 'i',
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Publish,
Remaining: 18,
},
TopicName: "a/b/c",
Payload: []byte("hello mochi"),
},
},
{
bytes: []byte{
byte(packets.Puback << 4), 2, // Fixed header
0, 11, // Packet ID - LSB+MSB
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Puback,
Remaining: 2,
},
PacketID: 11,
},
},
{
bytes: []byte{
byte(packets.Pubrec << 4), 2, // Fixed header
0, 12, // Packet ID - LSB+MSB
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Pubrec,
Remaining: 2,
},
PacketID: 12,
},
},
{
bytes: []byte{
byte(packets.Pubrel<<4) | 2, 2, // Fixed header
0, 12, // Packet ID - LSB+MSB
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Pubrel,
Remaining: 2,
Qos: 1,
},
PacketID: 12,
},
},
{
bytes: []byte{
byte(packets.Pubcomp << 4), 2, // Fixed header
0, 14, // Packet ID - LSB+MSB
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Pubcomp,
Remaining: 2,
},
PacketID: 14,
},
},
{
bytes: []byte{
byte(packets.Subscribe << 4), 30, // Fixed header
0, 15, // Packet ID - LSB+MSB
0, 3, // Topic Name - LSB+MSB
'a', '/', 'b', // Topic Name
0, // QoS
0, 11, // Topic Name - LSB+MSB
'd', '/', 'e', '/', 'f', '/', 'g', '/', 'h', '/', 'i', // Topic Name
1, // QoS
0, 5, // Topic Name - LSB+MSB
'x', '/', 'y', '/', 'z', // Topic Name
2, // QoS
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Subscribe,
Remaining: 30,
},
PacketID: 15,
Topics: []string{
"a/b",
"d/e/f/g/h/i",
"x/y/z",
},
Qoss: []byte{0, 1, 2},
},
},
{
bytes: []byte{
byte(packets.Suback << 4), 6, // Fixed header
0, 17, // Packet ID - LSB+MSB
0, // Return Code QoS 0
1, // Return Code QoS 1
2, // Return Code QoS 2
0x80, // Return Code fail
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Suback,
Remaining: 6,
},
PacketID: 17,
ReturnCodes: []byte{0, 1, 2, 0x80},
},
},
{
bytes: []byte{
byte(packets.Unsubscribe << 4), 27, // Fixed header
0, 35, // Packet ID - LSB+MSB
0, 3, // Topic Name - LSB+MSB
'a', '/', 'b', // Topic Name
0, 11, // Topic Name - LSB+MSB
'd', '/', 'e', '/', 'f', '/', 'g', '/', 'h', '/', 'i', // Topic Name
0, 5, // Topic Name - LSB+MSB
'x', '/', 'y', '/', 'z', // Topic Name
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Unsubscribe,
Remaining: 27,
},
PacketID: 35,
Topics: []string{
"a/b",
"d/e/f/g/h/i",
"x/y/z",
},
},
},
{
bytes: []byte{
byte(packets.Unsuback << 4), 2, // Fixed header
0, 37, // Packet ID - LSB+MSB
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Unsuback,
Remaining: 2,
},
PacketID: 37,
},
},
{
bytes: []byte{
byte(packets.Pingreq << 4), 0, // fixed header
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Pingreq,
Remaining: 0,
},
},
},
{
bytes: []byte{
byte(packets.Pingresp << 4), 0, // fixed header
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Pingresp,
Remaining: 0,
},
},
},
{
bytes: []byte{
byte(packets.Disconnect << 4), 0, // fixed header
},
packet: packets.Packet{
FixedHeader: packets.FixedHeader{
Type: packets.Disconnect,
Remaining: 0,
},
},
},
}
)