| package requests |
| |
| import ( |
| "net/http" |
| "reflect" |
| "testing" |
| |
| "github.com/frc971/971-Robot-Code/scouting/db" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/debug" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2023_data_scouting" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2024_data_scouting" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2023_data_scouting" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2023_data_scouting_response" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2024_data_scouting" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_2024_data_scouting_response" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_driver_rankings_response" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_pit_images_response" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_2024_actions" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule" |
| "github.com/frc971/971-Robot-Code/scouting/webserver/server" |
| flatbuffers "github.com/google/flatbuffers/go" |
| ) |
| |
| // Validates that an unhandled address results in a 404. |
| func Test404(t *testing.T) { |
| db := MockDatabase{} |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&db, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| resp, err := http.Get("http://localhost:8080/requests/foo") |
| if err != nil { |
| t.Fatalf("Failed to get data: %v", err) |
| } |
| if resp.StatusCode != http.StatusNotFound { |
| t.Fatalf("Expected error code 404, but got %d instead", resp.Status) |
| } |
| } |
| |
| // Validates that we can request the full match list. |
| func TestRequestAllMatches(t *testing.T) { |
| db := MockDatabase{ |
| matches: []db.TeamMatch{ |
| { |
| MatchNumber: 1, SetNumber: 1, CompLevel: "qm", |
| Alliance: "R", AlliancePosition: 1, TeamNumber: "5", |
| }, |
| { |
| MatchNumber: 1, SetNumber: 1, CompLevel: "qm", |
| Alliance: "R", AlliancePosition: 2, TeamNumber: "42", |
| }, |
| { |
| MatchNumber: 1, SetNumber: 1, CompLevel: "qm", |
| Alliance: "R", AlliancePosition: 3, TeamNumber: "600", |
| }, |
| { |
| MatchNumber: 1, SetNumber: 1, CompLevel: "qm", |
| Alliance: "B", AlliancePosition: 1, TeamNumber: "971", |
| }, |
| { |
| MatchNumber: 1, SetNumber: 1, CompLevel: "qm", |
| Alliance: "B", AlliancePosition: 2, TeamNumber: "400", |
| }, |
| { |
| MatchNumber: 1, SetNumber: 1, CompLevel: "qm", |
| Alliance: "B", AlliancePosition: 3, TeamNumber: "200", |
| }, |
| { |
| MatchNumber: 2, SetNumber: 1, CompLevel: "qm", |
| Alliance: "R", AlliancePosition: 1, TeamNumber: "6", |
| }, |
| { |
| MatchNumber: 2, SetNumber: 1, CompLevel: "qm", |
| Alliance: "R", AlliancePosition: 2, TeamNumber: "43", |
| }, |
| { |
| MatchNumber: 2, SetNumber: 1, CompLevel: "qm", |
| Alliance: "R", AlliancePosition: 3, TeamNumber: "601", |
| }, |
| { |
| MatchNumber: 2, SetNumber: 1, CompLevel: "qm", |
| Alliance: "B", AlliancePosition: 1, TeamNumber: "972", |
| }, |
| { |
| MatchNumber: 2, SetNumber: 1, CompLevel: "qm", |
| Alliance: "B", AlliancePosition: 2, TeamNumber: "401", |
| }, |
| { |
| MatchNumber: 2, SetNumber: 1, CompLevel: "qm", |
| Alliance: "B", AlliancePosition: 3, TeamNumber: "201", |
| }, |
| { |
| MatchNumber: 3, SetNumber: 1, CompLevel: "qm", |
| Alliance: "R", AlliancePosition: 1, TeamNumber: "7", |
| }, |
| { |
| MatchNumber: 3, SetNumber: 1, CompLevel: "qm", |
| Alliance: "R", AlliancePosition: 2, TeamNumber: "44", |
| }, |
| { |
| MatchNumber: 3, SetNumber: 1, CompLevel: "qm", |
| Alliance: "R", AlliancePosition: 3, TeamNumber: "602", |
| }, |
| { |
| MatchNumber: 3, SetNumber: 1, CompLevel: "qm", |
| Alliance: "B", AlliancePosition: 1, TeamNumber: "973", |
| }, |
| { |
| MatchNumber: 3, SetNumber: 1, CompLevel: "qm", |
| Alliance: "B", AlliancePosition: 2, TeamNumber: "402", |
| }, |
| { |
| MatchNumber: 3, SetNumber: 1, CompLevel: "qm", |
| Alliance: "B", AlliancePosition: 3, TeamNumber: "202", |
| }, |
| }, |
| // Pretend that we have some data scouting data. |
| stats2024: []db.Stats2024{ |
| { |
| PreScouting: false, TeamNumber: "5", |
| MatchNumber: 1, SetNumber: 1, CompLevel: "qm", StartingQuadrant: 3, |
| SpeakerAuto: 2, AmpAuto: 4, NotesDroppedAuto: 1, MobilityAuto: true, |
| Speaker: 0, Amp: 1, SpeakerAmplified: 2, AmpAmplified: 1, |
| NotesDropped: 0, Penalties: 1, TrapNote: true, Spotlight: false, AvgCycle: 233, |
| Park: false, OnStage: true, Harmony: false, RobotDied: false, CollectedBy: "alex", |
| }, |
| { |
| PreScouting: false, TeamNumber: "973", |
| MatchNumber: 3, SetNumber: 1, CompLevel: "qm", StartingQuadrant: 1, |
| SpeakerAuto: 0, AmpAuto: 2, NotesDroppedAuto: 0, MobilityAuto: false, |
| Speaker: 0, Amp: 4, SpeakerAmplified: 3, AmpAmplified: 1, |
| NotesDropped: 0, Penalties: 1, TrapNote: true, Spotlight: false, AvgCycle: 120, |
| Park: true, OnStage: false, Harmony: false, RobotDied: true, CollectedBy: "bob", |
| }, |
| }, |
| } |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&db, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&request_all_matches.RequestAllMatchesT{}).Pack(builder)) |
| |
| response, err := debug.RequestAllMatches("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to request all matches: ", err) |
| } |
| |
| expected := request_all_matches_response.RequestAllMatchesResponseT{ |
| MatchList: []*request_all_matches_response.MatchT{ |
| // MatchNumber, SetNumber, CompLevel |
| // R1, R2, R3, B1, B2, B3 |
| { |
| 1, 1, "qm", |
| "5", "42", "600", "971", "400", "200", |
| &request_all_matches_response.ScoutedLevelT{ |
| // The R1 team has already been data |
| // scouted. |
| true, false, false, false, false, false, |
| }, |
| }, |
| { |
| 2, 1, "qm", |
| "6", "43", "601", "972", "401", "201", |
| &request_all_matches_response.ScoutedLevelT{ |
| false, false, false, false, false, false, |
| }, |
| }, |
| { |
| 3, 1, "qm", |
| "7", "44", "602", "973", "402", "202", |
| &request_all_matches_response.ScoutedLevelT{ |
| // The B1 team has already been data |
| // scouted. |
| false, false, false, true, false, false, |
| }, |
| }, |
| }, |
| } |
| if len(expected.MatchList) != len(response.MatchList) { |
| t.Fatal("Expected ", expected, ", but got ", *response) |
| } |
| for i, match := range expected.MatchList { |
| if !reflect.DeepEqual(*match, *response.MatchList[i]) { |
| t.Fatal("Expected for match", i, ":", *match, ", but got:", *response.MatchList[i]) |
| } |
| } |
| |
| } |
| |
| // Validates that we can request the 2024 stats. |
| func TestRequest2024DataScouting(t *testing.T) { |
| db := MockDatabase{ |
| stats2024: []db.Stats2024{ |
| { |
| PreScouting: false, TeamNumber: "342", |
| MatchNumber: 3, SetNumber: 1, CompLevel: "quals", StartingQuadrant: 4, |
| SpeakerAuto: 1, AmpAuto: 1, NotesDroppedAuto: 0, MobilityAuto: true, |
| Speaker: 4, Amp: 2, SpeakerAmplified: 1, AmpAmplified: 0, |
| NotesDropped: 2, Penalties: 2, TrapNote: true, Spotlight: true, AvgCycle: 0, |
| Park: true, OnStage: false, Harmony: false, RobotDied: false, CollectedBy: "alex", |
| }, |
| { |
| PreScouting: false, TeamNumber: "982", |
| MatchNumber: 3, SetNumber: 1, CompLevel: "quals", StartingQuadrant: 2, |
| SpeakerAuto: 0, AmpAuto: 0, NotesDroppedAuto: 0, MobilityAuto: false, |
| Speaker: 0, Amp: 2, SpeakerAmplified: 3, AmpAmplified: 2, |
| NotesDropped: 1, Penalties: 0, TrapNote: false, Spotlight: true, AvgCycle: 0, |
| Park: false, OnStage: true, Harmony: false, RobotDied: false, CollectedBy: "george", |
| }, |
| }, |
| } |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&db, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&request_2024_data_scouting.Request2024DataScoutingT{}).Pack(builder)) |
| |
| response, err := debug.Request2024DataScouting("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to request all matches: ", err) |
| } |
| |
| expected := request_2024_data_scouting_response.Request2024DataScoutingResponseT{ |
| StatsList: []*request_2024_data_scouting_response.Stats2024T{ |
| { |
| PreScouting: false, TeamNumber: "342", |
| MatchNumber: 3, SetNumber: 1, CompLevel: "quals", StartingQuadrant: 4, |
| SpeakerAuto: 1, AmpAuto: 1, NotesDroppedAuto: 0, MobilityAuto: true, |
| Speaker: 4, Amp: 2, SpeakerAmplified: 1, AmpAmplified: 0, |
| NotesDropped: 2, Penalties: 2, TrapNote: true, Spotlight: true, AvgCycle: 0, |
| Park: true, OnStage: false, Harmony: false, RobotDied: false, CollectedBy: "alex", |
| }, |
| { |
| PreScouting: false, TeamNumber: "982", |
| MatchNumber: 3, SetNumber: 1, CompLevel: "quals", StartingQuadrant: 2, |
| SpeakerAuto: 0, AmpAuto: 0, NotesDroppedAuto: 0, MobilityAuto: false, |
| Speaker: 0, Amp: 2, SpeakerAmplified: 3, AmpAmplified: 2, |
| NotesDropped: 1, Penalties: 0, TrapNote: false, Spotlight: true, AvgCycle: 0, |
| Park: false, OnStage: true, Harmony: false, RobotDied: false, CollectedBy: "george", |
| }, |
| }, |
| } |
| if len(expected.StatsList) != len(response.StatsList) { |
| t.Fatal("Expected ", expected, ", but got ", *response) |
| } |
| for i, match := range expected.StatsList { |
| if !reflect.DeepEqual(*match, *response.StatsList[i]) { |
| t.Fatal("Expected for stats", i, ":", *match, ", but got:", *response.StatsList[i]) |
| } |
| } |
| } |
| |
| // Validates that we can request the 2023 stats. |
| func TestRequest2023DataScouting(t *testing.T) { |
| db := MockDatabase{ |
| stats2023: []db.Stats2023{ |
| { |
| TeamNumber: "3634", MatchNumber: 1, SetNumber: 2, |
| CompLevel: "quals", StartingQuadrant: 3, LowCubesAuto: 10, |
| MiddleCubesAuto: 1, HighCubesAuto: 1, CubesDroppedAuto: 0, |
| LowConesAuto: 1, MiddleConesAuto: 2, HighConesAuto: 1, |
| ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 1, |
| HighCubes: 2, CubesDropped: 1, LowCones: 1, |
| MiddleCones: 2, HighCones: 0, ConesDropped: 1, SuperchargedPieces: 0, |
| AvgCycle: 34, Mobility: false, DockedAuto: true, EngagedAuto: false, |
| BalanceAttemptAuto: false, Docked: false, Engaged: false, |
| BalanceAttempt: true, CollectedBy: "isaac", |
| }, |
| { |
| TeamNumber: "2343", MatchNumber: 1, SetNumber: 2, |
| CompLevel: "quals", StartingQuadrant: 1, LowCubesAuto: 0, |
| MiddleCubesAuto: 1, HighCubesAuto: 1, CubesDroppedAuto: 2, |
| LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0, |
| ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 0, |
| HighCubes: 1, CubesDropped: 0, LowCones: 0, |
| MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0, |
| AvgCycle: 53, Mobility: false, DockedAuto: false, EngagedAuto: false, |
| BalanceAttemptAuto: true, Docked: false, Engaged: false, |
| BalanceAttempt: true, CollectedBy: "unknown", |
| }, |
| }, |
| } |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&db, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&request_2023_data_scouting.Request2023DataScoutingT{}).Pack(builder)) |
| |
| response, err := debug.Request2023DataScouting("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to request all matches: ", err) |
| } |
| |
| expected := request_2023_data_scouting_response.Request2023DataScoutingResponseT{ |
| StatsList: []*request_2023_data_scouting_response.Stats2023T{ |
| { |
| TeamNumber: "3634", MatchNumber: 1, SetNumber: 2, |
| CompLevel: "quals", StartingQuadrant: 3, LowCubesAuto: 10, |
| MiddleCubesAuto: 1, HighCubesAuto: 1, CubesDroppedAuto: 0, |
| LowConesAuto: 1, MiddleConesAuto: 2, HighConesAuto: 1, |
| ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 1, |
| HighCubes: 2, CubesDropped: 1, LowCones: 1, |
| MiddleCones: 2, HighCones: 0, ConesDropped: 1, SuperchargedPieces: 0, |
| AvgCycle: 34, Mobility: false, DockedAuto: true, EngagedAuto: false, |
| BalanceAttemptAuto: false, Docked: false, Engaged: false, |
| BalanceAttempt: true, CollectedBy: "isaac", |
| }, |
| { |
| TeamNumber: "2343", MatchNumber: 1, SetNumber: 2, |
| CompLevel: "quals", StartingQuadrant: 1, LowCubesAuto: 0, |
| MiddleCubesAuto: 1, HighCubesAuto: 1, CubesDroppedAuto: 2, |
| LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0, |
| ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 0, |
| HighCubes: 1, CubesDropped: 0, LowCones: 0, |
| MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0, |
| AvgCycle: 53, Mobility: false, DockedAuto: false, EngagedAuto: false, |
| BalanceAttemptAuto: true, Docked: false, Engaged: false, |
| BalanceAttempt: true, CollectedBy: "unknown", |
| }, |
| }, |
| } |
| if len(expected.StatsList) != len(response.StatsList) { |
| t.Fatal("Expected ", expected, ", but got ", *response) |
| } |
| for i, match := range expected.StatsList { |
| if !reflect.DeepEqual(*match, *response.StatsList[i]) { |
| t.Fatal("Expected for stats", i, ":", *match, ", but got:", *response.StatsList[i]) |
| } |
| } |
| } |
| |
| // Validates that we can request the 2024 stats. |
| func TestConvertActionsToStat2024(t *testing.T) { |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&submit_2024_actions.Submit2024ActionsT{ |
| TeamNumber: "4244", |
| MatchNumber: 3, |
| SetNumber: 1, |
| CompLevel: "quals", |
| ActionsList: []*submit_2024_actions.ActionT{ |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypeStartMatchAction, |
| Value: &submit_2024_actions.StartMatchActionT{ |
| Position: 2, |
| }, |
| }, |
| Timestamp: 0, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePickupNoteAction, |
| Value: &submit_2024_actions.PickupNoteActionT{ |
| Auto: true, |
| }, |
| }, |
| Timestamp: 400, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePickupNoteAction, |
| Value: &submit_2024_actions.PickupNoteActionT{ |
| Auto: true, |
| }, |
| }, |
| Timestamp: 800, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePlaceNoteAction, |
| Value: &submit_2024_actions.PlaceNoteActionT{ |
| ScoreType: submit_2024_actions.ScoreTypekAMP, |
| Auto: true, |
| }, |
| }, |
| Timestamp: 2000, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypeMobilityAction, |
| Value: &submit_2024_actions.MobilityActionT{ |
| Mobility: true, |
| }, |
| }, |
| Timestamp: 2200, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePenaltyAction, |
| Value: &submit_2024_actions.PenaltyActionT{ |
| Penalties: 5, |
| }, |
| }, |
| Timestamp: 2400, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePickupNoteAction, |
| Value: &submit_2024_actions.PickupNoteActionT{ |
| Auto: false, |
| }, |
| }, |
| Timestamp: 2800, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePlaceNoteAction, |
| Value: &submit_2024_actions.PlaceNoteActionT{ |
| ScoreType: submit_2024_actions.ScoreTypekAMP_AMPLIFIED, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 3100, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePickupNoteAction, |
| Value: &submit_2024_actions.PickupNoteActionT{ |
| Auto: false, |
| }, |
| }, |
| Timestamp: 3200, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePlaceNoteAction, |
| Value: &submit_2024_actions.PlaceNoteActionT{ |
| ScoreType: submit_2024_actions.ScoreTypekDROPPED, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 3300, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypeRobotDeathAction, |
| Value: &submit_2024_actions.RobotDeathActionT{ |
| RobotDead: true, |
| }, |
| }, |
| Timestamp: 3400, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypeRobotDeathAction, |
| Value: &submit_2024_actions.RobotDeathActionT{ |
| RobotDead: false, |
| }, |
| }, |
| Timestamp: 3450, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePickupNoteAction, |
| Value: &submit_2024_actions.PickupNoteActionT{ |
| Auto: false, |
| }, |
| }, |
| Timestamp: 3500, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePlaceNoteAction, |
| Value: &submit_2024_actions.PlaceNoteActionT{ |
| ScoreType: submit_2024_actions.ScoreTypekSPEAKER_AMPLIFIED, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 3900, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypeEndMatchAction, |
| Value: &submit_2024_actions.EndMatchActionT{ |
| StageType: submit_2024_actions.StageTypekHARMONY, |
| TrapNote: false, |
| Spotlight: false, |
| }, |
| }, |
| Timestamp: 4200, |
| }, |
| }, |
| PreScouting: false, |
| }).Pack(builder)) |
| |
| submit2024Actions := submit_2024_actions.GetRootAsSubmit2024Actions(builder.FinishedBytes(), 0) |
| response, err := ConvertActionsToStat2024(submit2024Actions) |
| |
| if err != nil { |
| t.Fatal("Failed to convert actions to stats: ", err) |
| } |
| |
| expected := db.Stats2024{ |
| PreScouting: false, TeamNumber: "4244", |
| MatchNumber: 3, SetNumber: 1, CompLevel: "quals", StartingQuadrant: 2, |
| SpeakerAuto: 0, AmpAuto: 1, NotesDroppedAuto: 0, MobilityAuto: true, |
| Speaker: 0, Amp: 0, SpeakerAmplified: 1, AmpAmplified: 1, |
| NotesDropped: 1, Penalties: 5, TrapNote: false, Spotlight: false, AvgCycle: 633, |
| Park: false, OnStage: false, Harmony: true, RobotDied: true, CollectedBy: "", |
| } |
| |
| if expected != response { |
| t.Fatal("Expected ", expected, ", but got ", response) |
| } |
| } |
| |
| // Validates that we can request the 2023 stats. |
| func TestConvertActionsToStat(t *testing.T) { |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&submit_actions.SubmitActionsT{ |
| TeamNumber: "4244", |
| MatchNumber: 3, |
| SetNumber: 1, |
| CompLevel: "quals", |
| ActionsList: []*submit_actions.ActionT{ |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypeStartMatchAction, |
| Value: &submit_actions.StartMatchActionT{ |
| Position: 1, |
| }, |
| }, |
| Timestamp: 0, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePickupObjectAction, |
| Value: &submit_actions.PickupObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCube, |
| Auto: true, |
| }, |
| }, |
| Timestamp: 400, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePickupObjectAction, |
| Value: &submit_actions.PickupObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCube, |
| Auto: true, |
| }, |
| }, |
| Timestamp: 800, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePlaceObjectAction, |
| Value: &submit_actions.PlaceObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCube, |
| ScoreLevel: submit_actions.ScoreLevelkLow, |
| Auto: true, |
| }, |
| }, |
| Timestamp: 2000, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypeMobilityAction, |
| Value: &submit_actions.MobilityActionT{ |
| Mobility: true, |
| }, |
| }, |
| Timestamp: 2200, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypeAutoBalanceAction, |
| Value: &submit_actions.AutoBalanceActionT{ |
| Docked: true, |
| Engaged: true, |
| BalanceAttempt: false, |
| }, |
| }, |
| Timestamp: 2400, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePickupObjectAction, |
| Value: &submit_actions.PickupObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCone, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 2800, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePlaceObjectAction, |
| Value: &submit_actions.PlaceObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCone, |
| ScoreLevel: submit_actions.ScoreLevelkHigh, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 3100, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePickupObjectAction, |
| Value: &submit_actions.PickupObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCube, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 3500, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePlaceObjectAction, |
| Value: &submit_actions.PlaceObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCube, |
| ScoreLevel: submit_actions.ScoreLevelkSupercharged, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 3900, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypeEndMatchAction, |
| Value: &submit_actions.EndMatchActionT{ |
| Docked: true, |
| Engaged: false, |
| BalanceAttempt: true, |
| }, |
| }, |
| Timestamp: 4200, |
| }, |
| }, |
| PreScouting: false, |
| }).Pack(builder)) |
| |
| submitActions := submit_actions.GetRootAsSubmitActions(builder.FinishedBytes(), 0) |
| response, err := ConvertActionsToStat(submitActions) |
| |
| if err != nil { |
| t.Fatal("Failed to convert actions to stats: ", err) |
| } |
| |
| expected := db.Stats2023{ |
| PreScouting: false, |
| TeamNumber: "4244", MatchNumber: 3, SetNumber: 1, |
| CompLevel: "quals", StartingQuadrant: 1, LowCubesAuto: 1, |
| MiddleCubesAuto: 0, HighCubesAuto: 0, CubesDroppedAuto: 1, |
| LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0, |
| ConesDroppedAuto: 0, LowCubes: 0, MiddleCubes: 0, |
| HighCubes: 0, CubesDropped: 0, LowCones: 0, |
| MiddleCones: 0, HighCones: 1, ConesDropped: 0, SuperchargedPieces: 1, |
| AvgCycle: 950, Mobility: true, DockedAuto: true, EngagedAuto: true, |
| BalanceAttemptAuto: false, Docked: true, Engaged: false, |
| BalanceAttempt: true, CollectedBy: "", |
| } |
| |
| if expected != response { |
| t.Fatal("Expected ", expected, ", but got ", response) |
| } |
| } |
| |
| func TestSubmitNotes(t *testing.T) { |
| database := MockDatabase{} |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&database, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&submit_notes.SubmitNotesT{ |
| Team: "971", |
| Notes: "Notes", |
| GoodDriving: true, |
| BadDriving: false, |
| SolidPlacing: true, |
| SketchyPlacing: false, |
| GoodDefense: true, |
| BadDefense: false, |
| EasilyDefended: true, |
| NoShow: false, |
| MatchNumber: 4, |
| CompLevel: "qm", |
| SetNumber: 1, |
| }).Pack(builder)) |
| |
| _, err := debug.SubmitNotes("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to submit notes: ", err) |
| } |
| |
| expected := []db.NotesData{ |
| { |
| TeamNumber: "971", |
| Notes: "Notes", |
| GoodDriving: true, |
| BadDriving: false, |
| SolidPlacing: true, |
| SketchyPlacing: false, |
| GoodDefense: true, |
| BadDefense: false, |
| EasilyDefended: true, |
| NoShow: false, |
| MatchNumber: 4, |
| CompLevel: "qm", |
| SetNumber: 1, |
| }, |
| } |
| |
| if !reflect.DeepEqual(database.notes, expected) { |
| t.Fatal("Submitted notes did not match", expected, database.notes) |
| } |
| } |
| |
| func TestRequestNotes(t *testing.T) { |
| database := MockDatabase{ |
| notes: []db.NotesData{{ |
| TeamNumber: "971A", |
| Notes: "Notes", |
| GoodDriving: true, |
| BadDriving: false, |
| SolidPlacing: true, |
| SketchyPlacing: false, |
| GoodDefense: true, |
| BadDefense: false, |
| EasilyDefended: true, |
| NoShow: false, |
| MatchNumber: 4, |
| CompLevel: "qm", |
| SetNumber: 1, |
| }}, |
| } |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&database, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&request_notes_for_team.RequestNotesForTeamT{ |
| Team: "971A", |
| }).Pack(builder)) |
| response, err := debug.RequestNotes("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to submit notes: ", err) |
| } |
| |
| if response.Notes[0].Data != "Notes" { |
| t.Fatal("requested notes did not match", response) |
| } |
| } |
| |
| func TestSubmitPitImage(t *testing.T) { |
| database := MockDatabase{} |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&database, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&submit_pit_image.SubmitPitImageT{ |
| TeamNumber: "483A", ImagePath: "483Arobot.jpg", |
| ImageData: []byte{12, 43, 54, 34, 98}, |
| }).Pack(builder)) |
| |
| _, err := debug.SubmitPitImage("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to submit pit image: ", err) |
| } |
| |
| expected := []db.PitImage{ |
| { |
| TeamNumber: "483A", CheckSum: "177d9dc52bc25f391232e82521259c378964c068832a9178d73448ba4ac5e0b1", |
| ImagePath: "483Arobot.jpg", ImageData: []byte{12, 43, 54, 34, 98}, |
| }, |
| } |
| |
| if !reflect.DeepEqual(database.images, expected) { |
| t.Fatal("Submitted image did not match", expected, database.images) |
| } |
| } |
| |
| func TestRequestPitImages(t *testing.T) { |
| db := MockDatabase{ |
| images: []db.PitImage{ |
| { |
| TeamNumber: "932", ImagePath: "pitimage.jpg", |
| ImageData: []byte{3, 34, 44, 65}, CheckSum: "abcdf", |
| }, |
| { |
| TeamNumber: "234", ImagePath: "234robot.png", |
| ImageData: []byte{64, 54, 21, 21, 76, 32}, CheckSum: "egrfd", |
| }, |
| { |
| TeamNumber: "93A", ImagePath: "abcd.jpg", |
| ImageData: []byte{92, 94, 10, 30, 57, 32, 32}, CheckSum: "rgegfd", |
| }, |
| }, |
| } |
| |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&db, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&request_pit_images.RequestPitImagesT{"932"}).Pack(builder)) |
| |
| response, err := debug.RequestPitImages("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to request pit images: ", err) |
| } |
| |
| expected := request_pit_images_response.RequestPitImagesResponseT{ |
| PitImageList: []*request_pit_images_response.PitImageT{ |
| { |
| TeamNumber: "932", ImagePath: "pitimage.jpg", CheckSum: "abcdf", |
| }, |
| }, |
| } |
| |
| if len(expected.PitImageList) != len(response.PitImageList) { |
| t.Fatal("Expected ", expected, ", but got ", *response) |
| } |
| |
| for i, pit_image := range expected.PitImageList { |
| if !reflect.DeepEqual(*pit_image, *response.PitImageList[i]) { |
| t.Fatal("Expected for pit image", i, ":", *pit_image, ", but got:", *response.PitImageList[i]) |
| } |
| } |
| } |
| |
| func TestRequestAllPitImages(t *testing.T) { |
| db := MockDatabase{ |
| images: []db.PitImage{ |
| { |
| TeamNumber: "32", ImagePath: "pitimage.jpg", |
| ImageData: []byte{3, 43, 44, 32}, CheckSum: "cdhrj", |
| }, |
| { |
| TeamNumber: "231", ImagePath: "232robot.png", |
| ImageData: []byte{64, 54, 54, 21, 76, 32}, CheckSum: "rgre", |
| }, |
| { |
| TeamNumber: "90", ImagePath: "abcd.jpg", |
| ImageData: []byte{92, 94, 10, 30, 57, 32, 32}, CheckSum: "erfer", |
| }, |
| }, |
| } |
| |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&db, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&request_all_pit_images.RequestAllPitImagesT{}).Pack(builder)) |
| |
| response, err := debug.RequestAllPitImages("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to request pit images: ", err) |
| } |
| |
| expected := request_all_pit_images_response.RequestAllPitImagesResponseT{ |
| PitImageList: []*request_all_pit_images_response.PitImageT{ |
| { |
| TeamNumber: "32", ImagePath: "pitimage.jpg", CheckSum: "cdhrj", |
| }, |
| { |
| TeamNumber: "231", ImagePath: "232robot.png", CheckSum: "rgre", |
| }, |
| { |
| TeamNumber: "90", ImagePath: "abcd.jpg", CheckSum: "erfer", |
| }, |
| }, |
| } |
| |
| if len(expected.PitImageList) != len(response.PitImageList) { |
| t.Fatal("Expected ", expected, ", but got ", *response) |
| } |
| |
| for i, pit_image := range expected.PitImageList { |
| if !reflect.DeepEqual(*pit_image, *response.PitImageList[i]) { |
| t.Fatal("Expected for pit image", i, ":", *pit_image, ", but got:", *response.PitImageList[i]) |
| } |
| } |
| } |
| |
| func TestRequestShiftSchedule(t *testing.T) { |
| db := MockDatabase{ |
| shiftSchedule: []db.Shift{ |
| { |
| MatchNumber: 1, |
| R1scouter: "Bob", |
| R2scouter: "James", |
| R3scouter: "Robert", |
| B1scouter: "Alice", |
| B2scouter: "Mary", |
| B3scouter: "Patricia", |
| }, |
| { |
| MatchNumber: 2, |
| R1scouter: "Liam", |
| R2scouter: "Noah", |
| R3scouter: "Oliver", |
| B1scouter: "Emma", |
| B2scouter: "Charlotte", |
| B3scouter: "Amelia", |
| }, |
| }, |
| } |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&db, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&request_shift_schedule.RequestShiftScheduleT{}).Pack(builder)) |
| |
| response, err := debug.RequestShiftSchedule("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to request shift schedule: ", err) |
| } |
| |
| expected := request_shift_schedule_response.RequestShiftScheduleResponseT{ |
| ShiftSchedule: []*request_shift_schedule_response.MatchAssignmentT{ |
| { |
| MatchNumber: 1, |
| R1Scouter: "Bob", |
| R2Scouter: "James", |
| R3Scouter: "Robert", |
| B1Scouter: "Alice", |
| B2Scouter: "Mary", |
| B3Scouter: "Patricia", |
| }, |
| { |
| MatchNumber: 2, |
| R1Scouter: "Liam", |
| R2Scouter: "Noah", |
| R3Scouter: "Oliver", |
| B1Scouter: "Emma", |
| B2Scouter: "Charlotte", |
| B3Scouter: "Amelia", |
| }, |
| }, |
| } |
| if len(expected.ShiftSchedule) != len(response.ShiftSchedule) { |
| t.Fatal("Expected ", expected, ", but got ", *response) |
| } |
| for i, match := range expected.ShiftSchedule { |
| if !reflect.DeepEqual(*match, *response.ShiftSchedule[i]) { |
| t.Fatal("Expected for shift schedule", i, ":", *match, ", but got:", *response.ShiftSchedule[i]) |
| } |
| } |
| } |
| |
| func TestSubmitShiftSchedule(t *testing.T) { |
| database := MockDatabase{} |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&database, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&submit_shift_schedule.SubmitShiftScheduleT{ |
| ShiftSchedule: []*submit_shift_schedule.MatchAssignmentT{ |
| {MatchNumber: 1, |
| R1Scouter: "Bob", |
| R2Scouter: "James", |
| R3Scouter: "Robert", |
| B1Scouter: "Alice", |
| B2Scouter: "Mary", |
| B3Scouter: "Patricia"}, |
| }, |
| }).Pack(builder)) |
| |
| _, err := debug.SubmitShiftSchedule("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to submit shift schedule: ", err) |
| } |
| |
| expected := []db.Shift{ |
| {MatchNumber: 1, |
| R1scouter: "Bob", |
| R2scouter: "James", |
| R3scouter: "Robert", |
| B1scouter: "Alice", |
| B2scouter: "Mary", |
| B3scouter: "Patricia"}, |
| } |
| if !reflect.DeepEqual(expected, database.shiftSchedule) { |
| t.Fatal("Expected ", expected, ", but got:", database.shiftSchedule) |
| } |
| } |
| |
| func TestSubmitDriverRanking(t *testing.T) { |
| database := MockDatabase{} |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&database, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&submit_driver_ranking.SubmitDriverRankingT{ |
| MatchNumber: 36, |
| Rank1: "1234", |
| Rank2: "1235", |
| Rank3: "1236", |
| }).Pack(builder)) |
| |
| _, err := debug.SubmitDriverRanking("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to submit driver ranking: ", err) |
| } |
| |
| expected := []db.DriverRankingData{ |
| {MatchNumber: 36, Rank1: "1234", Rank2: "1235", Rank3: "1236"}, |
| } |
| |
| if !reflect.DeepEqual(database.driver_ranking, expected) { |
| t.Fatal("Submitted notes did not match", expected, database.notes) |
| } |
| } |
| |
| // Validates that we can request the driver rankings. |
| func TestRequestDriverRankings(t *testing.T) { |
| db := MockDatabase{ |
| driver_ranking: []db.DriverRankingData{ |
| { |
| MatchNumber: 36, |
| Rank1: "1234", |
| Rank2: "1235", |
| Rank3: "1236", |
| }, |
| { |
| MatchNumber: 36, |
| Rank1: "101", |
| Rank2: "202", |
| Rank3: "303", |
| }, |
| }, |
| } |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&db, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&request_all_driver_rankings.RequestAllDriverRankingsT{}).Pack(builder)) |
| |
| response, err := debug.RequestAllDriverRankings("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to request all driver rankings: ", err) |
| } |
| |
| expected := request_all_driver_rankings_response.RequestAllDriverRankingsResponseT{ |
| DriverRankingList: []*request_all_driver_rankings_response.RankingT{ |
| { |
| MatchNumber: 36, |
| Rank1: "1234", |
| Rank2: "1235", |
| Rank3: "1236", |
| }, |
| { |
| MatchNumber: 36, |
| Rank1: "101", |
| Rank2: "202", |
| Rank3: "303", |
| }, |
| }, |
| } |
| if len(expected.DriverRankingList) != len(response.DriverRankingList) { |
| t.Fatal("Expected ", expected, ", but got ", *response) |
| } |
| for i, match := range expected.DriverRankingList { |
| if !reflect.DeepEqual(*match, *response.DriverRankingList[i]) { |
| t.Fatal("Expected for driver ranking", i, ":", *match, ", but got:", *response.DriverRankingList[i]) |
| } |
| } |
| } |
| |
| // Validates that we can request all notes. |
| func TestRequestAllNotes(t *testing.T) { |
| db := MockDatabase{ |
| notes: []db.NotesData{ |
| { |
| TeamNumber: "971", |
| Notes: "Notes", |
| GoodDriving: true, |
| BadDriving: false, |
| SolidPlacing: true, |
| SketchyPlacing: false, |
| GoodDefense: true, |
| BadDefense: false, |
| EasilyDefended: false, |
| NoShow: false, |
| MatchNumber: 4, |
| CompLevel: "qm", |
| SetNumber: 1, |
| }, |
| { |
| TeamNumber: "972", |
| Notes: "More Notes", |
| GoodDriving: false, |
| BadDriving: false, |
| SolidPlacing: false, |
| SketchyPlacing: true, |
| GoodDefense: false, |
| BadDefense: true, |
| EasilyDefended: false, |
| NoShow: false, |
| MatchNumber: 1, |
| CompLevel: "qm", |
| SetNumber: 2, |
| }, |
| }, |
| } |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&db, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&request_all_notes.RequestAllNotesT{}).Pack(builder)) |
| |
| response, err := debug.RequestAllNotes("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to request all notes: ", err) |
| } |
| |
| expected := request_all_notes_response.RequestAllNotesResponseT{ |
| NoteList: []*request_all_notes_response.NoteT{ |
| { |
| Team: "971", |
| Notes: "Notes", |
| GoodDriving: true, |
| BadDriving: false, |
| SolidPlacing: true, |
| SketchyPlacing: false, |
| GoodDefense: true, |
| BadDefense: false, |
| EasilyDefended: false, |
| NoShow: false, |
| MatchNumber: 4, |
| CompLevel: "qm", |
| SetNumber: 1, |
| }, |
| { |
| Team: "972", |
| Notes: "More Notes", |
| GoodDriving: false, |
| BadDriving: false, |
| SolidPlacing: false, |
| SketchyPlacing: true, |
| GoodDefense: false, |
| BadDefense: true, |
| EasilyDefended: false, |
| NoShow: false, |
| MatchNumber: 1, |
| CompLevel: "qm", |
| SetNumber: 2, |
| }, |
| }, |
| } |
| if len(expected.NoteList) != len(response.NoteList) { |
| t.Fatal("Expected ", expected, ", but got ", *response) |
| } |
| for i, note := range expected.NoteList { |
| if !reflect.DeepEqual(*note, *response.NoteList[i]) { |
| t.Fatal("Expected for note", i, ":", *note, ", but got:", *response.NoteList[i]) |
| } |
| } |
| } |
| |
| func packAction(action *submit_actions.ActionT) []byte { |
| builder := flatbuffers.NewBuilder(50 * 1024) |
| builder.Finish((action).Pack(builder)) |
| return (builder.FinishedBytes()) |
| } |
| |
| func TestAddingActions2024(t *testing.T) { |
| database := MockDatabase{} |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&database, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&submit_2024_actions.Submit2024ActionsT{ |
| TeamNumber: "3421", |
| MatchNumber: 2, |
| SetNumber: 1, |
| CompLevel: "quals", |
| ActionsList: []*submit_2024_actions.ActionT{ |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePickupNoteAction, |
| Value: &submit_2024_actions.PickupNoteActionT{ |
| Auto: true, |
| }, |
| }, |
| Timestamp: 1800, |
| }, |
| { |
| ActionTaken: &submit_2024_actions.ActionTypeT{ |
| Type: submit_2024_actions.ActionTypePlaceNoteAction, |
| Value: &submit_2024_actions.PlaceNoteActionT{ |
| ScoreType: submit_2024_actions.ScoreTypekSPEAKER, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 2500, |
| }, |
| }, |
| PreScouting: true, |
| }).Pack(builder)) |
| |
| _, err := debug.Submit2024Actions("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to submit actions: ", err) |
| } |
| |
| expectedActions := []db.Action{ |
| { |
| PreScouting: true, |
| TeamNumber: "3421", |
| MatchNumber: 2, |
| SetNumber: 1, |
| CompLevel: "quals", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 1800, |
| }, |
| { |
| PreScouting: true, |
| TeamNumber: "3421", |
| MatchNumber: 2, |
| SetNumber: 1, |
| CompLevel: "quals", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 2500, |
| }, |
| } |
| |
| expectedStats := []db.Stats2024{ |
| db.Stats2024{ |
| PreScouting: true, TeamNumber: "3421", |
| MatchNumber: 2, SetNumber: 1, CompLevel: "quals", StartingQuadrant: 0, |
| SpeakerAuto: 0, AmpAuto: 0, NotesDroppedAuto: 0, MobilityAuto: false, |
| Speaker: 1, Amp: 0, SpeakerAmplified: 0, AmpAmplified: 0, |
| NotesDropped: 0, Penalties: 0, TrapNote: false, Spotlight: false, AvgCycle: 0, |
| Park: false, OnStage: false, Harmony: false, RobotDied: false, CollectedBy: "debug_cli", |
| }, |
| } |
| |
| if !reflect.DeepEqual(expectedActions, database.actions) { |
| t.Fatal("Expected ", expectedActions, ", but got:", database.actions) |
| } |
| if !reflect.DeepEqual(expectedStats, database.stats2024) { |
| t.Fatal("Expected ", expectedStats, ", but got:", database.stats2024) |
| } |
| } |
| |
| func TestAddingActions(t *testing.T) { |
| database := MockDatabase{} |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&database, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&submit_actions.SubmitActionsT{ |
| TeamNumber: "1234", |
| MatchNumber: 4, |
| SetNumber: 1, |
| CompLevel: "qual", |
| ActionsList: []*submit_actions.ActionT{ |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePickupObjectAction, |
| Value: &submit_actions.PickupObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCube, |
| Auto: true, |
| }, |
| }, |
| Timestamp: 2400, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePlaceObjectAction, |
| Value: &submit_actions.PlaceObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCube, |
| ScoreLevel: submit_actions.ScoreLevelkLow, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 1009, |
| }, |
| }, |
| PreScouting: true, |
| }).Pack(builder)) |
| |
| _, err := debug.SubmitActions("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to submit actions: ", err) |
| } |
| |
| // Make sure that the data made it into the database. |
| // TODO: Add this back when we figure out how to add the serialized action into the database. |
| |
| /* expectedActionsT := []*submit_actions.ActionT{ |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePickupObjectAction, |
| Value: &submit_actions.PickupObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCube, |
| Auto: true, |
| }, |
| }, |
| Timestamp: 2400, |
| }, |
| { |
| ActionTaken: &submit_actions.ActionTypeT{ |
| Type: submit_actions.ActionTypePlaceObjectAction, |
| Value: &submit_actions.PlaceObjectActionT{ |
| ObjectType: submit_actions.ObjectTypekCube, |
| ScoreLevel: submit_actions.ScoreLevelkLow, |
| Auto: false, |
| }, |
| }, |
| Timestamp: 1009, |
| }, |
| } */ |
| |
| expectedActions := []db.Action{ |
| { |
| PreScouting: true, |
| TeamNumber: "1234", |
| MatchNumber: 4, |
| SetNumber: 1, |
| CompLevel: "qual", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 2400, |
| }, |
| { |
| PreScouting: true, |
| TeamNumber: "1234", |
| MatchNumber: 4, |
| SetNumber: 1, |
| CompLevel: "qual", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 1009, |
| }, |
| } |
| |
| expectedStats := []db.Stats2023{ |
| db.Stats2023{ |
| PreScouting: true, |
| TeamNumber: "1234", MatchNumber: 4, SetNumber: 1, |
| CompLevel: "qual", StartingQuadrant: 0, LowCubesAuto: 0, |
| MiddleCubesAuto: 0, HighCubesAuto: 0, CubesDroppedAuto: 0, |
| LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0, |
| ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 0, |
| HighCubes: 0, CubesDropped: 0, LowCones: 0, |
| MiddleCones: 0, HighCones: 0, ConesDropped: 0, SuperchargedPieces: 0, |
| AvgCycle: 0, Mobility: false, DockedAuto: false, EngagedAuto: false, |
| BalanceAttemptAuto: false, Docked: false, Engaged: false, |
| BalanceAttempt: false, CollectedBy: "debug_cli", |
| }, |
| } |
| |
| if !reflect.DeepEqual(expectedActions, database.actions) { |
| t.Fatal("Expected ", expectedActions, ", but got:", database.actions) |
| } |
| if !reflect.DeepEqual(expectedStats, database.stats2023) { |
| t.Fatal("Expected ", expectedStats, ", but got:", database.stats2023) |
| } |
| } |
| |
| // Validates that we can delete stats. |
| func TestDeleteFromStats(t *testing.T) { |
| database := MockDatabase{ |
| stats2023: []db.Stats2023{ |
| { |
| TeamNumber: "3634", MatchNumber: 1, SetNumber: 2, |
| CompLevel: "quals", StartingQuadrant: 3, LowCubesAuto: 10, |
| MiddleCubesAuto: 1, HighCubesAuto: 1, CubesDroppedAuto: 0, |
| LowConesAuto: 1, MiddleConesAuto: 2, HighConesAuto: 1, |
| ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 1, |
| HighCubes: 2, CubesDropped: 1, LowCones: 1, |
| MiddleCones: 2, HighCones: 0, ConesDropped: 1, SuperchargedPieces: 0, |
| AvgCycle: 34, Mobility: false, DockedAuto: true, EngagedAuto: false, |
| BalanceAttemptAuto: false, Docked: false, Engaged: false, |
| BalanceAttempt: true, CollectedBy: "isaac", |
| }, |
| { |
| TeamNumber: "2343", MatchNumber: 1, SetNumber: 2, |
| CompLevel: "quals", StartingQuadrant: 1, LowCubesAuto: 0, |
| MiddleCubesAuto: 1, HighCubesAuto: 1, CubesDroppedAuto: 2, |
| LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0, |
| ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 0, |
| HighCubes: 1, CubesDropped: 0, LowCones: 0, |
| MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0, |
| AvgCycle: 53, Mobility: false, DockedAuto: false, EngagedAuto: false, |
| BalanceAttemptAuto: true, Docked: false, Engaged: false, |
| BalanceAttempt: true, CollectedBy: "unknown", |
| }, |
| }, |
| actions: []db.Action{ |
| { |
| PreScouting: true, |
| TeamNumber: "3634", |
| MatchNumber: 1, |
| SetNumber: 2, |
| CompLevel: "quals", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 2400, |
| }, |
| { |
| PreScouting: true, |
| TeamNumber: "2343", |
| MatchNumber: 1, |
| SetNumber: 2, |
| CompLevel: "quals", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 1009, |
| }, |
| }, |
| } |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&database, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&delete_2023_data_scouting.Delete2023DataScoutingT{ |
| CompLevel: "quals", |
| MatchNumber: 1, |
| SetNumber: 2, |
| TeamNumber: "2343", |
| }).Pack(builder)) |
| |
| _, err := debug.Delete2023DataScouting("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to delete from data scouting ", err) |
| } |
| |
| expectedActions := []db.Action{ |
| { |
| PreScouting: true, |
| TeamNumber: "3634", |
| MatchNumber: 1, |
| SetNumber: 2, |
| CompLevel: "quals", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 2400, |
| }, |
| } |
| |
| expectedStats := []db.Stats2023{ |
| { |
| TeamNumber: "3634", MatchNumber: 1, SetNumber: 2, |
| CompLevel: "quals", StartingQuadrant: 3, LowCubesAuto: 10, |
| MiddleCubesAuto: 1, HighCubesAuto: 1, CubesDroppedAuto: 0, |
| LowConesAuto: 1, MiddleConesAuto: 2, HighConesAuto: 1, |
| ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 1, |
| HighCubes: 2, CubesDropped: 1, LowCones: 1, |
| MiddleCones: 2, HighCones: 0, ConesDropped: 1, SuperchargedPieces: 0, |
| AvgCycle: 34, Mobility: false, DockedAuto: true, EngagedAuto: false, |
| BalanceAttemptAuto: false, Docked: false, Engaged: false, |
| BalanceAttempt: true, CollectedBy: "isaac", |
| }, |
| } |
| |
| if !reflect.DeepEqual(expectedActions, database.actions) { |
| t.Fatal("Expected ", expectedActions, ", but got:", database.actions) |
| } |
| if !reflect.DeepEqual(expectedStats, database.stats2023) { |
| t.Fatal("Expected ", expectedStats, ", but got:", database.stats2023) |
| } |
| } |
| |
| // Validates that we can delete 2024 stats. |
| func TestDeleteFromStats2024(t *testing.T) { |
| database := MockDatabase{ |
| stats2024: []db.Stats2024{ |
| { |
| PreScouting: false, TeamNumber: "746", |
| MatchNumber: 3, SetNumber: 1, CompLevel: "quals", StartingQuadrant: 2, |
| SpeakerAuto: 0, AmpAuto: 1, NotesDroppedAuto: 1, MobilityAuto: true, |
| Speaker: 0, Amp: 1, SpeakerAmplified: 1, AmpAmplified: 1, |
| NotesDropped: 0, Penalties: 1, TrapNote: true, Spotlight: false, AvgCycle: 233, |
| Park: false, OnStage: false, Harmony: true, RobotDied: false, CollectedBy: "alek", |
| }, |
| { |
| PreScouting: false, TeamNumber: "244", |
| MatchNumber: 5, SetNumber: 3, CompLevel: "quals", StartingQuadrant: 1, |
| SpeakerAuto: 0, AmpAuto: 0, NotesDroppedAuto: 0, MobilityAuto: false, |
| Speaker: 0, Amp: 0, SpeakerAmplified: 3, AmpAmplified: 1, |
| NotesDropped: 0, Penalties: 1, TrapNote: false, Spotlight: false, AvgCycle: 120, |
| Park: false, OnStage: true, Harmony: false, RobotDied: false, CollectedBy: "kacey", |
| }, |
| }, |
| actions: []db.Action{ |
| { |
| PreScouting: true, |
| TeamNumber: "746", |
| MatchNumber: 3, |
| SetNumber: 1, |
| CompLevel: "quals", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 2400, |
| }, |
| { |
| PreScouting: true, |
| TeamNumber: "244", |
| MatchNumber: 5, |
| SetNumber: 3, |
| CompLevel: "quals", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 1009, |
| }, |
| }, |
| } |
| scoutingServer := server.NewScoutingServer() |
| HandleRequests(&database, scoutingServer) |
| scoutingServer.Start(8080) |
| defer scoutingServer.Stop() |
| |
| builder := flatbuffers.NewBuilder(1024) |
| builder.Finish((&delete_2024_data_scouting.Delete2024DataScoutingT{ |
| CompLevel: "quals", |
| MatchNumber: 3, |
| SetNumber: 1, |
| TeamNumber: "746", |
| }).Pack(builder)) |
| |
| _, err := debug.Delete2024DataScouting("http://localhost:8080", builder.FinishedBytes()) |
| if err != nil { |
| t.Fatal("Failed to delete from data scouting 2024", err) |
| } |
| |
| expectedActions := []db.Action{ |
| { |
| PreScouting: true, |
| TeamNumber: "244", |
| MatchNumber: 5, |
| SetNumber: 3, |
| CompLevel: "quals", |
| CollectedBy: "debug_cli", |
| CompletedAction: []byte{}, |
| Timestamp: 1009, |
| }, |
| } |
| |
| expectedStats := []db.Stats2024{ |
| { |
| PreScouting: false, TeamNumber: "244", |
| MatchNumber: 5, SetNumber: 3, CompLevel: "quals", StartingQuadrant: 1, |
| SpeakerAuto: 0, AmpAuto: 0, NotesDroppedAuto: 0, MobilityAuto: false, |
| Speaker: 0, Amp: 0, SpeakerAmplified: 3, AmpAmplified: 1, |
| NotesDropped: 0, Penalties: 1, TrapNote: false, Spotlight: false, AvgCycle: 120, |
| Park: false, OnStage: true, Harmony: false, RobotDied: false, CollectedBy: "kacey", |
| }, |
| } |
| |
| if !reflect.DeepEqual(expectedActions, database.actions) { |
| t.Fatal("Expected ", expectedActions, ", but got:", database.actions) |
| } |
| if !reflect.DeepEqual(expectedStats, database.stats2024) { |
| t.Fatal("Expected ", expectedStats, ", but got:", database.stats2024) |
| } |
| } |
| |
| // A mocked database we can use for testing. Add functionality to this as |
| // needed for your tests. |
| |
| type MockDatabase struct { |
| matches []db.TeamMatch |
| notes []db.NotesData |
| shiftSchedule []db.Shift |
| driver_ranking []db.DriverRankingData |
| stats2023 []db.Stats2023 |
| stats2024 []db.Stats2024 |
| actions []db.Action |
| images []db.PitImage |
| } |
| |
| func (database *MockDatabase) AddToMatch(match db.TeamMatch) error { |
| database.matches = append(database.matches, match) |
| return nil |
| } |
| |
| func (database *MockDatabase) AddToStats2023(stats2023 db.Stats2023) error { |
| database.stats2023 = append(database.stats2023, stats2023) |
| return nil |
| } |
| |
| func (database *MockDatabase) AddToStats2024(stats2024 db.Stats2024) error { |
| database.stats2024 = append(database.stats2024, stats2024) |
| return nil |
| } |
| func (database *MockDatabase) ReturnMatches() ([]db.TeamMatch, error) { |
| return database.matches, nil |
| } |
| |
| func (database *MockDatabase) ReturnStats2023() ([]db.Stats2023, error) { |
| return database.stats2023, nil |
| } |
| |
| func (database *MockDatabase) ReturnStats2024() ([]db.Stats2024, error) { |
| return database.stats2024, nil |
| } |
| |
| func (database *MockDatabase) ReturnStats2023ForTeam(teamNumber string, matchNumber int32, setNumber int32, compLevel string, preScouting bool) ([]db.Stats2023, error) { |
| var results []db.Stats2023 |
| for _, stats := range database.stats2023 { |
| if stats.TeamNumber == teamNumber && stats.MatchNumber == matchNumber && stats.SetNumber == setNumber && stats.CompLevel == compLevel && stats.PreScouting == preScouting { |
| results = append(results, stats) |
| } |
| } |
| return results, nil |
| } |
| |
| func (database *MockDatabase) ReturnStats2024ForTeam(teamNumber string, matchNumber int32, setNumber int32, compLevel string, preScouting bool) ([]db.Stats2024, error) { |
| var results []db.Stats2024 |
| for _, stats := range database.stats2024 { |
| if stats.TeamNumber == teamNumber && stats.MatchNumber == matchNumber && stats.SetNumber == setNumber && stats.CompLevel == compLevel && stats.PreScouting == preScouting { |
| results = append(results, stats) |
| } |
| } |
| return results, nil |
| } |
| |
| func (database *MockDatabase) QueryNotes(requestedTeam string) ([]string, error) { |
| var results []string |
| for _, data := range database.notes { |
| if data.TeamNumber == requestedTeam { |
| results = append(results, data.Notes) |
| } |
| } |
| return results, nil |
| } |
| |
| func (database *MockDatabase) AddNotes(data db.NotesData) error { |
| database.notes = append(database.notes, data) |
| return nil |
| } |
| |
| func (database *MockDatabase) ReturnAllNotes() ([]db.NotesData, error) { |
| return database.notes, nil |
| } |
| |
| func (database *MockDatabase) AddToShift(data db.Shift) error { |
| database.shiftSchedule = append(database.shiftSchedule, data) |
| return nil |
| } |
| |
| func (database *MockDatabase) ReturnAllShifts() ([]db.Shift, error) { |
| return database.shiftSchedule, nil |
| } |
| |
| func (database *MockDatabase) QueryAllShifts(int) ([]db.Shift, error) { |
| return []db.Shift{}, nil |
| } |
| |
| func (database *MockDatabase) QueryPitImages(requestedTeam string) ([]db.RequestedPitImage, error) { |
| var results []db.RequestedPitImage |
| for _, data := range database.images { |
| if data.TeamNumber == requestedTeam { |
| results = append(results, db.RequestedPitImage{ |
| TeamNumber: data.TeamNumber, |
| ImagePath: data.ImagePath, |
| CheckSum: data.CheckSum, |
| }) |
| } |
| } |
| return results, nil |
| } |
| |
| func (database *MockDatabase) AddDriverRanking(data db.DriverRankingData) error { |
| database.driver_ranking = append(database.driver_ranking, data) |
| return nil |
| } |
| |
| func (database *MockDatabase) ReturnAllDriverRankings() ([]db.DriverRankingData, error) { |
| return database.driver_ranking, nil |
| } |
| |
| func (database *MockDatabase) AddAction(action db.Action) error { |
| database.actions = append(database.actions, action) |
| return nil |
| } |
| |
| func (database *MockDatabase) AddPitImage(pitImage db.PitImage) error { |
| database.images = append(database.images, pitImage) |
| return nil |
| } |
| |
| func (database *MockDatabase) ReturnActions() ([]db.Action, error) { |
| return database.actions, nil |
| } |
| |
| func (database *MockDatabase) ReturnPitImages() ([]db.PitImage, error) { |
| return database.images, nil |
| } |
| |
| func (database *MockDatabase) DeleteFromStats(compLevel_ string, matchNumber_ int32, setNumber_ int32, teamNumber_ string) error { |
| for i, stat := range database.stats2023 { |
| if stat.CompLevel == compLevel_ && |
| stat.MatchNumber == matchNumber_ && |
| stat.SetNumber == setNumber_ && |
| stat.TeamNumber == teamNumber_ { |
| // Match found, remove the element from the array. |
| database.stats2023 = append(database.stats2023[:i], database.stats2023[i+1:]...) |
| } |
| } |
| return nil |
| } |
| |
| func (database *MockDatabase) DeleteFromStats2024(compLevel_ string, matchNumber_ int32, setNumber_ int32, teamNumber_ string) error { |
| for i, stat := range database.stats2024 { |
| if stat.CompLevel == compLevel_ && |
| stat.MatchNumber == matchNumber_ && |
| stat.SetNumber == setNumber_ && |
| stat.TeamNumber == teamNumber_ { |
| // Match found, remove the element from the array. |
| database.stats2024 = append(database.stats2024[:i], database.stats2024[i+1:]...) |
| } |
| } |
| return nil |
| } |
| |
| func (database *MockDatabase) DeleteFromActions(compLevel_ string, matchNumber_ int32, setNumber_ int32, teamNumber_ string) error { |
| for i, action := range database.actions { |
| if action.CompLevel == compLevel_ && |
| action.MatchNumber == matchNumber_ && |
| action.SetNumber == setNumber_ && |
| action.TeamNumber == teamNumber_ { |
| // Match found, remove the element from the array. |
| database.actions = append(database.actions[:i], database.actions[i+1:]...) |
| } |
| } |
| return nil |
| } |