feat: new API endpoint - /v2/versions/{versionCode}/servers/{serverKey}/tribes/{tribeId}/members (#15)
Reviewed-on: twhelp/corev3#15
This commit is contained in:
parent
82d313d2ae
commit
e3bb2eb5c4
|
@ -205,6 +205,27 @@ paths:
|
|||
$ref: "#/components/responses/GetPlayerResponse"
|
||||
default:
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
/v2/versions/{versionCode}/servers/{serverKey}/tribes/{tribeId}/members:
|
||||
get:
|
||||
operationId: listTribeMembers
|
||||
tags:
|
||||
- versions
|
||||
- servers
|
||||
- tribes
|
||||
- players
|
||||
description: List tribe members
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/VersionCodePathParam"
|
||||
- $ref: "#/components/parameters/ServerKeyPathParam"
|
||||
- $ref: "#/components/parameters/TribeIdPathParam"
|
||||
- $ref: "#/components/parameters/CursorQueryParam"
|
||||
- $ref: "#/components/parameters/LimitQueryParam"
|
||||
- $ref: "#/components/parameters/PlayerSortQueryParam"
|
||||
responses:
|
||||
200:
|
||||
$ref: "#/components/responses/ListPlayersResponse"
|
||||
default:
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
|
|
|
@ -172,6 +172,10 @@ func (a listPlayersParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
|||
q = q.Where("player.name IN (?)", bun.In(names))
|
||||
}
|
||||
|
||||
if tribeIDs := a.params.TribeIDs(); len(tribeIDs) > 0 {
|
||||
q = q.Where("player.tribe_id IN (?)", bun.In(tribeIDs))
|
||||
}
|
||||
|
||||
if deleted := a.params.Deleted(); deleted.Valid {
|
||||
if deleted.V {
|
||||
q = q.Where("player.deleted_at IS NOT NULL")
|
||||
|
|
|
@ -432,6 +432,44 @@ func testPlayerRepository(t *testing.T, newRepos func(t *testing.T) repositories
|
|||
require.NoError(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: tribeIDs serverKeys",
|
||||
params: func(t *testing.T) domain.ListPlayersParams {
|
||||
t.Helper()
|
||||
|
||||
params := domain.NewListPlayersParams()
|
||||
|
||||
res, err := repos.player.List(ctx, params)
|
||||
require.NoError(t, err)
|
||||
idx := slices.IndexFunc(res.Players(), func(player domain.Player) bool {
|
||||
return player.TribeID() > 0
|
||||
})
|
||||
require.GreaterOrEqual(t, idx, 0)
|
||||
randPlayer := res.Players()[idx]
|
||||
|
||||
require.NoError(t, params.SetTribeIDs([]int{randPlayer.TribeID()}))
|
||||
require.NoError(t, params.SetServerKeys([]string{randPlayer.ServerKey()}))
|
||||
|
||||
return params
|
||||
},
|
||||
assertResult: func(t *testing.T, params domain.ListPlayersParams, res domain.ListPlayersResult) {
|
||||
t.Helper()
|
||||
|
||||
tribeIDs := params.TribeIDs()
|
||||
serverKeys := params.ServerKeys()
|
||||
|
||||
players := res.Players()
|
||||
assert.NotZero(t, players)
|
||||
for _, p := range players {
|
||||
assert.True(t, slices.Contains(tribeIDs, p.TribeID()))
|
||||
assert.True(t, slices.Contains(serverKeys, p.ServerKey()))
|
||||
}
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: deleted=true",
|
||||
params: func(t *testing.T) domain.ListPlayersParams {
|
||||
|
|
|
@ -699,6 +699,7 @@ type ListPlayersParams struct {
|
|||
ids []int
|
||||
serverKeys []string
|
||||
names []string
|
||||
tribeIDs []int
|
||||
deleted NullBool
|
||||
sort []PlayerSort
|
||||
cursor PlayerCursor
|
||||
|
@ -796,6 +797,27 @@ func (params *ListPlayersParams) SetNames(names []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (params *ListPlayersParams) TribeIDs() []int {
|
||||
return params.tribeIDs
|
||||
}
|
||||
|
||||
func (params *ListPlayersParams) SetTribeIDs(tribeIDs []int) error {
|
||||
for i, id := range tribeIDs {
|
||||
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
|
||||
return SliceElementValidationError{
|
||||
Model: listPlayersParamsModelName,
|
||||
Field: "tribeIDs",
|
||||
Index: i,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params.tribeIDs = tribeIDs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (params *ListPlayersParams) Deleted() NullBool {
|
||||
return params.deleted
|
||||
}
|
||||
|
@ -1008,7 +1030,6 @@ func NewListPlayersWithRelationsResult(
|
|||
}
|
||||
|
||||
if !next.IsZero() {
|
||||
fmt.Println(next.IsZero())
|
||||
player := next.Player()
|
||||
od := player.OD()
|
||||
res.next, err = NewPlayerCursor(
|
||||
|
|
|
@ -769,6 +769,66 @@ func TestListPlayersParams_SetNames(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestListPlayersParams_SetTribeIDs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
tribeIDs []int
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "OK",
|
||||
args: args{
|
||||
tribeIDs: []int{
|
||||
domaintest.RandID(),
|
||||
domaintest.RandID(),
|
||||
domaintest.RandID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: value < 1",
|
||||
args: args{
|
||||
tribeIDs: []int{
|
||||
domaintest.RandID(),
|
||||
domaintest.RandID(),
|
||||
domaintest.RandID(),
|
||||
0,
|
||||
domaintest.RandID(),
|
||||
},
|
||||
},
|
||||
expectedErr: domain.SliceElementValidationError{
|
||||
Model: "ListPlayersParams",
|
||||
Field: "tribeIDs",
|
||||
Index: 3,
|
||||
Err: domain.MinGreaterEqualError{
|
||||
Min: 1,
|
||||
Current: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := domain.NewListPlayersParams()
|
||||
|
||||
require.ErrorIs(t, params.SetTribeIDs(tt.args.tribeIDs), tt.expectedErr)
|
||||
if tt.expectedErr != nil {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, tt.args.tribeIDs, params.TribeIDs())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPlayersParams_SetSort(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -78,6 +78,62 @@ func (h *apiHTTPHandler) ListPlayers(
|
|||
renderJSON(w, r, http.StatusOK, apimodel.NewListPlayersResponse(res))
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (h *apiHTTPHandler) ListTribeMembers(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
_ apimodel.VersionCodePathParam,
|
||||
serverKey apimodel.ServerKeyPathParam,
|
||||
tribeID apimodel.TribeIdPathParam,
|
||||
params apimodel.ListTribeMembersParams,
|
||||
) {
|
||||
domainParams := domain.NewListPlayersParams()
|
||||
|
||||
if err := domainParams.SetSort([]domain.PlayerSort{domain.PlayerSortIDASC}); err != nil {
|
||||
h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if params.Sort != nil {
|
||||
if err := domainParams.PrependSortString(*params.Sort); err != nil {
|
||||
h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := domainParams.SetServerKeys([]string{serverKey}); err != nil {
|
||||
h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := domainParams.SetTribeIDs([]int{tribeID}); err != nil {
|
||||
h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
if params.Limit != nil {
|
||||
if err := domainParams.SetLimit(*params.Limit); err != nil {
|
||||
h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if params.Cursor != nil {
|
||||
if err := domainParams.SetEncodedCursor(*params.Cursor); err != nil {
|
||||
h.errorRenderer.withErrorPathFormatter(formatListPlayersErrorPath).render(w, r, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
res, err := h.playerSvc.ListWithRelations(r.Context(), domainParams)
|
||||
if err != nil {
|
||||
h.errorRenderer.render(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
renderJSON(w, r, http.StatusOK, apimodel.NewListPlayersResponse(res))
|
||||
}
|
||||
|
||||
func (h *apiHTTPHandler) GetPlayer(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
|
|
|
@ -177,7 +177,7 @@ func TestListPlayers(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "OK: tag",
|
||||
name: "OK: name",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
|
||||
|
@ -790,6 +790,559 @@ func TestListPlayers(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
const endpointListTribeMembers = "/v2/versions/%s/servers/%s/tribes/%d/members"
|
||||
|
||||
func TestListTribeMembers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
handler := newAPIHTTPHandler(t)
|
||||
players := getAllPlayers(t, handler)
|
||||
var server serverWithVersion
|
||||
var tribeID int
|
||||
|
||||
for _, p := range players {
|
||||
if p.Tribe != nil && p.Tribe.Id > 0 {
|
||||
server = p.Server
|
||||
tribeID = p.Tribe.Id
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
require.NotZero(t, server)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
reqModifier func(t *testing.T, req *http.Request)
|
||||
assertResp func(t *testing.T, req *http.Request, resp *http.Response)
|
||||
}{
|
||||
{
|
||||
name: "OK: without params",
|
||||
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ListPlayersResponse](t, resp.Body)
|
||||
assert.Zero(t, body.Cursor.Next)
|
||||
assert.NotZero(t, body.Cursor.Self)
|
||||
assert.NotZero(t, body.Data)
|
||||
assert.False(t, slices.ContainsFunc(body.Data, func(player apimodel.Player) bool {
|
||||
return player.Tribe == nil || player.Tribe.Id != tribeID
|
||||
}))
|
||||
assert.True(t, slices.IsSortedFunc(body.Data, func(a, b apimodel.Player) int {
|
||||
return cmp.Compare(a.Id, b.Id)
|
||||
}))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: limit=1",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Set("limit", "1")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ListPlayersResponse](t, resp.Body)
|
||||
assert.NotZero(t, body.Cursor.Next)
|
||||
assert.NotZero(t, body.Cursor.Self)
|
||||
assert.NotZero(t, body.Data)
|
||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, body.Data, limit)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: limit=1 cursor",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
|
||||
q := req.URL.Query()
|
||||
q.Set("limit", "1")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
resp := doCustomRequest(handler, req.Clone(req.Context()))
|
||||
defer resp.Body.Close()
|
||||
body := decodeJSON[apimodel.ListPlayersResponse](t, resp.Body)
|
||||
require.NotEmpty(t, body.Cursor.Next)
|
||||
|
||||
q.Set("cursor", body.Cursor.Next)
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ListPlayersResponse](t, resp.Body)
|
||||
assert.Equal(t, req.URL.Query().Get("cursor"), body.Cursor.Self)
|
||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, body.Data, limit)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: sort=[odScoreAtt:DESC]",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Set("sort", "odScoreAtt:DESC")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ListPlayersResponse](t, resp.Body)
|
||||
assert.Zero(t, body.Cursor.Next)
|
||||
assert.NotZero(t, body.Cursor.Self)
|
||||
assert.NotZero(t, body.Data)
|
||||
assert.True(t, slices.IsSortedFunc(body.Data, func(a, b apimodel.Player) int {
|
||||
return cmp.Or(
|
||||
cmp.Compare(a.OpponentsDefeated.ScoreAtt, b.OpponentsDefeated.ScoreAtt)*-1,
|
||||
cmp.Compare(a.Id, b.Id),
|
||||
)
|
||||
}))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: limit is not a string",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Set("limit", "asd")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: "invalid-param-format",
|
||||
Message: fmt.Sprintf(
|
||||
"error binding string parameter: strconv.ParseInt: parsing \"%s\": invalid syntax",
|
||||
req.URL.Query().Get("limit"),
|
||||
),
|
||||
Path: []string{"$query", "limit"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: limit < 1",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Set("limit", "0")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||
require.NoError(t, err)
|
||||
domainErr := domain.MinGreaterEqualError{
|
||||
Min: 1,
|
||||
Current: limit,
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"current": float64(domainErr.Current),
|
||||
"min": float64(domainErr.Min),
|
||||
},
|
||||
Path: []string{"$query", "limit"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: limit > 200",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Set("limit", "201")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
limit, err := strconv.Atoi(req.URL.Query().Get("limit"))
|
||||
require.NoError(t, err)
|
||||
domainErr := domain.MaxLessEqualError{
|
||||
Max: 200,
|
||||
Current: limit,
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"current": float64(domainErr.Current),
|
||||
"max": float64(domainErr.Max),
|
||||
},
|
||||
Path: []string{"$query", "limit"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: len(cursor) < 1",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Set("cursor", "")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
domainErr := domain.LenOutOfRangeError{
|
||||
Min: 1,
|
||||
Max: 1000,
|
||||
Current: len(req.URL.Query().Get("cursor")),
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"current": float64(domainErr.Current),
|
||||
"max": float64(domainErr.Max),
|
||||
"min": float64(domainErr.Min),
|
||||
},
|
||||
Path: []string{"$query", "cursor"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: len(cursor) > 1000",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Set("cursor", gofakeit.LetterN(1001))
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
domainErr := domain.LenOutOfRangeError{
|
||||
Min: 1,
|
||||
Max: 1000,
|
||||
Current: len(req.URL.Query().Get("cursor")),
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"current": float64(domainErr.Current),
|
||||
"max": float64(domainErr.Max),
|
||||
"min": float64(domainErr.Min),
|
||||
},
|
||||
Path: []string{"$query", "cursor"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: invalid cursor",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Set("cursor", gofakeit.LetterN(100))
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, _ *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
var domainErr domain.Error
|
||||
require.ErrorAs(t, domain.ErrInvalidCursor, &domainErr)
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Path: []string{"$query", "cursor"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: len(sort) > 2",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Add("sort", "odScoreAtt:DESC")
|
||||
q.Add("sort", "odScoreAtt:ASC")
|
||||
q.Add("sort", "points:ASC")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
domainErr := domain.LenOutOfRangeError{
|
||||
Min: 1,
|
||||
Max: 2,
|
||||
Current: len(req.URL.Query()["sort"]),
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"current": float64(domainErr.Current),
|
||||
"max": float64(domainErr.Max),
|
||||
"min": float64(domainErr.Min),
|
||||
},
|
||||
Path: []string{"$query", "sort"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: invalid sort",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Add("sort", "odScoreAtt:ASC")
|
||||
q.Add("sort", "test:DESC")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
domainErr := domain.UnsupportedSortStringError{
|
||||
Sort: req.URL.Query()["sort"][1],
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"sort": domainErr.Sort,
|
||||
},
|
||||
Path: []string{"$query", "sort", "1"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: sort conflict",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
q := req.URL.Query()
|
||||
q.Add("sort", "odScoreAtt:ASC")
|
||||
q.Add("sort", "odScoreAtt:DESC")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
q := req.URL.Query()
|
||||
domainErr := domain.SortConflictError{
|
||||
Sort: [2]string{q["sort"][0], q["sort"][1]},
|
||||
}
|
||||
paramSort := make([]any, len(domainErr.Sort))
|
||||
for i, s := range domainErr.Sort {
|
||||
paramSort[i] = s
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"sort": paramSort,
|
||||
},
|
||||
Path: []string{"$query", "sort"},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: version not found",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
req.URL.Path = fmt.Sprintf(endpointListTribeMembers, domaintest.RandVersionCode(), server.Key, tribeID)
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
pathSegments := strings.Split(req.URL.Path, "/")
|
||||
require.Len(t, pathSegments, 9)
|
||||
domainErr := domain.VersionNotFoundError{
|
||||
VersionCode: pathSegments[3],
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"code": domainErr.VersionCode,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: server not found",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
req.URL.Path = fmt.Sprintf(endpointListTribeMembers, server.Version.Code, domaintest.RandServerKey(), tribeID)
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
pathSegments := strings.Split(req.URL.Path, "/")
|
||||
require.Len(t, pathSegments, 9)
|
||||
domainErr := domain.ServerNotFoundError{
|
||||
Key: pathSegments[5],
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"key": domainErr.Key,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ERR: tribe not found",
|
||||
reqModifier: func(t *testing.T, req *http.Request) {
|
||||
t.Helper()
|
||||
req.URL.Path = fmt.Sprintf(endpointListTribeMembers, server.Version.Code, server.Key, domaintest.RandID())
|
||||
},
|
||||
assertResp: func(t *testing.T, req *http.Request, resp *http.Response) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
|
||||
|
||||
// body
|
||||
body := decodeJSON[apimodel.ErrorResponse](t, resp.Body)
|
||||
pathSegments := strings.Split(req.URL.Path, "/")
|
||||
require.Len(t, pathSegments, 9)
|
||||
id, err := strconv.Atoi(pathSegments[7])
|
||||
require.NoError(t, err)
|
||||
domainErr := domain.TribeNotFoundError{
|
||||
ID: id,
|
||||
ServerKey: pathSegments[5],
|
||||
}
|
||||
assert.Equal(t, apimodel.ErrorResponse{
|
||||
Errors: []apimodel.Error{
|
||||
{
|
||||
Code: domainErr.Code(),
|
||||
Message: domainErr.Error(),
|
||||
Params: map[string]any{
|
||||
"id": float64(domainErr.ID),
|
||||
"serverKey": domainErr.ServerKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, body)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
req := httptest.NewRequest(
|
||||
http.MethodGet,
|
||||
fmt.Sprintf(endpointListTribeMembers, server.Version.Code, server.Key, tribeID),
|
||||
nil,
|
||||
)
|
||||
if tt.reqModifier != nil {
|
||||
tt.reqModifier(t, req)
|
||||
}
|
||||
|
||||
resp := doCustomRequest(handler, req)
|
||||
defer resp.Body.Close()
|
||||
tt.assertResp(t, req, resp)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const endpointGetPlayer = "/v2/versions/%s/servers/%s/players/%d"
|
||||
|
||||
func TestGetPlayer(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user