Your IP : 216.73.216.224


Current Path : /home/hotlineuser/mobius/hotline/
Upload File :
Current File : //home/hotlineuser/mobius/hotline/tracker_test.go

package hotline

import (
	"bytes"
	"io"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestTrackerRegistration_Payload(t *testing.T) {
	type fields struct {
		Port        [2]byte
		UserCount   int
		PassID      [4]byte
		Name        string
		Description string
	}
	tests := []struct {
		name   string
		fields fields
		want   []byte
	}{
		{
			name: "returns expected payload bytes",
			fields: fields{
				Port:        [2]byte{0x00, 0x10},
				UserCount:   2,
				PassID:      [4]byte{0x00, 0x00, 0x00, 0x01},
				Name:        "Test Serv",
				Description: "Fooz",
			},
			want: []byte{
				0x00, 0x01,
				0x00, 0x10,
				0x00, 0x02,
				0x00, 0x00,
				0x00, 0x00, 0x00, 0x01,
				0x09,
				0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76,
				0x04,
				0x46, 0x6f, 0x6f, 0x7a,
				0x00,
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tr := &TrackerRegistration{
				Port:        tt.fields.Port,
				UserCount:   tt.fields.UserCount,
				PassID:      tt.fields.PassID,
				Name:        tt.fields.Name,
				Description: tt.fields.Description,
			}

			if got, _ := io.ReadAll(tr); !assert.Equal(t, tt.want, got) {
				t.Errorf("Read() = %v, want %v", got, tt.want)
			}
		})
	}
}

type mockConn struct {
	readBuffer  *bytes.Buffer
	writeBuffer *bytes.Buffer
	closed      bool
}

func (m *mockConn) Read(b []byte) (n int, err error) {
	return m.readBuffer.Read(b)
}

func (m *mockConn) Write(b []byte) (n int, err error) {
	return m.writeBuffer.Write(b)
}

func (m *mockConn) Close() error {
	m.closed = true
	return nil
}

func TestGetListing(t *testing.T) {
	tests := []struct {
		name       string
		mockConn   *mockConn
		wantErr    bool
		wantResult []ServerRecord
	}{
		{
			name: "Successful retrieval",
			mockConn: &mockConn{
				readBuffer: bytes.NewBuffer([]byte{
					// TrackerHeader
					0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK"
					0x00, 0x01, // Version 1
					// ServerInfoHeader
					0x00, 0x01, // MsgType (1)
					0x00, 0x14, // MsgDataSize (20)
					0x00, 0x02, // SrvCount (2)
					0x00, 0x02, // BatchSize (2)
					// ServerRecord 1
					192, 168, 1, 1, // IP address
					0x1F, 0x90, // Port 8080
					0x00, 0x10, // NumUsers 16
					0x00, 0x00, // TLSPort
					0x04,               // NameSize
					'S', 'e', 'r', 'v', // Name
					0x0B,                                                  // DescriptionSize
					'M', 'y', ' ', 'S', 'e', 'r', 'v', 'e', 'r', ' ', '1', // Description
					// ServerRecord 2
					10, 0, 0, 1, // IP address
					0x1F, 0x91, // Port 8081
					0x00, 0x05, // NumUsers 5
					0x00, 0x00, // TLSPort
					0x04,               // NameSize
					'S', 'e', 'r', 'v', // Name
					0x0B,                                                  // DescriptionSize
					'M', 'y', ' ', 'S', 'e', 'r', 'v', 'e', 'r', ' ', '2', // Description
				}),
				writeBuffer: &bytes.Buffer{},
			},
			wantErr: false,
			wantResult: []ServerRecord{
				{
					IPAddr:          [4]byte{192, 168, 1, 1},
					Port:            [2]byte{0x1F, 0x90},
					NumUsers:        [2]byte{0x00, 0x10},
					TLSPort:         [2]byte{0x00, 0x00},
					NameSize:        4,
					Name:            []byte("Serv"),
					DescriptionSize: 11,
					Description:     []byte("My Server 1"),
				},
				{
					IPAddr:          [4]byte{10, 0, 0, 1},
					Port:            [2]byte{0x1F, 0x91},
					NumUsers:        [2]byte{0x00, 0x05},
					TLSPort:         [2]byte{0x00, 0x00},
					NameSize:        4,
					Name:            []byte("Serv"),
					DescriptionSize: 11,
					Description:     []byte("My Server 2"),
				},
			},
		},
		{
			name: "Write error",
			mockConn: &mockConn{
				readBuffer:  &bytes.Buffer{},
				writeBuffer: &bytes.Buffer{},
			},
			wantErr:    true,
			wantResult: nil,
		},
		{
			name: "Read error on TrackerHeader",
			mockConn: &mockConn{
				readBuffer: bytes.NewBuffer([]byte{
					// incomplete data to cause read error
					0x48,
				}),
				writeBuffer: &bytes.Buffer{},
			},
			wantErr:    true,
			wantResult: nil,
		},
		{
			name: "Read error on ServerInfoHeader",
			mockConn: &mockConn{
				readBuffer: bytes.NewBuffer([]byte{
					// TrackerHeader
					0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK"
					0x00, 0x01, // Version 1
					// incomplete ServerInfoHeader
					0x00,
				}),
				writeBuffer: &bytes.Buffer{},
			},
			wantErr:    true,
			wantResult: nil,
		},
		{
			name: "Scanner error",
			mockConn: &mockConn{
				readBuffer: bytes.NewBuffer([]byte{
					// TrackerHeader
					0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK"
					0x00, 0x01, // Version 1
					// ServerInfoHeader
					0x00, 0x01, // MsgType (1)
					0x00, 0x14, // MsgDataSize (20)
					0x00, 0x01, // SrvCount (1)
					0x00, 0x01, // BatchSize (1)
					// incomplete ServerRecord to cause scanner error
					192, 168, 1, 1,
				}),
				writeBuffer: &bytes.Buffer{},
			},
			wantErr:    true,
			wantResult: nil,
		},
		{
			name: "Multiple batches with ServerInfoHeaders",
			mockConn: &mockConn{
				readBuffer: bytes.NewBuffer([]byte{
					// TrackerHeader
					0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK"
					0x00, 0x01, // Version 1
					// First ServerInfoHeader
					0x00, 0x01, // MsgType (1)
					0x00, 0x14, // MsgDataSize (20)
					0x00, 0x03, // SrvCount (3 total)
					0x00, 0x02, // BatchSize (2 in first batch)
					// ServerRecord 1
					192, 168, 1, 1, // IP address
					0x1F, 0x90, // Port 8080
					0x00, 0x0A, // NumUsers 10
					0x00, 0x00, // TLSPort
					0x07,                              // NameSize
					'S', 'e', 'r', 'v', 'e', 'r', '1', // Name
					0x0C,                                                       // DescriptionSize
					'F', 'i', 'r', 's', 't', ' ', 'b', 'a', 't', 'c', 'h', '1', // Description
					// ServerRecord 2
					192, 168, 1, 2, // IP address
					0x1F, 0x91, // Port 8081
					0x00, 0x14, // NumUsers 20
					0x00, 0x00, // TLSPort
					0x07,                              // NameSize
					'S', 'e', 'r', 'v', 'e', 'r', '2', // Name
					0x0C,                                                       // DescriptionSize
					'F', 'i', 'r', 's', 't', ' ', 'b', 'a', 't', 'c', 'h', '2', // Description
					// Second ServerInfoHeader (next batch)
					0x00, 0x01, // MsgType (1)
					0x00, 0x0A, // MsgDataSize (10)
					0x00, 0x03, // SrvCount (3 total - same)
					0x00, 0x01, // BatchSize (1 in second batch)
					// ServerRecord 3
					192, 168, 1, 3, // IP address
					0x1F, 0x92, // Port 8082
					0x00, 0x1E, // NumUsers 30
					0x00, 0x00, // TLSPort
					0x07,                              // NameSize
					'S', 'e', 'r', 'v', 'e', 'r', '3', // Name
					0x0D,                                                            // DescriptionSize
					'S', 'e', 'c', 'o', 'n', 'd', ' ', 'b', 'a', 't', 'c', 'h', '1', // Description
				}),
				writeBuffer: &bytes.Buffer{},
			},
			wantErr: false,
			wantResult: []ServerRecord{
				{
					IPAddr:          [4]byte{192, 168, 1, 1},
					Port:            [2]byte{0x1F, 0x90},
					NumUsers:        [2]byte{0x00, 0x0A},
					TLSPort:         [2]byte{0x00, 0x00},
					NameSize:        7,
					Name:            []byte("Server1"),
					DescriptionSize: 12,
					Description:     []byte("First batch1"),
				},
				{
					IPAddr:          [4]byte{192, 168, 1, 2},
					Port:            [2]byte{0x1F, 0x91},
					NumUsers:        [2]byte{0x00, 0x14},
					TLSPort:         [2]byte{0x00, 0x00},
					NameSize:        7,
					Name:            []byte("Server2"),
					DescriptionSize: 12,
					Description:     []byte("First batch2"),
				},
				{
					IPAddr:          [4]byte{192, 168, 1, 3},
					Port:            [2]byte{0x1F, 0x92},
					NumUsers:        [2]byte{0x00, 0x1E},
					TLSPort:         [2]byte{0x00, 0x00},
					NameSize:        7,
					Name:            []byte("Server3"),
					DescriptionSize: 13,
					Description:     []byte("Second batch1"),
				},
			},
		},
		{
			name: "Three batches",
			mockConn: &mockConn{
				readBuffer: bytes.NewBuffer([]byte{
					// TrackerHeader
					0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK"
					0x00, 0x01, // Version 1
					// First ServerInfoHeader
					0x00, 0x01, // MsgType (1)
					0x00, 0x0A, // MsgDataSize
					0x00, 0x04, // SrvCount (4 total)
					0x00, 0x02, // BatchSize (2 in first batch)
					// ServerRecord 1
					192, 168, 1, 1, // IP
					0x15, 0x7c, // Port 5500
					0x00, 0x01, // NumUsers 1
					0x00, 0x00, // TLSPort
					0x01, // NameSize
					'A',  // Name
					0x01, // DescriptionSize
					'1',  // Description
					// ServerRecord 2
					192, 168, 1, 2, // IP
					0x15, 0x7c, // Port 5500
					0x00, 0x02, // NumUsers 2
					0x00, 0x00, // TLSPort
					0x01, // NameSize
					'B',  // Name
					0x01, // DescriptionSize
					'2',  // Description
					// Second ServerInfoHeader
					0x00, 0x01, // MsgType (1)
					0x00, 0x0A, // MsgDataSize
					0x00, 0x04, // SrvCount (4 total)
					0x00, 0x01, // BatchSize (1 in second batch)
					// ServerRecord 3
					192, 168, 1, 3, // IP
					0x15, 0x7c, // Port 5500
					0x00, 0x03, // NumUsers 3
					0x00, 0x00, // TLSPort
					0x01, // NameSize
					'C',  // Name
					0x01, // DescriptionSize
					'3',  // Description
					// Third ServerInfoHeader
					0x00, 0x01, // MsgType (1)
					0x00, 0x0A, // MsgDataSize
					0x00, 0x04, // SrvCount (4 total)
					0x00, 0x01, // BatchSize (1 in third batch)
					// ServerRecord 4
					192, 168, 1, 4, // IP
					0x15, 0x7c, // Port 5500
					0x00, 0x04, // NumUsers 4
					0x00, 0x00, // TLSPort
					0x01, // NameSize
					'D',  // Name
					0x01, // DescriptionSize
					'4',  // Description
				}),
				writeBuffer: &bytes.Buffer{},
			},
			wantErr: false,
			wantResult: []ServerRecord{
				{
					IPAddr:          [4]byte{192, 168, 1, 1},
					Port:            [2]byte{0x15, 0x7c},
					NumUsers:        [2]byte{0x00, 0x01},
					TLSPort:         [2]byte{0x00, 0x00},
					NameSize:        1,
					Name:            []byte("A"),
					DescriptionSize: 1,
					Description:     []byte("1"),
				},
				{
					IPAddr:          [4]byte{192, 168, 1, 2},
					Port:            [2]byte{0x15, 0x7c},
					NumUsers:        [2]byte{0x00, 0x02},
					TLSPort:         [2]byte{0x00, 0x00},
					NameSize:        1,
					Name:            []byte("B"),
					DescriptionSize: 1,
					Description:     []byte("2"),
				},
				{
					IPAddr:          [4]byte{192, 168, 1, 3},
					Port:            [2]byte{0x15, 0x7c},
					NumUsers:        [2]byte{0x00, 0x03},
					TLSPort:         [2]byte{0x00, 0x00},
					NameSize:        1,
					Name:            []byte("C"),
					DescriptionSize: 1,
					Description:     []byte("3"),
				},
				{
					IPAddr:          [4]byte{192, 168, 1, 4},
					Port:            [2]byte{0x15, 0x7c},
					NumUsers:        [2]byte{0x00, 0x04},
					TLSPort:         [2]byte{0x00, 0x00},
					NameSize:        1,
					Name:            []byte("D"),
					DescriptionSize: 1,
					Description:     []byte("4"),
				},
			},
		},
		{
			name: "Error reading second ServerInfoHeader",
			mockConn: &mockConn{
				readBuffer: bytes.NewBuffer([]byte{
					// TrackerHeader
					0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK"
					0x00, 0x01, // Version 1
					// First ServerInfoHeader
					0x00, 0x01, // MsgType (1)
					0x00, 0x0A, // MsgDataSize
					0x00, 0x02, // SrvCount (2 total)
					0x00, 0x01, // BatchSize (1 in first batch)
					// ServerRecord 1
					192, 168, 1, 1, // IP
					0x15, 0x7c, // Port 5500
					0x00, 0x01, // NumUsers 1
					0x00, 0x00, // TLSPort
					0x01, // NameSize
					'A',  // Name
					0x01, // DescriptionSize
					'1',  // Description
					// Incomplete second ServerInfoHeader
					0x00, 0x01, // MsgType only
				}),
				writeBuffer: &bytes.Buffer{},
			},
			wantErr:    true,
			wantResult: nil,
		},
		{
			name: "Empty server list",
			mockConn: &mockConn{
				readBuffer: bytes.NewBuffer([]byte{
					// TrackerHeader
					0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK"
					0x00, 0x01, // Version 1
					// ServerInfoHeader with 0 servers
					0x00, 0x01, // MsgType (1)
					0x00, 0x00, // MsgDataSize (0)
					0x00, 0x00, // SrvCount (0)
					0x00, 0x00, // BatchSize (0)
				}),
				writeBuffer: &bytes.Buffer{},
			},
			wantErr:    false,
			wantResult: []ServerRecord{},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := GetListing(tt.mockConn)
			if tt.wantErr {
				require.Error(t, err)
			} else {
				require.NoError(t, err)
				assert.Equal(t, tt.wantResult, got)
			}
		})
	}
}