From 30168c503fd1e26cc027d6a5e4482106c806cb9c Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sat, 16 Jul 2022 02:16:14 +0100 Subject: [PATCH] Tests for Minecraft, minor refactoring --- .build.yml | 1 + main.go | 4 +- minecraft/minecraft.go | 13 +++++- mocks/minecraft/minecraft.go | 45 +++++++++++++++++++++ transport/http.go | 6 ++- transport/http_test.go | 78 ++++++++++++++++++------------------ 6 files changed, 104 insertions(+), 43 deletions(-) diff --git a/.build.yml b/.build.yml index d261a8d..d5ce2d5 100644 --- a/.build.yml +++ b/.build.yml @@ -19,6 +19,7 @@ tasks: sudo touch /etc/subuid /etc/subgid sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 build - build: | + cd minecraft-server-invites podman build . -t icr.gmem.ca/wlm - push: | sudo systemctl start tailscaled diff --git a/main.go b/main.go index 8ae7965..c1c67c6 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "log" "net/http" "whitelistmanager/invite" + "whitelistmanager/minecraft" "whitelistmanager/store" "whitelistmanager/transport" ) @@ -17,7 +18,8 @@ func main() { } defer db.Close() im := invite.NewManager(db) - handlers := transport.New(db, im) + mc := minecraft.NewCom() + handlers := transport.New(db, im, mc) // Auth endpoints mux.Group(func(mux *flow.Mux) { mux.HandleFunc("/api/v1/auth/redirect", handlers.AuthRedirect) diff --git a/minecraft/minecraft.go b/minecraft/minecraft.go index a2e2fb6..2dd657d 100644 --- a/minecraft/minecraft.go +++ b/minecraft/minecraft.go @@ -13,7 +13,18 @@ const ( RconCommandError = "command failed" ) -func Whitelist(user string, server store.Server) (string, error) { +type MinecraftCom struct { +} + +type Minecraft interface { + Whitelist(user string, server store.Server) (string, error) +} + +func NewCom() *MinecraftCom { + return &MinecraftCom{} +} + +func (m *MinecraftCom) Whitelist(user string, server store.Server) (string, error) { conn := new(mcrcon.MCConn) err := conn.Open(server.Rcon.Address, server.Rcon.Password) if err != nil { diff --git a/mocks/minecraft/minecraft.go b/mocks/minecraft/minecraft.go index f483420..c3edef5 100644 --- a/mocks/minecraft/minecraft.go +++ b/mocks/minecraft/minecraft.go @@ -3,3 +3,48 @@ // Package mock_minecraft is a generated GoMock package. package mock_minecraft + +import ( + reflect "reflect" + store "whitelistmanager/store" + + gomock "github.com/golang/mock/gomock" +) + +// MockMinecraft is a mock of Minecraft interface. +type MockMinecraft struct { + ctrl *gomock.Controller + recorder *MockMinecraftMockRecorder +} + +// MockMinecraftMockRecorder is the mock recorder for MockMinecraft. +type MockMinecraftMockRecorder struct { + mock *MockMinecraft +} + +// NewMockMinecraft creates a new mock instance. +func NewMockMinecraft(ctrl *gomock.Controller) *MockMinecraft { + mock := &MockMinecraft{ctrl: ctrl} + mock.recorder = &MockMinecraftMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockMinecraft) EXPECT() *MockMinecraftMockRecorder { + return m.recorder +} + +// Whitelist mocks base method. +func (m *MockMinecraft) Whitelist(user string, server store.Server) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Whitelist", user, server) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Whitelist indicates an expected call of Whitelist. +func (mr *MockMinecraftMockRecorder) Whitelist(user, server interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Whitelist", reflect.TypeOf((*MockMinecraft)(nil).Whitelist), user, server) +} diff --git a/transport/http.go b/transport/http.go index 7a4385c..7921026 100644 --- a/transport/http.go +++ b/transport/http.go @@ -21,6 +21,7 @@ import ( type Handler struct { store store.Storer manager invite.InviteManager + mc minecraft.Minecraft } type Handle interface { @@ -41,10 +42,11 @@ type Handle interface { InviteLog(w http.ResponseWriter, r *http.Request) } -func New(store store.Storer, im invite.InviteManager) *Handler { +func New(store store.Storer, im invite.InviteManager, mc minecraft.Minecraft) *Handler { return &Handler{ store: store, manager: im, + mc: mc, } } @@ -157,7 +159,7 @@ func (h *Handler) AcceptInvite(w http.ResponseWriter, r *http.Request) { } user := r.Context().Value("user").(store.User) log.Println(user.DisplayName) - resp, err := minecraft.Whitelist(user.DisplayName, server) + resp, err := h.mc.Whitelist(user.DisplayName, server) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/transport/http_test.go b/transport/http_test.go index 69e885e..e8553f1 100644 --- a/transport/http_test.go +++ b/transport/http_test.go @@ -15,6 +15,7 @@ import ( "time" "whitelistmanager/invite" mock_invite "whitelistmanager/mocks/invite" + mock_minecraft "whitelistmanager/mocks/minecraft" mock_store "whitelistmanager/mocks/store" "whitelistmanager/store" "whitelistmanager/transport" @@ -30,6 +31,7 @@ func TestInvites(t *testing.T) { ctrl := gomock.NewController(t) st := mock_store.NewMockStorer(ctrl) im := mock_invite.NewMockInviteManager(ctrl) + mc := mock_minecraft.NewMockMinecraft(ctrl) user := store.User{ Id: "1", @@ -67,7 +69,7 @@ func TestInvites(t *testing.T) { t.Run("create invite correctly", func(t *testing.T) { im.EXPECT().Create(invNoToken, user).Return(inv.Token, nil) - handler := transport.New(st, im) + handler := transport.New(st, im, mc) jsonData, err := json.Marshal(invPayload) if err != nil { @@ -102,7 +104,7 @@ func TestInvites(t *testing.T) { t.Run("user is not server owner", func(t *testing.T) { im.EXPECT().Create(invNoToken, user).Return("", errors.New(invite.NotOwnerofServer)) - handler := transport.New(st, im) + handler := transport.New(st, im, mc) jsonData, err := json.Marshal(invPayload) if err != nil { @@ -138,7 +140,7 @@ func TestInvites(t *testing.T) { t.Run("get existing invite", func(t *testing.T) { m := flow.New() st.EXPECT().GetInvite(inv.Token).Return(inv, nil) - handler := transport.New(st, im) + handler := transport.New(st, im, mc) req, err := http.NewRequest("GET", "/api/v1/invite/foo", nil) if err != nil { @@ -171,7 +173,7 @@ func TestInvites(t *testing.T) { t.Run("existing invite", func(t *testing.T) { m := flow.New() st.EXPECT().GetInvite(inv.Token).Return(inv, nil) - handler := transport.New(st, im) + handler := transport.New(st, im, mc) req, err := http.NewRequest("GET", "/api/v1/invite/foo", nil) if err != nil { @@ -204,7 +206,7 @@ func TestInvites(t *testing.T) { t.Run("non existent invite", func(t *testing.T) { m := flow.New() st.EXPECT().GetInvite(inv.Token).Return(store.Invite{}, sql.ErrNoRows) - handler := transport.New(st, im) + handler := transport.New(st, im, mc) req, err := http.NewRequest("GET", "/api/v1/invite/foo", nil) if err != nil { @@ -227,7 +229,7 @@ func TestInvites(t *testing.T) { t.Run("user not logged in when getting invite", func(t *testing.T) { m := flow.New() st.EXPECT().GetInvite(inv.Token).Return(inv, nil) - handler := transport.New(st, im) + handler := transport.New(st, im, mc) req, err := http.NewRequest("GET", "/api/v1/invite/foo", nil) if err != nil { @@ -253,37 +255,35 @@ func TestInvites(t *testing.T) { } }) - //t.Run("user can accept invite", func(t *testing.T) { - // m := flow.New() - // st.EXPECT().GetInvite(inv.Token).Return(inv, nil) - // im.EXPECT().RemainingUses(inv).Return(1, nil) - // st.EXPECT().GetServer(server.Id).Return(server, nil) - // handler := transport.New(st, im) - // - // req, err := http.NewRequest("POST", "/api/v1/invite/foo/accept", nil) - // if err != nil { - // t.Fatal(err) - // } - // - // ctx := req.Context() - // ctx = context.WithValue(ctx, "user", user) - // req = req.WithContext(ctx) - // rr := httptest.NewRecorder() - // m.HandleFunc("/api/v1/invite/:id/accept", handler.AcceptInvite, "POST") - // m.ServeHTTP(rr, req) - // - // if status := rr.Code; status != http.StatusForbidden { - // t.Errorf("handler returned wrong status code: got %v want %v", - // status, http.StatusNotFound) - // } - // - // expected, err := json.Marshal(inv) - // if err != nil { - // t.Fatal(err) - // } - // if rr.Body.String() != string(expected)+"\n" { - // t.Errorf("handler returned unexpected body: got %v want %v", - // rr.Body.String(), string(expected)) - // } - //}) + t.Run("user can accept invite", func(t *testing.T) { + m := flow.New() + st.EXPECT().GetInvite(inv.Token).Return(inv, nil) + im.EXPECT().RemainingUses(inv).Return(1, nil) + st.EXPECT().GetServer(server.Id).Return(server, nil) + mc.EXPECT().Whitelist(user.DisplayName, server).Return("success", nil) + handler := transport.New(st, im, mc) + + req, err := http.NewRequest("POST", "/api/v1/invite/foo/accept", nil) + if err != nil { + t.Fatal(err) + } + + ctx := req.Context() + ctx = context.WithValue(ctx, "user", user) + req = req.WithContext(ctx) + rr := httptest.NewRecorder() + m.HandleFunc("/api/v1/invite/:id/accept", handler.AcceptInvite, "POST") + m.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + t.Errorf("handler returned wrong status code: got %v want %v", + status, http.StatusOK) + } + + expected := "success" + if rr.Body.String() != expected { + t.Errorf("handler returned unexpected body: got %v want %v", + rr.Body.String(), expected) + } + }) }