Starting to write unit tests!

This commit is contained in:
Gabriel Simmer 2022-07-16 02:00:55 +01:00
parent 44f9cf6301
commit 53ddde50c0
9 changed files with 669 additions and 4 deletions

View file

@ -11,11 +11,13 @@ packages:
sources: sources:
- git@git.sr.ht:~gmem/minecraft-server-invites - git@git.sr.ht:~gmem/minecraft-server-invites
tasks: tasks:
- test: |
cd minecraft-server-invites
go test ./... -cover
- setup-docker: | - setup-docker: |
sudo touch /etc/subuid /etc/subgid sudo touch /etc/subuid /etc/subgid
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 build sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 build
- build: | - build: |
cd minecraft-server-invites
podman build . -t icr.gmem.ca/wlm podman build . -t icr.gmem.ca/wlm
- push: | - push: |
sudo systemctl start tailscaled sudo systemctl start tailscaled

1
go.mod
View file

@ -5,6 +5,7 @@ go 1.18
require ( require (
github.com/Kelwing/mc-rcon v0.0.0-20220214194105-bec8dcbccc3f github.com/Kelwing/mc-rcon v0.0.0-20220214194105-bec8dcbccc3f
github.com/alexedwards/flow v0.0.0-20220607190737-c48a87f2b4c4 github.com/alexedwards/flow v0.0.0-20220607190737-c48a87f2b4c4
github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/mattn/go-sqlite3 v1.14.14 github.com/mattn/go-sqlite3 v1.14.14
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0

21
go.sum
View file

@ -2,6 +2,8 @@ github.com/Kelwing/mc-rcon v0.0.0-20220214194105-bec8dcbccc3f h1:ySopb0/agJ4rwNs
github.com/Kelwing/mc-rcon v0.0.0-20220214194105-bec8dcbccc3f/go.mod h1:wlXY/EO9CBjMViEh95JOQhp//RMnHs4ZUBhYhx43LdM= github.com/Kelwing/mc-rcon v0.0.0-20220214194105-bec8dcbccc3f/go.mod h1:wlXY/EO9CBjMViEh95JOQhp//RMnHs4ZUBhYhx43LdM=
github.com/alexedwards/flow v0.0.0-20220607190737-c48a87f2b4c4 h1:tF8vI7d4pKpByHydzNUDsOuZMOqmuyt+8/HuSN0hzGA= github.com/alexedwards/flow v0.0.0-20220607190737-c48a87f2b4c4 h1:tF8vI7d4pKpByHydzNUDsOuZMOqmuyt+8/HuSN0hzGA=
github.com/alexedwards/flow v0.0.0-20220607190737-c48a87f2b4c4/go.mod h1:1rjOQiOqQlmMdUMuvlJFjldqTnE/tQULE7qPIu4aq3U= github.com/alexedwards/flow v0.0.0-20220607190737-c48a87f2b4c4/go.mod h1:1rjOQiOqQlmMdUMuvlJFjldqTnE/tQULE7qPIu4aq3U=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
@ -12,17 +14,36 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw= github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw= golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw=
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=

View file

@ -4,6 +4,7 @@ import (
"github.com/alexedwards/flow" "github.com/alexedwards/flow"
"log" "log"
"net/http" "net/http"
"whitelistmanager/invite"
"whitelistmanager/store" "whitelistmanager/store"
"whitelistmanager/transport" "whitelistmanager/transport"
) )
@ -15,7 +16,8 @@ func main() {
panic(err) panic(err)
} }
defer db.Close() defer db.Close()
handlers := transport.New(db) im := invite.NewManager(db)
handlers := transport.New(db, im)
// Auth endpoints // Auth endpoints
mux.Group(func(mux *flow.Mux) { mux.Group(func(mux *flow.Mux) {
mux.HandleFunc("/api/v1/auth/redirect", handlers.AuthRedirect) mux.HandleFunc("/api/v1/auth/redirect", handlers.AuthRedirect)

65
mocks/invite/invite.go Normal file
View file

@ -0,0 +1,65 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: invite/invite.go
// Package mock_invite is a generated GoMock package.
package mock_invite
import (
reflect "reflect"
store "whitelistmanager/store"
gomock "github.com/golang/mock/gomock"
)
// MockInviteManager is a mock of InviteManager interface.
type MockInviteManager struct {
ctrl *gomock.Controller
recorder *MockInviteManagerMockRecorder
}
// MockInviteManagerMockRecorder is the mock recorder for MockInviteManager.
type MockInviteManagerMockRecorder struct {
mock *MockInviteManager
}
// NewMockInviteManager creates a new mock instance.
func NewMockInviteManager(ctrl *gomock.Controller) *MockInviteManager {
mock := &MockInviteManager{ctrl: ctrl}
mock.recorder = &MockInviteManagerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockInviteManager) EXPECT() *MockInviteManagerMockRecorder {
return m.recorder
}
// Create mocks base method.
func (m *MockInviteManager) Create(in store.Invite, user store.User) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Create", in, user)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Create indicates an expected call of Create.
func (mr *MockInviteManagerMockRecorder) Create(in, user interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockInviteManager)(nil).Create), in, user)
}
// RemainingUses mocks base method.
func (m *MockInviteManager) RemainingUses(in store.Invite) (int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RemainingUses", in)
ret0, _ := ret[0].(int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// RemainingUses indicates an expected call of RemainingUses.
func (mr *MockInviteManagerMockRecorder) RemainingUses(in interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemainingUses", reflect.TypeOf((*MockInviteManager)(nil).RemainingUses), in)
}

View file

@ -0,0 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: minecraft/minecraft.go
// Package mock_minecraft is a generated GoMock package.
package mock_minecraft

281
mocks/store/database.go Normal file
View file

@ -0,0 +1,281 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: store/database.go
// Package mock_store is a generated GoMock package.
package mock_store
import (
reflect "reflect"
store "whitelistmanager/store"
gomock "github.com/golang/mock/gomock"
)
// MockStorer is a mock of Storer interface.
type MockStorer struct {
ctrl *gomock.Controller
recorder *MockStorerMockRecorder
}
// MockStorerMockRecorder is the mock recorder for MockStorer.
type MockStorerMockRecorder struct {
mock *MockStorer
}
// NewMockStorer creates a new mock instance.
func NewMockStorer(ctrl *gomock.Controller) *MockStorer {
mock := &MockStorer{ctrl: ctrl}
mock.recorder = &MockStorerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockStorer) EXPECT() *MockStorerMockRecorder {
return m.recorder
}
// Close mocks base method.
func (m *MockStorer) Close() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close")
ret0, _ := ret[0].(error)
return ret0
}
// Close indicates an expected call of Close.
func (mr *MockStorerMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockStorer)(nil).Close))
}
// DeleteInvite mocks base method.
func (m *MockStorer) DeleteInvite(invite store.Invite) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteInvite", invite)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteInvite indicates an expected call of DeleteInvite.
func (mr *MockStorerMockRecorder) DeleteInvite(invite interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteInvite", reflect.TypeOf((*MockStorer)(nil).DeleteInvite), invite)
}
// DeleteServer mocks base method.
func (m *MockStorer) DeleteServer(server store.Server, user store.User) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteServer", server, user)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteServer indicates an expected call of DeleteServer.
func (mr *MockStorerMockRecorder) DeleteServer(server, user interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteServer", reflect.TypeOf((*MockStorer)(nil).DeleteServer), server, user)
}
// GetInvite mocks base method.
func (m *MockStorer) GetInvite(token string) (store.Invite, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetInvite", token)
ret0, _ := ret[0].(store.Invite)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetInvite indicates an expected call of GetInvite.
func (mr *MockStorerMockRecorder) GetInvite(token interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInvite", reflect.TypeOf((*MockStorer)(nil).GetInvite), token)
}
// GetServer mocks base method.
func (m *MockStorer) GetServer(id string) (store.Server, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetServer", id)
ret0, _ := ret[0].(store.Server)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetServer indicates an expected call of GetServer.
func (mr *MockStorerMockRecorder) GetServer(id interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServer", reflect.TypeOf((*MockStorer)(nil).GetServer), id)
}
// GetUser mocks base method.
func (m *MockStorer) GetUser(uid string) (store.User, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetUser", uid)
ret0, _ := ret[0].(store.User)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUser indicates an expected call of GetUser.
func (mr *MockStorerMockRecorder) GetUser(uid interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUser", reflect.TypeOf((*MockStorer)(nil).GetUser), uid)
}
// GetUserServers mocks base method.
func (m *MockStorer) GetUserServers(user store.User) ([]store.Server, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetUserServers", user)
ret0, _ := ret[0].([]store.Server)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUserServers indicates an expected call of GetUserServers.
func (mr *MockStorerMockRecorder) GetUserServers(user interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserServers", reflect.TypeOf((*MockStorer)(nil).GetUserServers), user)
}
// InviteLog mocks base method.
func (m *MockStorer) InviteLog(invite store.Invite) ([]store.InviteLog, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InviteLog", invite)
ret0, _ := ret[0].([]store.InviteLog)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// InviteLog indicates an expected call of InviteLog.
func (mr *MockStorerMockRecorder) InviteLog(invite interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InviteLog", reflect.TypeOf((*MockStorer)(nil).InviteLog), invite)
}
// LogInviteUse mocks base method.
func (m *MockStorer) LogInviteUse(user store.User, invite store.Invite) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LogInviteUse", user, invite)
ret0, _ := ret[0].(error)
return ret0
}
// LogInviteUse indicates an expected call of LogInviteUse.
func (mr *MockStorerMockRecorder) LogInviteUse(user, invite interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogInviteUse", reflect.TypeOf((*MockStorer)(nil).LogInviteUse), user, invite)
}
// OauthState mocks base method.
func (m *MockStorer) OauthState(id string) (store.OauthState, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "OauthState", id)
ret0, _ := ret[0].(store.OauthState)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// OauthState indicates an expected call of OauthState.
func (mr *MockStorerMockRecorder) OauthState(id interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OauthState", reflect.TypeOf((*MockStorer)(nil).OauthState), id)
}
// SaveInvite mocks base method.
func (m *MockStorer) SaveInvite(invite store.Invite) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SaveInvite", invite)
ret0, _ := ret[0].(error)
return ret0
}
// SaveInvite indicates an expected call of SaveInvite.
func (mr *MockStorerMockRecorder) SaveInvite(invite interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveInvite", reflect.TypeOf((*MockStorer)(nil).SaveInvite), invite)
}
// SaveOauthState mocks base method.
func (m *MockStorer) SaveOauthState(state store.OauthState) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SaveOauthState", state)
ret0, _ := ret[0].(error)
return ret0
}
// SaveOauthState indicates an expected call of SaveOauthState.
func (mr *MockStorerMockRecorder) SaveOauthState(state interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveOauthState", reflect.TypeOf((*MockStorer)(nil).SaveOauthState), state)
}
// SaveServer mocks base method.
func (m *MockStorer) SaveServer(server store.Server) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SaveServer", server)
ret0, _ := ret[0].(error)
return ret0
}
// SaveServer indicates an expected call of SaveServer.
func (mr *MockStorerMockRecorder) SaveServer(server interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveServer", reflect.TypeOf((*MockStorer)(nil).SaveServer), server)
}
// SaveSession mocks base method.
func (m *MockStorer) SaveSession(token string, user store.User) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SaveSession", token, user)
ret0, _ := ret[0].(error)
return ret0
}
// SaveSession indicates an expected call of SaveSession.
func (mr *MockStorerMockRecorder) SaveSession(token, user interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveSession", reflect.TypeOf((*MockStorer)(nil).SaveSession), token, user)
}
// SaveUser mocks base method.
func (m *MockStorer) SaveUser(user store.User) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SaveUser", user)
ret0, _ := ret[0].(error)
return ret0
}
// SaveUser indicates an expected call of SaveUser.
func (mr *MockStorerMockRecorder) SaveUser(user interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveUser", reflect.TypeOf((*MockStorer)(nil).SaveUser), user)
}
// ServerInvites mocks base method.
func (m *MockStorer) ServerInvites(server store.Server) ([]store.Invite, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ServerInvites", server)
ret0, _ := ret[0].([]store.Invite)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ServerInvites indicates an expected call of ServerInvites.
func (mr *MockStorerMockRecorder) ServerInvites(server interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServerInvites", reflect.TypeOf((*MockStorer)(nil).ServerInvites), server)
}
// SessionUser mocks base method.
func (m *MockStorer) SessionUser(token string) (store.User, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SessionUser", token)
ret0, _ := ret[0].(store.User)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// SessionUser indicates an expected call of SessionUser.
func (mr *MockStorerMockRecorder) SessionUser(token interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SessionUser", reflect.TypeOf((*MockStorer)(nil).SessionUser), token)
}

View file

@ -41,8 +41,7 @@ type Handle interface {
InviteLog(w http.ResponseWriter, r *http.Request) InviteLog(w http.ResponseWriter, r *http.Request)
} }
func New(store store.Storer) *Handler { func New(store store.Storer, im invite.InviteManager) *Handler {
im := invite.NewManager(store)
return &Handler{ return &Handler{
store: store, store: store,
manager: im, manager: im,

289
transport/http_test.go Normal file
View file

@ -0,0 +1,289 @@
package transport_test
import (
"bytes"
"context"
"database/sql"
"encoding/json"
"errors"
"github.com/alexedwards/flow"
"github.com/golang/mock/gomock"
"log"
"net/http"
"net/http/httptest"
"testing"
"time"
"whitelistmanager/invite"
mock_invite "whitelistmanager/mocks/invite"
mock_store "whitelistmanager/mocks/store"
"whitelistmanager/store"
"whitelistmanager/transport"
)
type invitePayload struct {
Server string `json:"server"`
Unlimited bool `json:"unlimited"`
Uses int `json:"uses"`
}
func TestInvites(t *testing.T) {
ctrl := gomock.NewController(t)
st := mock_store.NewMockStorer(ctrl)
im := mock_invite.NewMockInviteManager(ctrl)
user := store.User{
Id: "1",
Token: "",
DisplayName: "user",
RefreshToken: "",
TokenExpiry: time.Time{},
}
server := store.Server{
Id: "1",
}
inv := store.Invite{
Token: "foo",
Server: server,
Uses: 0,
Unlimited: false,
}
invNoToken := store.Invite{
Token: "",
Server: store.Server{
Id: "1",
},
Uses: 0,
Unlimited: false,
}
invPayload := invitePayload{
Server: "1",
Uses: 0,
Unlimited: false,
}
t.Run("create invite correctly", func(t *testing.T) {
im.EXPECT().Create(invNoToken, user).Return(inv.Token, nil)
handler := transport.New(st, im)
jsonData, err := json.Marshal(invPayload)
if err != nil {
log.Fatal(err)
}
req, err := http.NewRequest("POST", "/api/v1/invites", bytes.NewBuffer(jsonData))
if err != nil {
t.Fatal(err)
}
ctx := req.Context()
ctx = context.WithValue(ctx, "user", user)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
h := http.HandlerFunc(handler.CreateInvite)
h.ServeHTTP(rr, req)
// Check the status code is what we expect.
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
expected := `foo`
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
})
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)
jsonData, err := json.Marshal(invPayload)
if err != nil {
log.Fatal(err)
}
req, err := http.NewRequest("POST", "/api/v1/invites", bytes.NewBuffer(jsonData))
if err != nil {
t.Fatal(err)
}
ctx := req.Context()
ctx = context.WithValue(ctx, "user", user)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
h := http.HandlerFunc(handler.CreateInvite)
h.ServeHTTP(rr, req)
// Check the status code is what we expect.
if status := rr.Code; status != http.StatusForbidden {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusForbidden)
}
expected := "user is not owner of server\n"
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
})
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)
req, err := http.NewRequest("GET", "/api/v1/invite/foo", 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", handler.GetInvite)
m.ServeHTTP(rr, req)
// Check the status code is what we expect.
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
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("existing invite", func(t *testing.T) {
m := flow.New()
st.EXPECT().GetInvite(inv.Token).Return(inv, nil)
handler := transport.New(st, im)
req, err := http.NewRequest("GET", "/api/v1/invite/foo", 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", handler.GetInvite)
m.ServeHTTP(rr, req)
// Check the status code is what we expect.
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
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("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)
req, err := http.NewRequest("GET", "/api/v1/invite/foo", 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", handler.GetInvite)
m.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusNotFound {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusNotFound)
}
})
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)
req, err := http.NewRequest("GET", "/api/v1/invite/foo", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
m.HandleFunc("/api/v1/invite/:id", handler.GetInvite)
m.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusOK {
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)
// 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))
// }
})
}