simpleadmin-web 0.1.0: web panel for CS2-SimpleAdmin
This commit is contained in:
commit
4f38daf0e6
31 changed files with 6870 additions and 0 deletions
132
internal/rcon/rcon_test.go
Normal file
132
internal/rcon/rcon_test.go
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
package rcon
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestArg(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
`plain reason`: "plain reason",
|
||||
`quote" ; quit`: "quote quit",
|
||||
"new\nline": "new line",
|
||||
`back\slash`: "backslash",
|
||||
" padded ": "padded",
|
||||
`"; css_addadmin 1 x @css/root`: " css_addadmin 1 x @css/root",
|
||||
}
|
||||
for in, want := range cases {
|
||||
if got := Arg(in, 0); got != strings.TrimSpace(want) {
|
||||
t.Errorf("Arg(%q) = %q, want %q", in, got, strings.TrimSpace(want))
|
||||
}
|
||||
}
|
||||
if got := Arg("abcdef", 3); got != "abc" {
|
||||
t.Errorf("max length: got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// fakeServer answers auth, then replies to each command with its text split over two packets,
|
||||
// and mirrors the empty end-marker packet the way srcds does.
|
||||
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() {
|
||||
for {
|
||||
c, err := ln.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go serve(c, password)
|
||||
}
|
||||
}()
|
||||
return ln.Addr().String()
|
||||
}
|
||||
|
||||
func readPkt(r io.Reader) (int32, int32, string, error) {
|
||||
var size int32
|
||||
if err := binary.Read(r, binary.LittleEndian, &size); err != nil {
|
||||
return 0, 0, "", err
|
||||
}
|
||||
b := make([]byte, size)
|
||||
if _, err := io.ReadFull(r, b); err != nil {
|
||||
return 0, 0, "", err
|
||||
}
|
||||
return int32(binary.LittleEndian.Uint32(b)), int32(binary.LittleEndian.Uint32(b[4:])), strings.TrimRight(string(b[8:]), "\x00"), nil
|
||||
}
|
||||
|
||||
func writePkt(w io.Writer, id, typ int32, body string) {
|
||||
buf := make([]byte, 12+len(body)+2)
|
||||
binary.LittleEndian.PutUint32(buf, uint32(len(body)+10))
|
||||
binary.LittleEndian.PutUint32(buf[4:], uint32(id))
|
||||
binary.LittleEndian.PutUint32(buf[8:], uint32(typ))
|
||||
copy(buf[12:], body)
|
||||
w.Write(buf)
|
||||
}
|
||||
|
||||
func serve(c net.Conn, password string) {
|
||||
defer c.Close()
|
||||
for {
|
||||
id, typ, body, err := readPkt(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch typ {
|
||||
case typeAuth:
|
||||
writePkt(c, id, typeResponseValue, "")
|
||||
if body == password {
|
||||
writePkt(c, id, typeAuthResponse, "")
|
||||
} else {
|
||||
writePkt(c, -1, typeAuthResponse, "")
|
||||
}
|
||||
case typeExecCommand:
|
||||
out := "echo:" + body + "\n" + strings.Repeat("x", 5000)
|
||||
writePkt(c, id, typeResponseValue, out[:4000])
|
||||
writePkt(c, id, typeResponseValue, out[4000:])
|
||||
case typeResponseValue:
|
||||
writePkt(c, id, typeResponseValue, "")
|
||||
writePkt(c, id, typeResponseValue, "\x00\x01\x00\x00")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecMultiPacket(t *testing.T) {
|
||||
addr := fakeServer(t, "pw")
|
||||
c := New(addr, "pw")
|
||||
defer c.Close()
|
||||
for i := 0; i < 3; i++ {
|
||||
out, err := c.Exec("status")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.HasPrefix(out, "echo:status\n") || len(out) != len("echo:status\n")+5000 {
|
||||
t.Fatalf("got %d bytes: %.40q", len(out), out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrongPassword(t *testing.T) {
|
||||
addr := fakeServer(t, "pw")
|
||||
c := New(addr, "nope")
|
||||
if _, err := c.Exec("status"); err != ErrAuth {
|
||||
t.Fatalf("got %v, want ErrAuth", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackoff(t *testing.T) {
|
||||
ln, _ := net.Listen("tcp", "127.0.0.1:0")
|
||||
addr := ln.Addr().String()
|
||||
ln.Close() // nothing listens here now
|
||||
c := New(addr, "pw")
|
||||
if _, err := c.Exec("status"); err == nil {
|
||||
t.Fatal("expected a connection error")
|
||||
}
|
||||
if _, err := c.Exec("status"); !errors.Is(err, ErrDown) {
|
||||
t.Fatalf("second call should fail fast with ErrDown, got %v", err)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue