2024-03-11 06:41:32 +00:00
package port_test
import (
"cmp"
"fmt"
"net/http"
"net/http/httptest"
"slices"
"strconv"
"strings"
"testing"
2024-03-11 09:05:29 +00:00
"time"
2024-03-11 06:41:32 +00:00
"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 endpointListEnnoblements = "/v2/versions/%s/servers/%s/ennoblements"
func TestListEnnoblements ( t * testing . T ) {
t . Parallel ( )
handler := newAPIHTTPHandler ( t )
ennoblements := getAllEnnoblements ( t , handler )
server := ennoblements [ 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 . ListEnnoblementsResponse ] ( 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 . Ennoblement ) int {
2024-03-11 07:37:04 +00:00
return cmp . Or (
a . CreatedAt . Compare ( b . CreatedAt ) ,
cmp . Compare ( a . Id , b . Id ) ,
)
2024-03-11 06:41:32 +00:00
} ) )
} ,
} ,
{
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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 )
} ,
} ,
2024-03-11 09:05:29 +00:00
{
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
2024-03-11 12:08:51 +00:00
body := decodeJSON [ apimodel . ListEnnoblementsResponse ] ( t , resp . Body )
2024-03-11 09:05:29 +00:00
assert . Zero ( t , body . Cursor . Next )
assert . NotZero ( t , body . Cursor . Self )
assert . NotZero ( t , body . Data )
2024-03-11 12:08:51 +00:00
assert . True ( t , slices . IsSortedFunc ( body . Data , func ( a , b apimodel . Ennoblement ) int {
2024-03-11 09:05:29 +00:00
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 [ ] ennoblementWithServer
for _ , e := range ennoblements {
if e . Server . Key == server . Key {
filtered = append ( filtered , e )
}
}
slices . SortFunc ( filtered , func ( a , b ennoblementWithServer ) 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 . ListEnnoblementsResponse ] ( 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 _ , e := range body . Data {
assert . True ( t , e . CreatedAt . After ( since ) || e . CreatedAt . Equal ( since ) )
}
} ,
} ,
{
2024-03-13 07:23:22 +00:00
name : "OK: before" ,
2024-03-11 09:05:29 +00:00
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
var filtered [ ] ennoblementWithServer
for _ , e := range ennoblements {
if e . Server . Key == server . Key {
filtered = append ( filtered , e )
}
}
slices . SortFunc ( filtered , func ( a , b ennoblementWithServer ) 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 . ListEnnoblementsResponse ] ( 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 _ , e := range body . Data {
assert . True ( t , e . CreatedAt . Before ( before ) )
}
} ,
} ,
2024-03-11 06:41:32 +00:00
{
2024-03-27 07:03:54 +00:00
name : "ERR: limit is not an integer" ,
2024-03-11 06:41:32 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 06:41:32 +00:00
Message : domainErr . Error ( ) ,
Params : map [ string ] any {
"current" : float64 ( domainErr . Current ) ,
"min" : float64 ( domainErr . Min ) ,
} ,
Path : [ ] string { "$query" , "limit" } ,
} ,
} ,
} , body )
} ,
} ,
{
2024-03-11 07:16:29 +00:00
name : fmt . Sprintf ( "ERR: limit > %d" , domain . EnnoblementListMaxLimit ) ,
2024-03-11 06:41:32 +00:00
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
2024-03-11 07:16:29 +00:00
q . Set ( "limit" , strconv . Itoa ( domain . EnnoblementListMaxLimit + 1 ) )
2024-03-11 06:41:32 +00:00
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 {
2024-03-11 07:16:29 +00:00
Max : domain . EnnoblementListMaxLimit ,
2024-03-11 06:41:32 +00:00
Current : limit ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 06:41:32 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 06:41:32 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 06:41:32 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 06:41:32 +00:00
Message : domainErr . Error ( ) ,
Path : [ ] string { "$query" , "cursor" } ,
} ,
} ,
} , body )
} ,
} ,
2024-03-11 09:05:29 +00:00
{
2024-03-25 07:29:37 +00:00
name : "ERR: len(sort) > 1" ,
2024-03-11 09:05:29 +00:00
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 )
domainErr := domain . LenOutOfRangeError {
2024-03-25 07:29:37 +00:00
Min : 0 ,
Max : 1 ,
2024-03-11 09:05:29 +00:00
Current : len ( req . URL . Query ( ) [ "sort" ] ) ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 09:05:29 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 09:05:29 +00:00
Message : domainErr . Error ( ) ,
Params : map [ string ] any {
"sort" : domainErr . Sort ,
} ,
Path : [ ] string { "$query" , "sort" , "0" } ,
} ,
} ,
} , 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 )
} ,
} ,
2024-03-11 06:41:32 +00:00
{
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 ( endpointListEnnoblements , randInvalidVersionCode ( t , handler ) , server . Key )
2024-03-11 06:41:32 +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 , 7 )
domainErr := domain . VersionNotFoundError {
VersionCode : pathSegments [ 3 ] ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 06:41:32 +00:00
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 ( endpointListEnnoblements , server . Version . Code , domaintest . RandServerKey ( ) )
} ,
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 , 7 )
domainErr := domain . ServerNotFoundError {
Key : pathSegments [ 5 ] ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 06:41:32 +00:00
Message : domainErr . Error ( ) ,
Params : map [ string ] any {
"key" : domainErr . Key ,
} ,
} ,
} ,
} , body )
} ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
t . Parallel ( )
req := httptest . NewRequest (
http . MethodGet ,
fmt . Sprintf ( endpointListEnnoblements , server . Version . Code , server . Key ) ,
nil ,
)
if tt . reqModifier != nil {
tt . reqModifier ( t , req )
}
resp := doCustomRequest ( handler , req )
defer resp . Body . Close ( )
tt . assertResp ( t , req , resp )
} )
}
}
2024-03-11 12:08:51 +00:00
const endpointListPlayerEnnoblements = "/v2/versions/%s/servers/%s/players/%d/ennoblements"
func TestListPlayerEnnoblements ( t * testing . T ) {
t . Parallel ( )
handler := newAPIHTTPHandler ( t )
ennoblements := getAllEnnoblements ( t , handler )
server := ennoblements [ 0 ] . Server
player := ennoblements [ 0 ] . NewOwner
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 . ListEnnoblementsResponse ] ( 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 . Ennoblement ) 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . Ennoblement ) 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 [ ] ennoblementWithServer
for _ , e := range ennoblements {
if e . Server . Key == server . Key {
filtered = append ( filtered , e )
}
}
slices . SortFunc ( filtered , func ( a , b ennoblementWithServer ) 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 . ListEnnoblementsResponse ] ( 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 _ , e := range body . Data {
assert . True ( t , e . CreatedAt . After ( since ) || e . CreatedAt . Equal ( since ) )
}
} ,
} ,
{
2024-03-13 07:23:22 +00:00
name : "OK: before" ,
2024-03-11 12:08:51 +00:00
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
var filtered [ ] ennoblementWithServer
for _ , e := range ennoblements {
if e . Server . Key == server . Key {
filtered = append ( filtered , e )
}
}
slices . SortFunc ( filtered , func ( a , b ennoblementWithServer ) 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 . ListEnnoblementsResponse ] ( 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 _ , e := range body . Data {
assert . True ( t , e . CreatedAt . Before ( before ) )
}
} ,
} ,
{
2024-03-27 07:03:54 +00:00
name : "ERR: limit is not an integer" ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 . EnnoblementListMaxLimit ) ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "limit" , strconv . Itoa ( domain . EnnoblementListMaxLimit + 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 . EnnoblementListMaxLimit ,
Current : limit ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
Message : domainErr . Error ( ) ,
Path : [ ] string { "$query" , "cursor" } ,
} ,
} ,
} , body )
} ,
} ,
{
2024-03-25 07:29:37 +00:00
name : "ERR: len(sort) > 1" ,
2024-03-11 12:08:51 +00:00
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 )
domainErr := domain . LenOutOfRangeError {
2024-03-25 07:29:37 +00:00
Min : 0 ,
Max : 1 ,
2024-03-11 12:08:51 +00:00
Current : len ( req . URL . Query ( ) [ "sort" ] ) ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
Message : domainErr . Error ( ) ,
Params : map [ string ] any {
"sort" : domainErr . Sort ,
} ,
Path : [ ] string { "$query" , "sort" , "0" } ,
} ,
} ,
} , 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 (
endpointListPlayerEnnoblements ,
randInvalidVersionCode ( t , handler ) ,
server . Key ,
player . Id ,
)
2024-03-11 12:08:51 +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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 (
endpointListPlayerEnnoblements ,
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 (
endpointListPlayerEnnoblements ,
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 ( endpointListPlayerEnnoblements , 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 endpointListTribeEnnoblements = "/v2/versions/%s/servers/%s/tribes/%d/ennoblements"
func TestListTribeEnnoblements ( t * testing . T ) {
t . Parallel ( )
handler := newAPIHTTPHandler ( t )
ennoblements := getAllEnnoblements ( t , handler )
var server serverWithVersion
var tribe apimodel . TribeMeta
for _ , e := range ennoblements {
if e . NewOwner . Tribe != nil {
server = e . Server
tribe = * e . NewOwner . Tribe
break
}
}
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 . ListEnnoblementsResponse ] ( 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 . Ennoblement ) 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . Ennoblement ) 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 [ ] ennoblementWithServer
for _ , e := range ennoblements {
if e . Server . Key == server . Key {
filtered = append ( filtered , e )
}
}
slices . SortFunc ( filtered , func ( a , b ennoblementWithServer ) 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 . ListEnnoblementsResponse ] ( 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 _ , e := range body . Data {
assert . True ( t , e . CreatedAt . After ( since ) || e . CreatedAt . Equal ( since ) )
}
} ,
} ,
{
2024-03-13 07:23:22 +00:00
name : "OK: before" ,
2024-03-11 12:08:51 +00:00
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
var filtered [ ] ennoblementWithServer
for _ , e := range ennoblements {
if e . Server . Key == server . Key {
filtered = append ( filtered , e )
}
}
slices . SortFunc ( filtered , func ( a , b ennoblementWithServer ) 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 . ListEnnoblementsResponse ] ( 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 _ , e := range body . Data {
assert . True ( t , e . CreatedAt . Before ( before ) )
}
} ,
} ,
{
2024-03-27 07:03:54 +00:00
name : "ERR: limit is not an integer" ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 . EnnoblementListMaxLimit ) ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "limit" , strconv . Itoa ( domain . EnnoblementListMaxLimit + 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 . EnnoblementListMaxLimit ,
Current : limit ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
Message : domainErr . Error ( ) ,
Path : [ ] string { "$query" , "cursor" } ,
} ,
} ,
} , body )
} ,
} ,
{
2024-03-25 07:29:37 +00:00
name : "ERR: len(sort) > 1" ,
2024-03-11 12:08:51 +00:00
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 )
domainErr := domain . LenOutOfRangeError {
2024-03-25 07:29:37 +00:00
Min : 0 ,
Max : 1 ,
2024-03-11 12:08:51 +00:00
Current : len ( req . URL . Query ( ) [ "sort" ] ) ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
Message : domainErr . Error ( ) ,
Params : map [ string ] any {
"sort" : domainErr . Sort ,
} ,
Path : [ ] string { "$query" , "sort" , "0" } ,
} ,
} ,
} , 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 ( endpointListTribeEnnoblements , randInvalidVersionCode ( t , handler ) , server . Key , tribe . Id )
2024-03-11 12:08:51 +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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 (
endpointListTribeEnnoblements ,
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 (
endpointListTribeEnnoblements ,
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 ( endpointListTribeEnnoblements , 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 )
} )
}
}
const endpointListVillageEnnoblements = "/v2/versions/%s/servers/%s/villages/%d/ennoblements"
func TestListVillageEnnoblements ( t * testing . T ) {
t . Parallel ( )
handler := newAPIHTTPHandler ( t )
ennoblements := getAllEnnoblements ( t , handler )
server := ennoblements [ 0 ] . Server
village := ennoblements [ 0 ] . Village
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 . ListEnnoblementsResponse ] ( 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 . Ennoblement ) 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . ListEnnoblementsResponse ] ( 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 . Ennoblement ) 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 [ ] ennoblementWithServer
for _ , e := range ennoblements {
if e . Server . Key == server . Key {
filtered = append ( filtered , e )
}
}
slices . SortFunc ( filtered , func ( a , b ennoblementWithServer ) 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 . ListEnnoblementsResponse ] ( 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 _ , e := range body . Data {
assert . True ( t , e . CreatedAt . After ( since ) || e . CreatedAt . Equal ( since ) )
}
} ,
} ,
{
2024-03-13 07:23:22 +00:00
name : "OK: before" ,
2024-03-11 12:08:51 +00:00
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
var filtered [ ] ennoblementWithServer
for _ , e := range ennoblements {
if e . Server . Key == server . Key {
filtered = append ( filtered , e )
}
}
slices . SortFunc ( filtered , func ( a , b ennoblementWithServer ) 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 . ListEnnoblementsResponse ] ( 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 _ , e := range body . Data {
assert . True ( t , e . CreatedAt . Before ( before ) )
}
} ,
} ,
{
2024-03-27 07:03:54 +00:00
name : "ERR: limit is not an integer" ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 . EnnoblementListMaxLimit ) ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
q := req . URL . Query ( )
q . Set ( "limit" , strconv . Itoa ( domain . EnnoblementListMaxLimit + 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 . EnnoblementListMaxLimit ,
Current : limit ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
Message : domainErr . Error ( ) ,
Path : [ ] string { "$query" , "cursor" } ,
} ,
} ,
} , body )
} ,
} ,
{
2024-03-25 07:29:37 +00:00
name : "ERR: len(sort) > 1" ,
2024-03-11 12:08:51 +00:00
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 )
domainErr := domain . LenOutOfRangeError {
2024-03-25 07:29:37 +00:00
Min : 0 ,
Max : 1 ,
2024-03-11 12:08:51 +00:00
Current : len ( req . URL . Query ( ) [ "sort" ] ) ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
Message : domainErr . Error ( ) ,
Params : map [ string ] any {
"sort" : domainErr . Sort ,
} ,
Path : [ ] string { "$query" , "sort" , "0" } ,
} ,
} ,
} , 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 (
endpointListVillageEnnoblements ,
randInvalidVersionCode ( t , handler ) ,
server . Key ,
village . Id ,
)
2024-03-11 12:08:51 +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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 (
endpointListVillageEnnoblements ,
server . Version . Code ,
domaintest . RandServerKey ( ) ,
village . 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 {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
Message : domainErr . Error ( ) ,
Params : map [ string ] any {
"key" : domainErr . Key ,
} ,
} ,
} ,
} , body )
} ,
} ,
{
name : "ERR: village not found" ,
reqModifier : func ( t * testing . T , req * http . Request ) {
t . Helper ( )
req . URL . Path = fmt . Sprintf (
endpointListVillageEnnoblements ,
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 . VillageNotFoundError {
ID : id ,
ServerKey : pathSegments [ 5 ] ,
}
assert . Equal ( t , apimodel . ErrorResponse {
Errors : [ ] apimodel . Error {
{
2024-03-18 07:01:47 +00:00
Code : apimodel . ErrorCode ( domainErr . Code ( ) ) ,
2024-03-11 12:08:51 +00:00
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 ( endpointListVillageEnnoblements , server . Version . Code , server . Key , village . Id ) ,
nil ,
)
if tt . reqModifier != nil {
tt . reqModifier ( t , req )
}
resp := doCustomRequest ( handler , req )
defer resp . Body . Close ( )
tt . assertResp ( t , req , resp )
} )
}
}
2024-03-11 06:41:32 +00:00
type ennoblementWithServer struct {
apimodel . Ennoblement
Server serverWithVersion
}
func getAllEnnoblements ( tb testing . TB , h http . Handler ) [ ] ennoblementWithServer {
tb . Helper ( )
servers := getAllServers ( tb , h )
var ennoblements [ ] ennoblementWithServer
for _ , s := range servers {
resp := doRequest ( h , http . MethodGet , fmt . Sprintf ( endpointListEnnoblements , s . Version . Code , s . Key ) , nil )
require . Equal ( tb , http . StatusOK , resp . StatusCode )
for _ , e := range decodeJSON [ apimodel . ListEnnoblementsResponse ] ( tb , resp . Body ) . Data {
ennoblements = append ( ennoblements , ennoblementWithServer {
Ennoblement : e ,
Server : s ,
} )
}
_ = resp . Body . Close ( )
}
require . NotZero ( tb , ennoblements )
return ennoblements
}