Compare commits

...

2 commits

Author SHA1 Message Date
Augusto Dwenger J. aa3d91eab1
Fix typos 2022-03-05 17:31:46 +01:00
Augusto Dwenger J. 5798c26e08
Add MinecraftClient tests and examples 2022-03-05 15:37:31 +01:00
5 changed files with 315 additions and 6 deletions

View file

@ -0,0 +1,100 @@
package client_test
import (
"log"
"net"
"github.com/hamburghammer/grcon"
"github.com/hamburghammer/grcon/client"
"github.com/hamburghammer/grcon/util"
)
func ExampleNewMinecraftClient() {
conn, err := net.Dial("tcp", "127.0.0.1:12345")
if err != nil {
log.Fatalf("connection failed: %s", err.Error())
}
defer conn.Close()
remoteConsole := grcon.NewRemoteConsole(conn)
// the returned MinecraftClient can now be used.
// It will use the utility function to generate ids
_ = client.NewMinecraftClient(remoteConsole, util.GenerateRequestId)
}
func ExampleMinecraftClient() {
conn, err := net.Dial("tcp", "127.0.0.1:12345")
if err != nil {
log.Fatalf("connection failed: %s", err.Error())
}
defer conn.Close()
remoteConsole := grcon.NewRemoteConsole(conn)
minecraftClient := client.MinecraftClient{
RemoteConsole: remoteConsole,
// Use the utility function to generate ids
IdGenFunc: util.GenerateRequestId,
}
err = minecraftClient.Auth("password")
if err != nil {
log.Fatalf("authentication failed: %s", err.Error())
}
result, err := minecraftClient.Exec("players")
if err != nil {
log.Fatalf("failed to retrive active players: %s", err.Error())
}
log.Println(string(result))
}
func ExampleMinecraftClient_Auth() {
conn, err := net.Dial("tcp", "127.0.0.1:12345")
if err != nil {
log.Fatalf("connection failed: %s", err.Error())
}
defer conn.Close()
remoteConsole := grcon.NewRemoteConsole(conn)
minecraftClient := client.MinecraftClient{
RemoteConsole: remoteConsole,
IdGenFunc: util.GenerateRequestId,
}
err = minecraftClient.Auth("password")
if err != nil {
log.Fatalf("authentication failed: %s", err.Error())
}
}
func ExampleMinecraftClient_Exec() {
conn, err := net.Dial("tcp", "127.0.0.1:12345")
if err != nil {
log.Fatalf("connection failed: %s", err.Error())
}
defer conn.Close()
remoteConsole := grcon.NewRemoteConsole(conn)
minecraftClient := client.MinecraftClient{
RemoteConsole: remoteConsole,
IdGenFunc: util.GenerateRequestId,
}
// before you execute something you might want to authenticated the connection.
err = minecraftClient.Auth("password")
if err != nil {
log.Fatalf("authentication failed: %s", err.Error())
}
result, err := minecraftClient.Exec("players")
if err != nil {
log.Fatalf("failed to retrive active players: %s", err.Error())
}
log.Println(string(result))
}

View file

