2024-03-13 07:23:22 +00:00
package port_test
import (
"cmp"
"fmt"
"net/http"
"net/http/httptest"
"slices"
"strconv"
"strings"
"testing"
"time"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain/domaintest"
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
"github.com/brianvoe/gofakeit/v7"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const endpointListPlayerTribeChanges = "/v2/versions/%s/servers/%s/players/%d/tribe-changes"
func TestListPlayerTribeChanges ( t * testing . T ) {
t . Parallel ( )
handler := newAPIHTTPHandler ( t )
tcs := getAllTribeChanges ( t , handler )
var server serverWithVersion
var player apimodel . PlayerMeta
tcsGroupedByPlayerIDAndServerKey := make ( map [ string ] [ ] tribeChangeWithServer )
for _ , tc := range tcs {
k := strconv . Itoa ( tc . Player . Id ) + tc . Server . Key
tcsGroupedByPlayerIDAndServerKey [ k ] = append ( tcsGroupedByPlayerIDAndServerKey [ k ] , tc )
}
currentMax := - 1
for _ , grouped := range tcsGroupedByPlayerIDAndServerKey {
if l := len ( grouped ) ; l > currentMax && l > 0 {
currentMax = l
player = grouped [ 0 ] . Player
server = grouped [ 0 ] . 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 . ListTribeChangesResponse ] ( 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 . TribeChange ) int {
return cmp . Or (
a . CreatedAt . Compare ( b . CreatedAt ) ,
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 . ListTribeChangesResponse ] ( 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 . ListTribeChangesResponse ] ( 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 . ListTribeChangesResponse ] ( 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=[createdAt:DESC]" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "sort" , "createdAt: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 . ListTribeChangesResponse ] ( 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 . TribeChange ) int {
return cmp . Or (
a . CreatedAt . Compare ( b . CreatedAt ) * - 1 ,
cmp . Compare ( a . Id , b . Id ) ,
)
} ) )
} ,
} ,
{
name : "OK: since" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
var filtered [ ] tribeChangeWithServer
for _ , tc := range tcs {
if tc . Server . Key == server . Key {
filtered = append ( filtered , tc )
}
}
slices . SortFunc ( filtered , func ( a , b tribeChangeWithServer ) int {
return cmp . Or (
a . CreatedAt . Compare ( b . CreatedAt ) ,
cmp . Compare ( a . Id , b . Id ) ,
)
} )
require . GreaterOrEqual ( t , len ( filtered ) , 2 )
q := req . URL . Query ( )
q . Set ( "since" , filtered [ 1 ] . CreatedAt . Format ( time . RFC3339 ) )
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 . ListTribeChangesResponse ] ( t , resp . Body )
assert . Zero ( t , body . Cursor . Next )
assert . NotZero ( t , body . Cursor . Self )
assert . NotZero ( t , body . Data )
since , err := time . Parse ( time . RFC3339 , req . URL . Query ( ) . Get ( "since" ) )
require . NoError ( t , err )
for _ , tc := range body . Data {
assert . True ( t , tc . CreatedAt . After ( since ) || tc . CreatedAt . Equal ( since ) )
}
} ,
} ,
{
name : "OK: before" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
var filtered [ ] tribeChangeWithServer
for _ , tc := range tcs {
if tc . Server . Key == server . Key && tc . Player . Id == player . Id {
filtered = append ( filtered , tc )
}
}
slices . SortFunc ( filtered , func ( a , b tribeChangeWithServer ) int {
return cmp . Or (
a . CreatedAt . Compare ( b . CreatedAt ) ,
cmp . Compare ( a . Id , b . Id ) ,
)
} )
require . GreaterOrEqual ( t , len ( filtered ) , 2 )
q := req . URL . Query ( )
q . Set ( "before" , filtered [ 1 ] . CreatedAt . Format ( time . RFC3339 ) )
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 . ListTribeChangesResponse ] ( t , resp . Body )
assert . Zero ( t , body . Cursor . Next )
assert . NotZero ( t , body . Cursor . Self )
assert . NotZero ( t , body . Data )
before , err := time . Parse ( time . RFC3339 , req . URL . Query ( ) . Get ( "before" ) )
require . NoError ( t , err )
for _ , tc := range body . Data {
assert . True ( t , tc . CreatedAt . Before ( before ) )
}
} ,
} ,
{
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 : fmt . Sprintf ( "ERR: limit > %d" , domain . TribeChangeListMaxLimit ) ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "limit" , strconv . Itoa ( domain . TribeChangeListMaxLimit + 1 ) )
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 : domain . TribeChangeListMaxLimit ,
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" , "createdAt:DESC" )
q . Add ( "sort" , "createdAt:ASC" )
q . Add ( "sort" , "createdAt: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" , "createdAt:" )
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" ] [ 0 ] ,
}
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" , "0" } ,
} ,
} ,
} , body )
} ,
} ,
{
name : "ERR: sort conflict" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Add ( "sort" , "createdAt:DESC" )
q . Add ( "sort" , "createdAt: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 )
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: invalid since" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "since" , gofakeit . LetterN ( 100 ) )
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 )
var domainErr domain . Error
require . ErrorAs ( t , domain . ErrInvalidCursor , & domainErr )
since := req . URL . Query ( ) . Get ( "since" )
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
Code : "invalid-param-format" ,
//nolint:lll
Message : fmt . Sprintf ( "error parsing '%s' as RFC3339 or 2006-01-02 time: parsing time \"%s\" as \"2006-01-02\": cannot parse \"%s\" as \"2006\"" , since , since , since ) ,
Path : [ ] string { "$query" , "since" } ,
} ,
} ,
} , body )
} ,
} ,
{
name : "ERR: invalid before" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "before" , gofakeit . LetterN ( 100 ) )
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 )
var domainErr domain . Error
require . ErrorAs ( t , domain . ErrInvalidCursor , & domainErr )
before := req . URL . Query ( ) . Get ( "before" )
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
Code : "invalid-param-format" ,
//nolint:lll
Message : fmt . Sprintf ( "error parsing '%s' as RFC3339 or 2006-01-02 time: parsing time \"%s\" as \"2006-01-02\": cannot parse \"%s\" as \"2006\"" , before , before , before ) ,
Path : [ ] string { "$query" , "before" } ,
} ,
} ,
} , body )
} ,
} ,
{
name : "ERR: version not found" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
2024-03-15 06:38:38 +00:00
req . URL . Path = fmt . Sprintf (
endpointListPlayerTribeChanges ,
randInvalidVersionCode ( t , handler ) ,
server . Key ,
player . Id ,
)
2024-03-13 07:23:22 +00:00
} ,
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 (
endpointListPlayerTribeChanges ,
server . Version . Code ,
domaintest . RandServerKey ( ) ,
player . Id ,
)
} ,
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: player not found" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
req . URL . Path = fmt . Sprintf (
endpointListPlayerTribeChanges ,
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 . PlayerNotFoundError {
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 ( endpointListPlayerTribeChanges , server . Version . Code , server . Key , player . Id ) ,
nil ,
)
if tt . reqModifier != nil {
tt . reqModifier ( t , req )
}
resp := doCustomRequest ( handler , req )
defer resp . Body . Close ( )
tt . assertResp ( t , req , resp )
} )
}
}
const endpointListTribeTribeChanges = "/v2/versions/%s/servers/%s/tribes/%d/tribe-changes"
func TestListTribeTribeChanges ( t * testing . T ) {
t . Parallel ( )
handler := newAPIHTTPHandler ( t )
tcs := getAllTribeChanges ( t , handler )
var server serverWithVersion
var tribe apimodel . TribeMeta
tcsGroupedByTribeIDAndServerKey := make ( map [ string ] [ ] tribeChangeWithServer )
for _ , tc := range tcs {
var keys [ ] string
if tc . NewTribe != nil {
keys = append ( keys , strconv . Itoa ( tc . NewTribe . Id ) + tc . Server . Key )
}
if tc . Player . Tribe != nil {
keys = append ( keys , strconv . Itoa ( tc . Player . Tribe . Id ) + tc . Server . Key )
}
for _ , k := range keys {
tcsGroupedByTribeIDAndServerKey [ k ] = append ( tcsGroupedByTribeIDAndServerKey [ k ] , tc )
}
}
currentMax := - 1
for k , grouped := range tcsGroupedByTribeIDAndServerKey {
if l := len ( grouped ) ; l > currentMax && l > 0 {
currentMax = l
server = grouped [ 0 ] . Server
id , err := strconv . Atoi ( strings . TrimSuffix ( k , grouped [ 0 ] . Server . Key ) )
require . NoError ( t , err )
if grouped [ 0 ] . NewTribe != nil && grouped [ 0 ] . NewTribe . Id == id {
tribe = * grouped [ 0 ] . NewTribe
} else if grouped [ 0 ] . Player . Tribe != nil && grouped [ 0 ] . Player . Tribe . Id == id {
tribe = * grouped [ 0 ] . Player . Tribe
}
}
}
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 . ListTribeChangesResponse ] ( 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 . TribeChange ) int {
return cmp . Or (
a . CreatedAt . Compare ( b . CreatedAt ) ,
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 . ListTribeChangesResponse ] ( 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 . ListTribeChangesResponse ] ( 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 . ListTribeChangesResponse ] ( 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=[createdAt:DESC]" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "sort" , "createdAt: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 . ListTribeChangesResponse ] ( 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 . TribeChange ) int {
return cmp . Or (
a . CreatedAt . Compare ( b . CreatedAt ) * - 1 ,
cmp . Compare ( a . Id , b . Id ) ,
)
} ) )
} ,
} ,
{
name : "OK: since" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
var filtered [ ] tribeChangeWithServer
for _ , tc := range tcs {
if tc . Server . Key == server . Key {
filtered = append ( filtered , tc )
}
}
slices . SortFunc ( filtered , func ( a , b tribeChangeWithServer ) int {
return cmp . Or (
a . CreatedAt . Compare ( b . CreatedAt ) ,
cmp . Compare ( a . Id , b . Id ) ,
)
} )
require . GreaterOrEqual ( t , len ( filtered ) , 2 )
q := req . URL . Query ( )
q . Set ( "since" , filtered [ 1 ] . CreatedAt . Format ( time . RFC3339 ) )
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 . ListTribeChangesResponse ] ( t , resp . Body )
assert . Zero ( t , body . Cursor . Next )
assert . NotZero ( t , body . Cursor . Self )
assert . NotZero ( t , body . Data )
since , err := time . Parse ( time . RFC3339 , req . URL . Query ( ) . Get ( "since" ) )
require . NoError ( t , err )
for _ , tc := range body . Data {
assert . True ( t , tc . CreatedAt . After ( since ) || tc . CreatedAt . Equal ( since ) )
}
} ,
} ,
{
name : "OK: before" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
var filtered [ ] tribeChangeWithServer
for _ , tc := range tcs {
sameServerKey := tc . Server . Key == server . Key
newTribeIDCheck := tc . NewTribe != nil && tc . NewTribe . Id == tribe . Id
oldTribeIDCheck := tc . Player . Tribe != nil && tc . Player . Tribe . Id == tribe . Id
if sameServerKey && ( newTribeIDCheck || oldTribeIDCheck ) {
filtered = append ( filtered , tc )
}
}
slices . SortFunc ( filtered , func ( a , b tribeChangeWithServer ) int {
return cmp . Or (
a . CreatedAt . Compare ( b . CreatedAt ) ,
cmp . Compare ( a . Id , b . Id ) ,
)
} )
require . GreaterOrEqual ( t , len ( filtered ) , 2 )
q := req . URL . Query ( )
q . Set ( "before" , filtered [ 1 ] . CreatedAt . Format ( time . RFC3339 ) )
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 . ListTribeChangesResponse ] ( t , resp . Body )
assert . Zero ( t , body . Cursor . Next )
assert . NotZero ( t , body . Cursor . Self )
assert . NotZero ( t , body . Data )
before , err := time . Parse ( time . RFC3339 , req . URL . Query ( ) . Get ( "before" ) )
require . NoError ( t , err )
for _ , tc := range body . Data {
assert . True ( t , tc . CreatedAt . Before ( before ) )
}
} ,
} ,
{
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 : fmt . Sprintf ( "ERR: limit > %d" , domain . TribeChangeListMaxLimit ) ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "limit" , strconv . Itoa ( domain . TribeChangeListMaxLimit + 1 ) )
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 : domain . TribeChangeListMaxLimit ,
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" , "createdAt:DESC" )
q . Add ( "sort" , "createdAt:ASC" )
q . Add ( "sort" , "createdAt: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" , "createdAt:" )
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" ] [ 0 ] ,
}
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" , "0" } ,
} ,
} ,
} , body )
} ,
} ,
{
name : "ERR: sort conflict" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Add ( "sort" , "createdAt:DESC" )
q . Add ( "sort" , "createdAt: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 )
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: invalid since" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "since" , gofakeit . LetterN ( 100 ) )
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 )
var domainErr domain . Error
require . ErrorAs ( t , domain . ErrInvalidCursor , & domainErr )
since := req . URL . Query ( ) . Get ( "since" )
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
Code : "invalid-param-format" ,
//nolint:lll
Message : fmt . Sprintf ( "error parsing '%s' as RFC3339 or 2006-01-02 time: parsing time \"%s\" as \"2006-01-02\": cannot parse \"%s\" as \"2006\"" , since , since , since ) ,
Path : [ ] string { "$query" , "since" } ,
} ,
} ,
} , body )
} ,
} ,
{
name : "ERR: invalid before" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "before" , gofakeit . LetterN ( 100 ) )
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 )
var domainErr domain . Error
require . ErrorAs ( t , domain . ErrInvalidCursor , & domainErr )
before := req . URL . Query ( ) . Get ( "before" )
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
Code : "invalid-param-format" ,
//nolint:lll
Message : fmt . Sprintf ( "error parsing '%s' as RFC3339 or 2006-01-02 time: parsing time \"%s\" as \"2006-01-02\": cannot parse \"%s\" as \"2006\"" , before , before , before ) ,
Path : [ ] string { "$query" , "before" } ,
} ,
} ,
} , body )
} ,
} ,
{
name : "ERR: version not found" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
2024-03-15 06:38:38 +00:00
req . URL . Path = fmt . Sprintf ( endpointListTribeTribeChanges , randInvalidVersionCode ( t , handler ) , server . Key , tribe . Id )
2024-03-13 07:23:22 +00:00
} ,
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 (
endpointListTribeTribeChanges ,
server . Version . Code ,
domaintest . RandServerKey ( ) ,
tribe . Id ,
)
} ,
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 (
endpointListTribeTribeChanges ,
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 ( endpointListTribeTribeChanges , server . Version . Code , server . Key , tribe . Id ) ,
nil ,
)
if tt . reqModifier != nil {
tt . reqModifier ( t , req )
}
resp := doCustomRequest ( handler , req )
defer resp . Body . Close ( )
tt . assertResp ( t , req , resp )
} )
}
}
type tribeChangeWithServer struct {
apimodel . TribeChange
Server serverWithVersion
}
func getAllTribeChanges ( tb testing . TB , h http . Handler ) [ ] tribeChangeWithServer {
tb . Helper ( )
players := getAllPlayers ( tb , h )
var tcs [ ] tribeChangeWithServer
for _ , p := range players {
resp := doRequest ( h , http . MethodGet , fmt . Sprintf (
endpointListPlayerTribeChanges ,
p . Server . Version . Code ,
p . Server . Key ,
p . Id ,
) , nil )
require . Equal ( tb , http . StatusOK , resp . StatusCode )
for _ , tc := range decodeJSON [ apimodel . ListTribeChangesResponse ] ( tb , resp . Body ) . Data {
tcs = append ( tcs , tribeChangeWithServer {
TribeChange : tc ,
Server : p . Server ,
} )
}
_ = resp . Body . Close ( )
}
require . NotZero ( tb , tcs )
return tcs
}