Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include context to outgoing http api requests #3

Merged
merged 3 commits into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package raiderio

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -30,7 +31,7 @@ func NewClient() *Client {
// GetCharacter retrieves a character profile from the Raider.IO API
// It returns an error if the API returns a non-200 status code, or if the
// response body cannot be read or mapped to the CharacterProfile struct
func (c *Client) GetCharacter(cq *CharacterQuery) (*Character, error) {
func (c *Client) GetCharacter(ctx context.Context, cq *CharacterQuery) (*Character, error) {
err := validateCharacterQuery(cq)
if err != nil {
return nil, err
Expand All @@ -41,7 +42,7 @@ func (c *Client) GetCharacter(cq *CharacterQuery) (*Character, error) {
reqUrl += "&fields=" + strings.Join(cq.fields, ",")
}

body, err := c.getAPIResponse(reqUrl)
body, err := c.getAPIResponse(ctx, reqUrl)
if err != nil {
return nil, err
}
Expand All @@ -58,7 +59,7 @@ func (c *Client) GetCharacter(cq *CharacterQuery) (*Character, error) {
// GetGuild retrieves a guild profile from the Raider.IO API
// It returns an error if the API returns a non-200 status code, or if the
// response body cannot be read or mapped to the GuildProfile struct
func (c *Client) GetGuild(gq *GuildQuery) (*Guild, error) {
func (c *Client) GetGuild(ctx context.Context, gq *GuildQuery) (*Guild, error) {
err := createGuildQuery(gq)
if err != nil {
return nil, err
Expand All @@ -69,7 +70,7 @@ func (c *Client) GetGuild(gq *GuildQuery) (*Guild, error) {
reqUrl += "&fields=" + strings.Join(gq.fields, ",")
}

body, err := c.getAPIResponse(reqUrl)
body, err := c.getAPIResponse(ctx, reqUrl)
if err != nil {
return nil, err
}
Expand All @@ -86,9 +87,9 @@ func (c *Client) GetGuild(gq *GuildQuery) (*Guild, error) {
// It returns an error if the API returns a non-200 status code, or if the
// response body cannot be read or mapped to the Raids struct
// Takes an Expansion enum as a parameter
func (c *Client) GetRaids(e expansion.Expansion) (*Raids, error) {
func (c *Client) GetRaids(ctx context.Context, e expansion.Expansion) (*Raids, error) {
reqUrl := c.ApiUrl + "/raiding/static-data?expansion_id=" + fmt.Sprintf("%d", e)
body, err := c.getAPIResponse(reqUrl)
body, err := c.getAPIResponse(ctx, reqUrl)
if err != nil {
return nil, err
}
Expand All @@ -106,7 +107,7 @@ func (c *Client) GetRaids(e expansion.Expansion) (*Raids, error) {
// It returns an error if the API returns a non-200 status code, or if the
// response body cannot be read or mapped to the RaidRankings struct
// Takes a RaidQuery struct as a parameter
func (c *Client) GetRaidRankings(rq *RaidQuery) (*RaidRankings, error) {
func (c *Client) GetRaidRankings(ctx context.Context, rq *RaidQuery) (*RaidRankings, error) {
err := validateRaidRankingsQuery(rq)
if err != nil {
return nil, err
Expand All @@ -127,7 +128,7 @@ func (c *Client) GetRaidRankings(rq *RaidQuery) (*RaidRankings, error) {
reqUrl += "&page=" + fmt.Sprintf("%d", rq.Page)
}

body, err := c.getAPIResponse(reqUrl)
body, err := c.getAPIResponse(ctx, reqUrl)
if err != nil {
return nil, err
}
Expand Down
132 changes: 96 additions & 36 deletions client_test.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
package raiderio_test

import (
"context"
"os"
"testing"
"time"

"github.com/tmaffia/raiderio"
"github.com/tmaffia/raiderio/expansion"
"github.com/tmaffia/raiderio/region"
)

func TestNewClient(t *testing.T) {
c := raiderio.NewClient()
var c *raiderio.Client
var defaultCtx context.Context

func setup() {
c = raiderio.NewClient()
defaultCtx = context.Background()
}

func TestMain(m *testing.M) {
setup()
exitCode := m.Run()
os.Exit(exitCode)
}

func TestNewClient(t *testing.T) {
if c.ApiUrl != "https://raider.io/api/v1" {
t.Errorf("NewClient apiUrl created incorrectly")
}
}

func TestGetCharacterProfile(t *testing.T) {
c := raiderio.NewClient()

testCases := []struct {
timeout bool
region *region.Region
realm string
name string
Expand All @@ -33,10 +47,18 @@ func TestGetCharacterProfile(t *testing.T) {
{region: &region.Region{Slug: "badregion"}, realm: "illidan", name: "impossiblecharactername", expectedErrMsg: "invalid region"},
{region: region.US, realm: "illidan", name: "impossiblecharactername", expectedErrMsg: "character not found"},
{region: region.US, realm: "invalidrealm", name: "highervalue", expectedErrMsg: "invalid realm"},
{timeout: true, region: region.US, realm: "illidan", name: "highervalue", expectedErrMsg: "raiderio api request timeout"},
}

for _, tc := range testCases {
profile, err := c.GetCharacter(&raiderio.CharacterQuery{
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(defaultCtx, time.Millisecond*10)
defer cancel()
}

profile, err := c.GetCharacter(ctx, &raiderio.CharacterQuery{
Region: tc.region,
Realm: tc.realm,
Name: tc.name,
Expand All @@ -53,20 +75,27 @@ func TestGetCharacterProfile(t *testing.T) {
}

func TestGetCharacterWGear(t *testing.T) {
c := raiderio.NewClient()

testCases := []struct {
timeout bool
region *region.Region
realm string
name string
expectedErrMsg string
expectedName string
}{
{region: region.US, realm: "illidan", name: "highervalue", expectedName: "Highervalue"},
{timeout: true, region: region.US, realm: "illidan", name: "highervalue", expectedErrMsg: "raiderio api request timeout"},
}

for _, tc := range testCases {
profile, err := c.GetCharacter(&raiderio.CharacterQuery{
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
defer cancel()
}

profile, err := c.GetCharacter(ctx, &raiderio.CharacterQuery{
Region: tc.region,
Realm: tc.realm,
Name: tc.name,
Expand All @@ -88,24 +117,22 @@ func TestGetCharacterWGear(t *testing.T) {
}

func TestGetCharacterWTalents(t *testing.T) {
c := raiderio.NewClient()
cq := raiderio.CharacterQuery{
Region: region.US,
Realm: "illidan",
Name: "highervalue",
TalentLoadout: true,
}

profile, err := c.GetCharacter(&cq)
profile, err := c.GetCharacter(defaultCtx, &cq)
if err == nil && profile.TalentLoadout.LoadoutText == "" {
t.Fatalf("talent loadout: %v expected to not be empty", profile.TalentLoadout.LoadoutText)
}
}

func TestGetGuild(t *testing.T) {
c := raiderio.NewClient()

testCases := []struct {
timeout bool
region *region.Region
realm string
name string
Expand All @@ -119,10 +146,18 @@ func TestGetGuild(t *testing.T) {
{region: &region.Region{Slug: "badregion"}, realm: "illidan", name: "warpath", expectedErrMsg: "invalid region"},
{region: region.US, realm: "illidan", name: "impossible_guild_name", expectedErrMsg: "guild not found"},
{region: region.US, realm: "invalidrealm", name: "highervalue", expectedErrMsg: "invalid realm"},
{timeout: true, region: region.US, realm: "illidan", name: "highervalue", expectedErrMsg: "raiderio api request timeout"},
}

for _, tc := range testCases {
profile, err := c.GetGuild(&raiderio.GuildQuery{
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
defer cancel()
}

profile, err := c.GetGuild(ctx, &raiderio.GuildQuery{
Region: tc.region,
Realm: tc.realm,
Name: tc.name,
Expand All @@ -139,7 +174,6 @@ func TestGetGuild(t *testing.T) {
}

func TestGetGuildWMembers(t *testing.T) {
c := raiderio.NewClient()
testCases := []struct {
region *region.Region
realm string
Expand All @@ -149,12 +183,12 @@ func TestGetGuildWMembers(t *testing.T) {
}

for range testCases {
profile, err := c.GetGuild((&raiderio.GuildQuery{
profile, err := c.GetGuild(defaultCtx, &raiderio.GuildQuery{
Region: region.US,
Realm: "illidan",
Name: "warpath",
Members: true,
}))
})

if err != nil {
t.Fatalf("Error getting guild")
Expand All @@ -168,7 +202,6 @@ func TestGetGuildWMembers(t *testing.T) {
}

func TestGetGuildWRaidProgression(t *testing.T) {
c := raiderio.NewClient()
testCases := []struct {
region *region.Region
realm string
Expand All @@ -178,7 +211,7 @@ func TestGetGuildWRaidProgression(t *testing.T) {
}

for range testCases {
profile, err := c.GetGuild(&raiderio.GuildQuery{
profile, err := c.GetGuild(defaultCtx, &raiderio.GuildQuery{
Region: region.US,
Realm: "illidan",
Name: "warpath",
Expand All @@ -196,55 +229,74 @@ func TestGetGuildWRaidProgression(t *testing.T) {
}

func TestGetGuildWRaidRankings(t *testing.T) {
c := raiderio.NewClient()
testCases := []struct {
region *region.Region
realm string
name string
raidName string
expectedRank int
timeout bool
region *region.Region
realm string
name string
raidName string
expectedRank int
expectedErrMsg string
}{
{region: region.US, realm: "illidan", name: "warpath",
raidName: "aberrus-the-shadowed-crucible", expectedRank: 158},
{timeout: true, region: region.US, realm: "illidan", name: "warpath",
raidName: "aberrus-the-shadowed-crucible", expectedErrMsg: "raiderio api request timeout"},
}

for _, tc := range testCases {
profile, err := c.GetGuild(&raiderio.GuildQuery{
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
defer cancel()
}

profile, err := c.GetGuild(ctx, &raiderio.GuildQuery{
Region: region.US,
Realm: "illidan",
Name: "warpath",
RaidRankings: true,
})

if err != nil {
t.Errorf("Error getting guild")
if err != nil && err.Error() != tc.expectedErrMsg {
t.Fatalf("error message got: %v, expected: %v",
err.Error(), tc.expectedErrMsg)
}

rank := profile.RaidRankings[tc.raidName]

if rank.Mythic.World != tc.expectedRank {
t.Fatalf("mythic guild ranking for raid: %v, got: %d, expected: %d",
rank.RaidSlug, rank.Mythic.World, tc.expectedRank)
if err == nil {
rank := profile.RaidRankings[tc.raidName]
if rank.Mythic.World != tc.expectedRank {
t.Fatalf("mythic guild ranking for raid: %v, got: %d, expected: %d",
rank.RaidSlug, rank.Mythic.World, tc.expectedRank)
}
}
}
}

func TestGetRaids(t *testing.T) {
c := raiderio.NewClient()
testCases := []struct {
timeout bool
expansion expansion.Expansion
raidName string
raidDifficulty string
expectedRaidName string
expectedErrMsg string
}{
{expansion: expansion.Dragonflight, raidName: "aberrus-the-shadowed-crucible", expectedRaidName: "Aberrus, the Shadowed Crucible"},
{timeout: true, expansion: expansion.Dragonflight, raidName: "aberrus-the-shadowed-crucible", expectedErrMsg: "raiderio api request timeout"},
{expansion: 2, expectedErrMsg: "unsupported expansion"},
}

for _, tc := range testCases {
raids, err := c.GetRaids(tc.expansion)
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
defer cancel()
}

raids, err := c.GetRaids(ctx, tc.expansion)
if err != nil && err.Error() != tc.expectedErrMsg {
t.Fatalf("expected error: %v, got %v", tc.expectedErrMsg, err.Error())
}
Expand All @@ -262,6 +314,7 @@ func TestGetRaids(t *testing.T) {
func TestGetRaidRankings(t *testing.T) {
c := raiderio.NewClient()
testCases := []struct {
timeout bool
slug string
difficulty raiderio.RaidDifficulty
region *region.Region
Expand All @@ -284,18 +337,25 @@ func TestGetRaidRankings(t *testing.T) {
{slug: "aberrus-the-shadowed-crucible", difficulty: raiderio.MythicRaid, region: region.WORLD, limit: -20, expectedErrMsg: "limit must be a positive int"},
{slug: "aberrus-the-shadowed-crucible", difficulty: raiderio.MythicRaid, region: region.US, expectedRank1GuildName: "Accession", limit: 40, page: 2},
{slug: "aberrus-the-shadowed-crucible", difficulty: raiderio.MythicRaid, region: region.US, limit: 40, page: -2, expectedErrMsg: "page must be a positive int"},
{timeout: true, slug: "aberrus-the-shadowed-crucible", difficulty: raiderio.MythicRaid, region: region.US, expectedErrMsg: "raiderio api request timeout"},
}

for _, tc := range testCases {
rankings, err := c.GetRaidRankings(&raiderio.RaidQuery{
ctx := defaultCtx
var cancel context.CancelFunc
if tc.timeout {
ctx, cancel = context.WithTimeout(ctx, time.Millisecond*10)
defer cancel()
}

rankings, err := c.GetRaidRankings(ctx, &raiderio.RaidQuery{
Slug: tc.slug,
Difficulty: raiderio.RaidDifficulty(tc.difficulty),
Region: tc.region,
Realm: tc.realm,
Limit: tc.limit,
Page: tc.page,
})

if err != nil && err.Error() != tc.expectedErrMsg {
t.Fatalf("expected error: %v, got: %v", tc.expectedErrMsg, err.Error())
}
Expand Down
Loading
Loading