@ -0,0 +1,209 @@
package client_test
import (
"testing"
"github.com/hamburghammer/grcon"
"github.com/hamburghammer/grcon/client"
)
func TestMinecraftClient_Auth(t *testing.T) {
t.Run("successful auth", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 1, Type: grcon.SERVERDATA_AUTH_RESPONSE, Body: []byte("")},
}}
minecraftClient := client.MinecraftClient{
RemoteConsole: mock,
IdGenFunc: mockIdGen.GetNextId,
}
err := minecraftClient.Auth("foo")
if err != nil {
t.Error(err)
t.FailNow()
}
})
t.Run("auth response", func(t *testing.T) {
t.Run("not match type", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 1, Type: grcon.SERVERDATA_RESPONSE_VALUE, Body: []byte("")},
}}
minecraftClient := client.MinecraftClient{
RemoteConsole: mock,
IdGenFunc: mockIdGen.GetNextId,
}
err := minecraftClient.Auth("foo")
_, ok := err.(client.InvalidResponseTypeError)
if err != nil && !ok {
t.Errorf("expected: InvalidResponseTypeError\ngot: %T\n", err)
t.Error(err)
t.FailNow()
}
})
t.Run("auth failed", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: -1, Type: grcon.SERVERDATA_AUTH_RESPONSE, Body: []byte("")},
}}
minecraftClient := client.MinecraftClient{
RemoteConsole: mock,
IdGenFunc: mockIdGen.GetNextId,
}
err := minecraftClient.Auth("foo")
_, ok := err.(client.AuthFailedError)
if err != nil && !ok {
t.Errorf("expected: AuthFailedError\ngot: %T\n", err)
t.Error(err)
t.FailNow()
}
})
t.Run("not matching ids", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 2, Type: grcon.SERVERDATA_AUTH_RESPONSE, Body: []byte("")},
}}
minecraftClient := client.MinecraftClient{
RemoteConsole: mock,
IdGenFunc: mockIdGen.GetNextId,
}
err := minecraftClient.Auth("foo")
_, ok := err.(client.ResponseIdMismatchError)
if err != nil && !ok {
t.Errorf("expected: ResponseIdMismatchError\ngot: %T\n", err)
t.Error(err)
t.FailNow()
}
})
})
t.Run("written packet", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 1, Type: grcon.SERVERDATA_AUTH_RESPONSE, Body: []byte("")},
}}
simpleClient := client.MinecraftClient{
RemoteConsole: mock,
IdGenFunc: mockIdGen.GetNextId,
}
err := simpleClient.Auth("foo")
if err != nil {
t.Error(err)
t.FailNow()
}
got := mock.Out
if len(got) < 1 {
t.Errorf("expected at leased 1 packet but got %d\n", len(got))
}
gotPacket := got[0]
if gotPacket.Id != 1 {
t.Error("expected id 1 but got something different")
}
if gotPacket.Type != grcon.SERVERDATA_AUTH {
t.Error("packet was not of type auth")
}
if string(gotPacket.Body) != "foo" {
t.Error("body/password did not match")
}
})
}
func TestMinecraftClient_Exec(t *testing.T) {
t.Run("successful execution", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 1, Type: grcon.SERVERDATA_RESPONSE_VALUE, Body: []byte("bar")},
}}
minecraftClient := client.MinecraftClient{
RemoteConsole: mock,
IdGenFunc: mockIdGen.GetNextId,
}
got, err := minecraftClient.Exec("foo")
if err != nil {
t.Error(err)
t.FailNow()
}
if string(got) != "bar" {
t.Errorf("response did not match:\nexpected: %s\ngot: %s\n", "bar", string(got))
}
})
t.Run("write cmd packet", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 1, Type: grcon.SERVERDATA_RESPONSE_VALUE, Body: []byte("")},
}}
minecraftClient := client.MinecraftClient{
RemoteConsole: mock,
IdGenFunc: mockIdGen.GetNextId,
}
_, err := minecraftClient.Exec("foo")
if err != nil {
t.Error(err)
t.FailNow()
}
got := mock.Out
if len(got) != 1 {
t.Error("written less than 1 packet")
t.FailNow()
}
gotPacket := got[0]
if gotPacket.Id != 1 {
t.Error("id missmatch")
}
if gotPacket.Type != grcon.SERVERDATA_EXECCOMMAND {
t.Error("type missmatch")
}
if string(gotPacket.Body) != "foo" {
t.Error("body missmatch")
}
})
t.Run("invalid response type error", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1, 2}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 1, Type: grcon.SERVERDATA_AUTH_RESPONSE, Body: []byte("bar")},
}}
simpleClient := client.SimpleClient{
RemoteConsole: mock,
IdGenFunc: mockIdGen.GetNextId,
}
_, err := simpleClient.Exec("foo")
_, ok := err.(client.InvalidResponseTypeError)
if err != nil && !ok {
t.Error(err)
t.FailNow()
}
})
t.Run("id response missmatch type error", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1, 2}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 3, Type: grcon.SERVERDATA_RESPONSE_VALUE, Body: []byte("bar")},
}}
simpleClient := client.SimpleClient{
RemoteConsole: mock,
IdGenFunc: mockIdGen.GetNextId,
}
_, err := simpleClient.Exec("foo")
_, ok := err.(client.ResponseIdMismatchError)
if err != nil && !ok {
t.Error(err)
t.FailNow()
}
})
}

View file

@ -77,12 +77,12 @@ func (sc SimpleClient) Auth(password string) error {
// waits till the response is read returns it.
// Supports multi-packet responses.
//
// The server has to response in synchronously!
// The server has to response synchronously!
//
// Errors:
// Returns all errors returned from the Write and Read methode from the RemoteConsole implementation.
// Can also return an InvalidResponseTypeError if the response is not of the type
//grcon.SERVERDATA_RESPONSE_VALUE.
// grcon.SERVERDATA_RESPONSE_VALUE.
func (sc SimpleClient) Exec(cmd string) ([]byte, error) {
cmdPacket := grcon.Packet{
Id: sc.IdGenFunc(),

View file

@ -8,7 +8,7 @@ import (
)
func TestSimpleClient_Auth(t *testing.T) {
t.Run("successfull auth", func(t *testing.T) {
t.Run("successful auth", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 1, Type: grcon.SERVERDATA_RESPONSE_VALUE, Body: []byte("")},
@ -180,7 +180,7 @@ func TestSimpleClient_Auth(t *testing.T) {
}
func TestSimpleClient_Exec(t *testing.T) {
t.Run("successfull execution", func(t *testing.T) {
t.Run("successful execution", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1, 2}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 1, Type: grcon.SERVERDATA_RESPONSE_VALUE, Body: []byte("bar")},
@ -201,7 +201,7 @@ func TestSimpleClient_Exec(t *testing.T) {
}
})
t.Run("successfull multi packet execution", func(t *testing.T) {
t.Run("successful multi packet execution", func(t *testing.T) {
mockIdGen := &MockIdGenerator{Ids: []grcon.PacketId{1, 2}}
mock := &MockRemoteConsole{In: []grcon.Packet{
{Id: 1, Type: grcon.SERVERDATA_RESPONSE_VALUE, Body: []byte("foo")},

View file

@ -68,7 +68,7 @@ func ExampleRemoteConsole() {
log.Fatal("auth failed: auth rejected password invalid")
}
// packet that contais the command to execute
// packet that contains the command to execute
cmdPacket := grcon.Packet{
Id: 2,
Type: grcon.SERVERDATA_EXECCOMMAND,