redo discord mocks

This commit is contained in:
41666 2025-03-26 13:35:47 -07:00
parent f4718f979a
commit dfbb9e2bca
19 changed files with 223 additions and 105 deletions

View file

@ -1,30 +0,0 @@
package discord
import (
"bytes"
"encoding/json"
"io"
"net/http"
"github.com/stretchr/testify/mock"
)
type DiscordClientMock struct {
mock.Mock
}
func (c *DiscordClientMock) Do(req *http.Request) (*http.Response, error) {
args := c.Called(req)
return args.Get(0).(*http.Response), args.Error(1)
}
func (c *DiscordClientMock) MockResponse(statusCode int, data any) *http.Response {
body := bytes.Buffer{}
json.NewEncoder(&body).Encode(data)
return &http.Response{
StatusCode: statusCode,
Body: io.NopCloser(&body),
}
}

View file

@ -0,0 +1,42 @@
package clientmock
import (
"bytes"
"encoding/json"
"io"
"net/http"
"regexp"
"strings"
"github.com/stretchr/testify/mock"
)
type DiscordClientMock struct {
mock.Mock
}
func (c *DiscordClientMock) Do(req *http.Request) (*http.Response, error) {
args := c.Called(req)
return args.Get(0).(*http.Response), args.Error(1)
}
func (c *DiscordClientMock) BotAuth(req *http.Request) {
c.Called(req)
}
func (c *DiscordClientMock) MockResponse(method, path string, statusCode int, data any) {
body := bytes.Buffer{}
json.NewEncoder(&body).Encode(data)
r := &http.Response{
StatusCode: statusCode,
Body: io.NopCloser(&body),
}
pathMatcher := regexp.MustCompile(strings.ReplaceAll(path, "*", "[a-z0-9_-]+"))
c.On("Do", mock.MatchedBy(func(req *http.Request) bool {
return req.Method == method && pathMatcher.MatchString(req.URL.Path)
})).Return(r, nil)
}

View file

@ -5,12 +5,15 @@ import (
"net/http"
"net/url"
"time"
"github.com/goccy/go-json"
)
const DiscordBaseUrl = "https://discord.com/api/v10"
type IDiscordClient interface {
Do(req *http.Request) (*http.Response, error)
BotAuth(req *http.Request)
}
type DiscordClient struct {
@ -36,7 +39,11 @@ func (d *DiscordClient) Do(req *http.Request) (*http.Response, error) {
return d.Client.Do(req)
}
func NewRequest(method string, path string, botToken string) *http.Request {
func (d *DiscordClient) BotAuth(req *http.Request) {
req.Header.Set("Authorization", fmt.Sprintf("Bot %s", d.BotToken))
}
func NewRequest(method string, path string) *http.Request {
url, err := url.Parse(fmt.Sprintf("%s%s", DiscordBaseUrl, path))
if err != nil {
panic("discord/api: wtf couldnt join a string??")
@ -45,13 +52,15 @@ func NewRequest(method string, path string, botToken string) *http.Request {
req := &http.Request{
Method: method,
URL: url,
Header: http.Header{},
}
req.Header.Set("User-Agent", "Roleypoly (https://roleypoly.com, v4)")
if botToken != "" {
req.Header.Set("Authorization", fmt.Sprintf("Bot %s", botToken))
}
return req
}
func OutputResponse(resp *http.Response, dst any) error {
// TODO: more checks?
return json.NewDecoder(resp.Body).Decode(dst)
}

View file

@ -1,12 +1,39 @@
package discord
import "git.sapphic.engineer/roleypoly/v4/types"
import (
"fmt"
"git.sapphic.engineer/roleypoly/v4/types"
"git.sapphic.engineer/roleypoly/v4/utils"
)
type IGuild interface {
GetMember(memberID string) (IMember, error)
}
type Guild struct {
Client IDiscordClient
types.DiscordGuild
Client IDiscordClient `json:"-"`
}
func (g *Guild) GetMember(memberID string) (*Member, error) {
guildID := g.ID
req := NewRequest("GET", utils.J("guilds", guildID, "members", memberID))
g.Client.BotAuth(req)
resp, err := g.Client.Do(req)
if err != nil {
return nil, fmt.Errorf("Guild.GetMember: request failed: %w", err)
}
member := &Member{
Client: g.Client,
}
err = OutputResponse(resp, member)
if err != nil {
return nil, fmt.Errorf("Guild.GetMember: response decode failed: %w", err)
}
return member, nil
}

View file

@ -1,19 +0,0 @@
package discord
import (
"github.com/stretchr/testify/mock"
)
type GuildMock struct {
mock.Mock
}
func (g *GuildMock) GetMember(memberID string) (IMember, error) {
args := g.Called(memberID)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(IMember), args.Error(1)
}

31
discord/guild_test.go Normal file
View file

@ -0,0 +1,31 @@
package discord_test
import (
"testing"
"github.com/stretchr/testify/assert"
"git.sapphic.engineer/roleypoly/v4/discord"
"git.sapphic.engineer/roleypoly/v4/types/fixtures"
"git.sapphic.engineer/roleypoly/v4/utils"
)
var (
fixtureMember = &discord.Member{
DiscordMember: fixtures.Member,
}
)
func TestGetMember(t *testing.T) {
dc := defaultMocks(t)
g := discord.Guild{
Client: dc,
DiscordGuild: fixtures.Guild,
}
dc.MockResponse("GET", utils.J("guilds", fixtures.Guild.ID, "members", fixtureMember.User.ID), 200, fixtureMember)
m, err := g.GetMember("41666")
assert.Nil(t, err)
assert.Equal(t, "Doll", m.Nick)
}

View file

@ -1,5 +1,11 @@
package discord
import (
"fmt"
"git.sapphic.engineer/roleypoly/v4/utils"
)
type IGuildService interface {
Client() IDiscordClient
GetGuild(guildID string) (IGuild, error)
@ -19,7 +25,23 @@ func (gs *GuildService) Client() IDiscordClient {
return gs.client
}
func (gs *GuildService) GetGuild(guildID string) (IGuild, error) {
// gs.client
return nil, nil
func (gs *GuildService) GetGuild(guildID string) (*Guild, error) {
req := NewRequest("GET", utils.J("guilds", guildID))
gs.client.BotAuth(req)
resp, err := gs.client.Do(req)
if err != nil {
return nil, fmt.Errorf("GuildService.GetGuild: request failed: %w", err)
}
guild := &Guild{
Client: gs.client,
}
err = OutputResponse(resp, guild)
if err != nil {
return nil, fmt.Errorf("GuildService.GetGuild: response decode failed: %w", err)
}
return guild, nil
}

View file

@ -1,24 +0,0 @@
package discord
import (
"github.com/stretchr/testify/mock"
)
type GuildServiceMock struct {
mock.Mock
}
func (gs *GuildServiceMock) GetGuild(guildID string) (IGuild, error) {
args := gs.Called(guildID)
if args.Get(0) == nil {
return nil, args.Error(1)
}
return args.Get(0).(IGuild), args.Error(1)
}
func (gs *GuildServiceMock) Client() IDiscordClient {
args := gs.Called()
return args.Get(0).(IDiscordClient)
}

View file

@ -0,0 +1,27 @@
package discord_test
import (
"testing"
"git.sapphic.engineer/roleypoly/v4/discord"
"git.sapphic.engineer/roleypoly/v4/types/fixtures"
"git.sapphic.engineer/roleypoly/v4/utils"
"github.com/stretchr/testify/assert"
)
var (
fixtureGuild = &discord.Guild{
DiscordGuild: fixtures.Guild,
}
)
func TestGetGuild(t *testing.T) {
dc := defaultMocks(t)
gs := discord.NewGuildService(dc)
dc.MockResponse("GET", utils.J("guilds", fixtures.Guild.ID), 200, fixtureGuild)
g, err := gs.GetGuild("1312")
assert.Nil(t, err)
assert.Equal(t, "1312", g.ID)
}

View file

@ -8,6 +8,7 @@ type IMember interface {
}
type Member struct {
Client IDiscordClient
types.DiscordMember
}

View file

@ -1,17 +0,0 @@
package discord
import "github.com/stretchr/testify/mock"
type MemberMock struct {
mock.Mock
}
func (m *MemberMock) GetRoles() error {
args := m.Called()
return args.Error(0)
}
func (m *MemberMock) PatchRoles() error {
args := m.Called()
return args.Error(0)
}

1
discord/member_test.go Normal file
View file

@ -0,0 +1 @@
package discord_test

16
discord/utils_test.go Normal file
View file

@ -0,0 +1,16 @@
package discord_test
import (
"testing"
"git.sapphic.engineer/roleypoly/v4/discord/clientmock"
"github.com/stretchr/testify/mock"
)
func defaultMocks(t *testing.T) *clientmock.DiscordClientMock {
dc := &clientmock.DiscordClientMock{}
dc.On("BotAuth", mock.AnythingOfType("*http.Request"))
return dc
}

View file

@ -56,9 +56,8 @@ func TestPostHandlerSigFail(t *testing.T) {
app := roleypoly.CreateFiberApp()
i.Routes(app)
// TODO: make real interaction
body, err := json.Marshal(map[string]string{
"temp": "temp",
body, err := json.Marshal(map[string]any{
"type": 1,
})
if err != nil {
t.Error(err)

View file

@ -10,7 +10,7 @@ import (
)
type TestingController struct {
Guilds discord.IGuildService
Guilds *discord.GuildService
}
func (t *TestingController) Routes(r fiber.Router) {

9
types/fixtures/guild.go Normal file
View file

@ -0,0 +1,9 @@
package fixtures
import "git.sapphic.engineer/roleypoly/v4/types"
var (
Guild = types.DiscordGuild{
ID: "1312",
}
)

12
types/fixtures/member.go Normal file
View file

@ -0,0 +1,12 @@
package fixtures
import "git.sapphic.engineer/roleypoly/v4/types"
var (
Member = types.DiscordMember{
User: User,
Nick: "Doll",
Permissions: 0,
Roles: []string{"role1", "role2"},
}
)

10
types/fixtures/user.go Normal file
View file

@ -0,0 +1,10 @@
package fixtures
import "git.sapphic.engineer/roleypoly/v4/types"
var (
User = types.DiscordUser{
Username: "41666",
ID: "41666",
}
)

View file

@ -1,3 +1,5 @@
package types
type DiscordGuild struct{}
type DiscordGuild struct {
ID string `json:"id"`
}