summaryrefslogtreecommitdiff
path: root/adapters/rcon/rcon_test.go
blob: f712fa54cac83db9ea52228f800480194053a04c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package rcon

import (
	"encoding/binary"
	"errors"
	"io"
	"net"
	"testing"
	"time"
)

func writeTestPacket(w io.Writer, id, typ int32, body string) {
	binary.Write(w, binary.LittleEndian, int32(headerSize+len(body)+paddingSize))
	binary.Write(w, binary.LittleEndian, id)
	binary.Write(w, binary.LittleEndian, typ)
	io.WriteString(w, body)
	w.Write([]byte{0, 0})
}

func readTestPacket(r io.Reader) (id, typ int32, body string) {
	var size int32
	binary.Read(r, binary.LittleEndian, &size)
	payload := make([]byte, size)
	io.ReadFull(r, payload)
	id = int32(binary.LittleEndian.Uint32(payload[0:4]))
	typ = int32(binary.LittleEndian.Uint32(payload[4:8]))
	return id, typ, string(payload[headerSize : size-paddingSize])
}

// fakeServer speaks just enough Source RCON to exercise the client.
func fakeServer(t *testing.T, password string) string {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { ln.Close() })

	go func() {
		conn, err := ln.Accept()
		if err != nil {
			return
		}
		defer conn.Close()

		id, typ, body := readTestPacket(conn)
		if typ != typeAuth {
			return
		}
		respID := id
		if body != password {
			respID = -1
		}
		writeTestPacket(conn, id, typeResponse, "") // empty value first
		writeTestPacket(conn, respID, typeAuthResp, "")
		if respID == -1 {
			return
		}

		cid, _, cbody := readTestPacket(conn)
		out := "unknown command"
		if cbody == "list" {
			out = "There are 1 of a max of 20 players online: Steve"
		}
		writeTestPacket(conn, cid, typeResponse, out)
	}()

	return ln.Addr().String()
}

func TestClientExecute(t *testing.T) {
	client, err := Dial(fakeServer(t, "secret"), "secret", time.Second)
	if err != nil {
		t.Fatal(err)
	}
	defer client.Close()

	out, err := client.Execute("list")
	if err != nil {
		t.Fatal(err)
	}
	if want := "There are 1 of a max of 20 players online: Steve"; out != want {
		t.Errorf("Execute = %q, want %q", out, want)
	}
}

func TestClientAuthFailure(t *testing.T) {
	_, err := Dial(fakeServer(t, "secret"), "wrong", time.Second)
	if !errors.Is(err, ErrAuthFailed) {
		t.Errorf("Dial err = %v, want ErrAuthFailed", err)
	}
}