// +build integration package internal import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "path" "testing" "github.com/google/uuid" "github.com/mdiluz/rove/pkg/accounts" "github.com/mdiluz/rove/pkg/atlas" "github.com/mdiluz/rove/pkg/game" "github.com/mdiluz/rove/pkg/rove" "github.com/mdiluz/rove/pkg/vector" "github.com/stretchr/testify/assert" ) func TestHandleStatus(t *testing.T) { request, _ := http.NewRequest(http.MethodGet, "/status", nil) response := httptest.NewRecorder() s := NewServer() s.Initialise(true) s.router.ServeHTTP(response, request) assert.Equal(t, http.StatusOK, response.Code) var status rove.StatusResponse err := json.NewDecoder(response.Body).Decode(&status) assert.NoError(t, err) if status.Ready != true { t.Errorf("got false for /status") } if len(status.Version) == 0 { t.Errorf("got empty version info") } } func TestHandleRegister(t *testing.T) { data := rove.RegisterData{Name: uuid.New().String()} b, err := json.Marshal(data) if err != nil { t.Error(err) } request, _ := http.NewRequest(http.MethodPost, "/register", bytes.NewReader(b)) response := httptest.NewRecorder() s := NewServer() s.Initialise(true) s.router.ServeHTTP(response, request) assert.Equal(t, http.StatusOK, response.Code) var status rove.RegisterResponse err = json.NewDecoder(response.Body).Decode(&status) assert.NoError(t, err) } func TestHandleCommand(t *testing.T) { name := uuid.New().String() s := NewServer() s.Initialise(false) // Leave the world empty with no obstacles reg := accounts.RegisterInfo{Name: name} acc, err := s.accountant.Register(context.Background(), ®) assert.NoError(t, err) assert.NotNil(t, acc) assert.True(t, acc.Success, acc.Error) assert.NoError(t, err, "Error registering account") // Spawn the rover rover for the account _, inst, err := s.SpawnRoverForAccount(name) assert.NoError(t, s.world.WarpRover(inst, vector.Vector{})) attribs, err := s.world.RoverAttributes(inst) assert.NoError(t, err, "Couldn't get rover position") data := rove.CommandData{ Commands: []game.Command{ { Command: game.CommandMove, Bearing: "N", Duration: 1, }, }, } b, err := json.Marshal(data) assert.NoError(t, err, "Error marshalling data") request, _ := http.NewRequest(http.MethodPost, path.Join("/", name, "/command"), bytes.NewReader(b)) response := httptest.NewRecorder() s.router.ServeHTTP(response, request) assert.Equal(t, http.StatusOK, response.Code) var status rove.CommandResponse err = json.NewDecoder(response.Body).Decode(&status) assert.NoError(t, err) attrib, err := s.world.RoverAttributes(inst) assert.NoError(t, err, "Couldn't get rover attribs") // Tick the command queues to progress the move command s.world.EnqueueAllIncoming() s.world.ExecuteCommandQueues() attribs2, err := s.world.RoverAttributes(inst) assert.NoError(t, err, "Couldn't get rover position") attribs.Pos.Add(vector.Vector{X: 0.0, Y: attrib.Speed * 1}) // Should have moved north by the speed and duration assert.Equal(t, attribs.Pos, attribs2.Pos, "Rover should have moved by bearing") } func TestHandleRadar(t *testing.T) { name := uuid.New().String() s := NewServer() s.Initialise(false) // Spawn a clean world reg := accounts.RegisterInfo{Name: name} acc, err := s.accountant.Register(context.Background(), ®) assert.NoError(t, err) assert.True(t, acc.Success, acc.Error) assert.NoError(t, err, "Error registering account") // Spawn the rover rover for the account attrib, id, err := s.SpawnRoverForAccount(name) assert.NoError(t, err) // Warp this rover to 0,0 assert.NoError(t, s.world.WarpRover(id, vector.Vector{})) // Explicity set a few nearby tiles wallPos1 := vector.Vector{X: 0, Y: -1} wallPos2 := vector.Vector{X: 1, Y: 1} rockPos := vector.Vector{X: 1, Y: 3} emptyPos := vector.Vector{X: -2, Y: -3} assert.NoError(t, s.world.Atlas.SetTile(wallPos1, atlas.TileWall)) assert.NoError(t, s.world.Atlas.SetTile(wallPos2, atlas.TileWall)) assert.NoError(t, s.world.Atlas.SetTile(rockPos, atlas.TileRock)) assert.NoError(t, s.world.Atlas.SetTile(emptyPos, atlas.TileEmpty)) request, _ := http.NewRequest(http.MethodGet, path.Join("/", name, "/radar"), nil) response := httptest.NewRecorder() s.router.ServeHTTP(response, request) assert.Equal(t, http.StatusOK, response.Code) var status rove.RadarResponse err = json.NewDecoder(response.Body).Decode(&status) assert.NoError(t, err) scope := attrib.Range*2 + 1 radarOrigin := vector.Vector{X: -attrib.Range, Y: -attrib.Range} // Make sure the rover tile is correct assert.Equal(t, atlas.TileRover, status.Tiles[len(status.Tiles)/2]) // Check our other tiles wallPos1.Add(radarOrigin.Negated()) wallPos2.Add(radarOrigin.Negated()) rockPos.Add(radarOrigin.Negated()) emptyPos.Add(radarOrigin.Negated()) assert.Equal(t, atlas.TileWall, status.Tiles[wallPos1.X+wallPos1.Y*scope]) assert.Equal(t, atlas.TileWall, status.Tiles[wallPos2.X+wallPos2.Y*scope]) assert.Equal(t, atlas.TileRock, status.Tiles[rockPos.X+rockPos.Y*scope]) assert.Equal(t, atlas.TileEmpty, status.Tiles[emptyPos.X+emptyPos.Y*scope]) } func TestHandleRover(t *testing.T) { name := uuid.New().String() s := NewServer() s.Initialise(true) reg := accounts.RegisterInfo{Name: name} acc, err := s.accountant.Register(context.Background(), ®) assert.NoError(t, err) assert.True(t, acc.Success, acc.Error) // Spawn one rover for the account attribs, _, err := s.SpawnRoverForAccount(name) assert.NoError(t, err) request, _ := http.NewRequest(http.MethodGet, path.Join("/", name, "/rover"), nil) response := httptest.NewRecorder() s.router.ServeHTTP(response, request) assert.Equal(t, http.StatusOK, response.Code) var status rove.RoverResponse err = json.NewDecoder(response.Body).Decode(&status) assert.NoError(t, err) if attribs != status.Attributes { t.Errorf("Missmatched attributes: %+v, !=%+v", attribs, status.Attributes) } }