Add missing ruleset params to request body and --debug-requests option (#55)

* fix sending of new params

* add royale and squad settings to requests

* add --debug-requests option

* update test for request body and add helper

Co-authored-by: Penelope Phippen <penelope@hey.com>
This commit is contained in:
Rob O'Dwyer 2021-09-07 14:58:10 -07:00 committed by GitHub
parent 0cba5eff59
commit 31faba642c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 179 additions and 10 deletions

View file

@ -54,9 +54,29 @@ type BoardResponse struct {
Snakes []SnakeResponse `json:"snakes"` Snakes []SnakeResponse `json:"snakes"`
} }
type GameResponseRulesetSettings struct {
HazardDamagePerTurn int32 `json:"hazardDamagePerTurn"`
FoodSpawnChance int32 `json:"foodSpawnChance"`
MinimumFood int32 `json:"minimumFood"`
RoyaleSettings RoyaleSettings `json:"royale"`
SquadSettings SquadSettings `json:"squad"`
}
type RoyaleSettings struct {
ShrinkEveryNTurns int32 `json:"shrinkEveryNTurns"`
}
type SquadSettings struct {
AllowBodyCollisions bool `json:"allowBodyCollisions"`
SharedElimination bool `json:"sharedElimination"`
SharedHealth bool `json:"sharedHealth"`
SharedLength bool `json:"sharedLength"`
}
type GameResponseRuleset struct { type GameResponseRuleset struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version"` Version string `json:"version"`
Settings GameResponseRulesetSettings `json:"settings"`
} }
type GameResponse struct { type GameResponse struct {
@ -101,6 +121,7 @@ var GameType string
var ViewMap bool var ViewMap bool
var Seed int64 var Seed int64
var TurnDelay int32 var TurnDelay int32
var DebugRequests bool
var FoodSpawnChance int32 var FoodSpawnChance int32
var MinimumFood int32 var MinimumFood int32
@ -128,6 +149,7 @@ func init() {
playCmd.Flags().BoolVarP(&ViewMap, "viewmap", "v", false, "View the Map Each Turn") playCmd.Flags().BoolVarP(&ViewMap, "viewmap", "v", false, "View the Map Each Turn")
playCmd.Flags().Int64VarP(&Seed, "seed", "r", time.Now().UTC().UnixNano(), "Random Seed") playCmd.Flags().Int64VarP(&Seed, "seed", "r", time.Now().UTC().UnixNano(), "Random Seed")
playCmd.Flags().Int32VarP(&TurnDelay, "delay", "d", 0, "Turn Delay in Milliseconds") playCmd.Flags().Int32VarP(&TurnDelay, "delay", "d", 0, "Turn Delay in Milliseconds")
playCmd.Flags().BoolVar(&DebugRequests, "debug-requests", false, "Log body of all requests sent")
playCmd.Flags().Int32Var(&FoodSpawnChance, "foodSpawnChance", 15, "Percentage chance of spawning a new food every round") playCmd.Flags().Int32Var(&FoodSpawnChance, "foodSpawnChance", 15, "Percentage chance of spawning a new food every round")
playCmd.Flags().Int32Var(&MinimumFood, "minimumFood", 1, "Minimum food to keep on the board every turn") playCmd.Flags().Int32Var(&MinimumFood, "minimumFood", 1, "Minimum food to keep on the board every turn")
@ -263,6 +285,9 @@ func initializeBoardFromArgs(ruleset rules.Ruleset, snakes []Battlesnake) *rules
requestBody := getIndividualBoardStateForSnake(state, snake, ruleset) requestBody := getIndividualBoardStateForSnake(state, snake, ruleset)
u, _ := url.ParseRequestURI(snake.URL) u, _ := url.ParseRequestURI(snake.URL)
u.Path = path.Join(u.Path, "start") u.Path = path.Join(u.Path, "start")
if DebugRequests {
log.Printf("POST %s: %v", u, string(requestBody))
}
_, err = HttpClient.Post(u.String(), "application/json", bytes.NewBuffer(requestBody)) _, err = HttpClient.Post(u.String(), "application/json", bytes.NewBuffer(requestBody))
if err != nil { if err != nil {
log.Printf("[WARN]: Request to %v failed", u.String()) log.Printf("[WARN]: Request to %v failed", u.String())
@ -326,6 +351,9 @@ func getMoveForSnake(ruleset rules.Ruleset, state *rules.BoardState, snake Battl
requestBody := getIndividualBoardStateForSnake(state, snake, ruleset) requestBody := getIndividualBoardStateForSnake(state, snake, ruleset)
u, _ := url.ParseRequestURI(snake.URL) u, _ := url.ParseRequestURI(snake.URL)
u.Path = path.Join(u.Path, "move") u.Path = path.Join(u.Path, "move")
if DebugRequests {
log.Printf("POST %s: %v", u, string(requestBody))
}
res, err := HttpClient.Post(u.String(), "application/json", bytes.NewBuffer(requestBody)) res, err := HttpClient.Post(u.String(), "application/json", bytes.NewBuffer(requestBody))
move := snake.LastMove move := snake.LastMove
if err != nil { if err != nil {
@ -353,6 +381,9 @@ func sendEndRequest(ruleset rules.Ruleset, state *rules.BoardState, snake Battle
requestBody := getIndividualBoardStateForSnake(state, snake, ruleset) requestBody := getIndividualBoardStateForSnake(state, snake, ruleset)
u, _ := url.ParseRequestURI(snake.URL) u, _ := url.ParseRequestURI(snake.URL)
u.Path = path.Join(u.Path, "end") u.Path = path.Join(u.Path, "end")
if DebugRequests {
log.Printf("POST %s: %v", u, string(requestBody))
}
_, err := HttpClient.Post(u.String(), "application/json", bytes.NewBuffer(requestBody)) _, err := HttpClient.Post(u.String(), "application/json", bytes.NewBuffer(requestBody))
if err != nil { if err != nil {
log.Printf("[WARN]: Request to %v failed", u.String()) log.Printf("[WARN]: Request to %v failed", u.String())
@ -371,6 +402,20 @@ func getIndividualBoardStateForSnake(state *rules.BoardState, snake Battlesnake,
Game: GameResponse{Id: GameId, Timeout: Timeout, Ruleset: GameResponseRuleset{ Game: GameResponse{Id: GameId, Timeout: Timeout, Ruleset: GameResponseRuleset{
Name: ruleset.Name(), Name: ruleset.Name(),
Version: "cli", // TODO: Use GitHub Release Version Version: "cli", // TODO: Use GitHub Release Version
Settings: GameResponseRulesetSettings{
HazardDamagePerTurn: HazardDamagePerTurn,
FoodSpawnChance: FoodSpawnChance,
MinimumFood: MinimumFood,
RoyaleSettings: RoyaleSettings{
ShrinkEveryNTurns: ShrinkEveryNTurns,
},
SquadSettings: SquadSettings{
AllowBodyCollisions: true,
SharedElimination: true,
SharedHealth: true,
SharedLength: true,
},
},
}}, }},
Turn: Turn, Turn: Turn,
Board: BoardResponse{ Board: BoardResponse{

View file

@ -4,7 +4,6 @@ import (
"testing" "testing"
"github.com/BattlesnakeOfficial/rules" "github.com/BattlesnakeOfficial/rules"
"github.com/stretchr/testify/require"
) )
func TestGetIndividualBoardStateForSnake(t *testing.T) { func TestGetIndividualBoardStateForSnake(t *testing.T) {
@ -18,6 +17,5 @@ func TestGetIndividualBoardStateForSnake(t *testing.T) {
snake := Battlesnake{Name: "one", URL: "", ID: "one"} snake := Battlesnake{Name: "one", URL: "", ID: "one"}
requestBody := getIndividualBoardStateForSnake(state, snake, &rules.StandardRuleset{}) requestBody := getIndividualBoardStateForSnake(state, snake, &rules.StandardRuleset{})
expected := "{\"game\":{\"id\":\"\",\"timeout\":500,\"ruleset\":{\"name\":\"standard\",\"version\":\"cli\"}},\"turn\":0,\"board\":{\"height\":11,\"width\":11,\"food\":[],\"hazards\":[],\"snakes\":[{\"id\":\"one\",\"name\":\"\",\"health\":0,\"body\":[{\"x\":3,\"y\":3}],\"latency\":\"0\",\"head\":{\"x\":3,\"y\":3},\"length\":1,\"shout\":\"\",\"squad\":\"\"},{\"id\":\"two\",\"name\":\"\",\"health\":0,\"body\":[{\"x\":4,\"y\":3}],\"latency\":\"0\",\"head\":{\"x\":4,\"y\":3},\"length\":1,\"shout\":\"\",\"squad\":\"\"}]},\"you\":{\"id\":\"one\",\"name\":\"\",\"health\":0,\"body\":[{\"x\":3,\"y\":3}],\"latency\":\"0\",\"head\":{\"x\":3,\"y\":3},\"length\":1,\"shout\":\"\",\"squad\":\"\"}}" rules.RequireJSONMatchesFixture(t, "testdata/snake_request_body.json", string(requestBody))
require.Equal(t, expected, string(requestBody))
} }

View file

@ -0,0 +1,90 @@
{
"game": {
"id": "",
"timeout": 500,
"ruleset": {
"name": "standard",
"version": "cli",
"settings": {
"hazardDamagePerTurn": 14,
"foodSpawnChance": 15,
"minimumFood": 1,
"royale": {
"shrinkEveryNTurns": 25
},
"squad": {
"allowBodyCollisions": true,
"sharedElimination": true,
"sharedHealth": true,
"sharedLength": true
}
}
}
},
"turn": 0,
"board": {
"height": 11,
"width": 11,
"food": [],
"hazards": [],
"snakes": [
{
"id": "one",
"name": "",
"health": 0,
"body": [
{
"x": 3,
"y": 3
}
],
"latency": "0",
"head": {
"x": 3,
"y": 3
},
"length": 1,
"shout": "",
"squad": ""
},
{
"id": "two",
"name": "",
"health": 0,
"body": [
{
"x": 4,
"y": 3
}
],
"latency": "0",
"head": {
"x": 4,
"y": 3
},
"length": 1,
"shout": "",
"squad": ""
}
]
},
"you": {
"id": "one",
"name": "",
"health": 0,
"body": [
{
"x": 3,
"y": 3
}
],
"latency": "0",
"head": {
"x": 3,
"y": 3
},
"length": 1,
"shout": "",
"squad": ""
}
}

View file

@ -43,6 +43,7 @@ type Snake struct {
Body []Point Body []Point
Health int32 Health int32
EliminatedCause string EliminatedCause string
EliminatedOnTurn int32
EliminatedBy string EliminatedBy string
} }

35
test_utils.go Normal file
View file

@ -0,0 +1,35 @@
package rules
import (
"bytes"
"encoding/json"
"flag"
"io/ioutil"
"testing"
"github.com/stretchr/testify/require"
)
var updateFixtures = flag.Bool("update-fixtures", false, "Regenerate fixtures in testdata based on current test output")
// RequireJSONMatchesFixture asserts that the JSON text in actual matches the
// JSON read from filename, without taking into account whitespace and
// ordering. Files can be specified relative to the calling test (e.g.
// testdata/example.json). To regenerate the expected test data automatically
// after making a code change, pass the `-update-fixtures` flag to `go test`.
func RequireJSONMatchesFixture(t *testing.T, filename string, actual string) {
t.Helper()
if *updateFixtures {
var indented bytes.Buffer
err := json.Indent(&indented, []byte(actual), "", " ")
require.NoError(t, err, "Failed to indent JSON")
err = ioutil.WriteFile(filename, indented.Bytes(), 0644)
require.NoError(t, err, "Failed to update fixture", filename)
}
expectedData, err := ioutil.ReadFile(filename)
require.NoError(t, err, "Failed to read fixture", filename)
require.JSONEq(t, string(expectedData), actual)
}