blob: f6a06b9a0c3ba6c24ea36ea830c70f599aecbe2c [file] [log] [blame]
Philipp Schradercdb5cfc2022-02-20 14:57:07 -08001package requests
2
3import (
4 "bytes"
5 "io"
6 "net/http"
Philipp Schradercbf5c6a2022-02-27 23:25:19 -08007 "reflect"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -08008 "testing"
9
Philipp Schrader8747f1b2022-02-23 23:56:22 -080010 "github.com/frc971/971-Robot-Code/scouting/db"
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080011 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/debug"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080012 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080013 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches"
14 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
Philipp Schraderd1c4bef2022-02-28 22:51:30 -080015 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team"
16 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team_response"
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080017 "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting"
18 _ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting_response"
19 "github.com/frc971/971-Robot-Code/scouting/webserver/server"
20 flatbuffers "github.com/google/flatbuffers/go"
21)
22
23// Validates that an unhandled address results in a 404.
24func Test404(t *testing.T) {
Philipp Schrader8747f1b2022-02-23 23:56:22 -080025 db := MockDatabase{}
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080026 scoutingServer := server.NewScoutingServer()
Philipp Schrader8747f1b2022-02-23 23:56:22 -080027 HandleRequests(&db, scoutingServer)
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080028 scoutingServer.Start(8080)
29 defer scoutingServer.Stop()
30
31 resp, err := http.Get("http://localhost:8080/requests/foo")
32 if err != nil {
33 t.Fatalf("Failed to get data: %v", err)
34 }
35 if resp.StatusCode != http.StatusNotFound {
36 t.Fatalf("Expected error code 404, but got %d instead", resp.Status)
37 }
38}
39
40// Validates that we can submit new data scouting data.
41func TestSubmitDataScoutingError(t *testing.T) {
Philipp Schrader8747f1b2022-02-23 23:56:22 -080042 db := MockDatabase{}
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080043 scoutingServer := server.NewScoutingServer()
Philipp Schrader8747f1b2022-02-23 23:56:22 -080044 HandleRequests(&db, scoutingServer)
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080045 scoutingServer.Start(8080)
46 defer scoutingServer.Stop()
47
48 resp, err := http.Post("http://localhost:8080/requests/submit/data_scouting", "application/octet-stream", bytes.NewReader([]byte("")))
49 if err != nil {
50 t.Fatalf("Failed to send request: %v", err)
51 }
52 if resp.StatusCode != http.StatusBadRequest {
53 t.Fatal("Unexpected status code. Got", resp.Status)
54 }
55
56 responseBytes, err := io.ReadAll(resp.Body)
57 if err != nil {
58 t.Fatal("Failed to read response bytes:", err)
59 }
60 errorResponse := error_response.GetRootAsErrorResponse(responseBytes, 0)
61
62 errorMessage := string(errorResponse.ErrorMessage())
63 if errorMessage != "Failed to parse SubmitDataScouting: runtime error: index out of range [3] with length 0" {
64 t.Fatal("Got mismatched error message:", errorMessage)
65 }
66}
67
68// Validates that we can submit new data scouting data.
69func TestSubmitDataScouting(t *testing.T) {
Philipp Schrader8747f1b2022-02-23 23:56:22 -080070 db := MockDatabase{}
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080071 scoutingServer := server.NewScoutingServer()
Philipp Schrader8747f1b2022-02-23 23:56:22 -080072 HandleRequests(&db, scoutingServer)
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080073 scoutingServer.Start(8080)
74 defer scoutingServer.Stop()
75
76 builder := flatbuffers.NewBuilder(1024)
77 builder.Finish((&submit_data_scouting.SubmitDataScoutingT{
Sabina Leavere66c2fc2022-02-24 16:56:15 -080078 Team: 971,
79 Match: 1,
80 MissedShotsAuto: 9971,
81 UpperGoalAuto: 9971,
82 LowerGoalAuto: 9971,
83 MissedShotsTele: 9971,
84 UpperGoalTele: 9971,
85 LowerGoalTele: 9971,
86 DefenseRating: 9971,
87 Climbing: 9971,
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080088 }).Pack(builder))
89
90 resp, err := http.Post("http://localhost:8080/requests/submit/data_scouting", "application/octet-stream", bytes.NewReader(builder.FinishedBytes()))
91 if err != nil {
92 t.Fatalf("Failed to send request: %v", err)
93 }
94 if resp.StatusCode != http.StatusNotImplemented {
95 t.Fatal("Unexpected status code. Got", resp.Status)
96 }
97 // TODO(phil): We have nothing to validate yet. Fix that.
Philipp Schraderd9096a32022-02-24 17:53:09 -080098 // TODO(phil): Can we use scouting/webserver/requests/debug here?
Philipp Schradercdb5cfc2022-02-20 14:57:07 -080099}
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800100
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800101// Validates that we can request the full match list.
102func TestRequestAllMatches(t *testing.T) {
103 db := MockDatabase{
104 matches: []db.Match{
105 {
106 MatchNumber: 1, Round: 1, CompLevel: "qual",
107 R1: 5, R2: 42, R3: 600, B1: 971, B2: 400, B3: 200,
108 },
109 {
110 MatchNumber: 2, Round: 1, CompLevel: "qual",
111 R1: 6, R2: 43, R3: 601, B1: 972, B2: 401, B3: 201,
112 },
113 {
114 MatchNumber: 3, Round: 1, CompLevel: "qual",
115 R1: 7, R2: 44, R3: 602, B1: 973, B2: 402, B3: 202,
116 },
117 },
118 }
119 scoutingServer := server.NewScoutingServer()
120 HandleRequests(&db, scoutingServer)
121 scoutingServer.Start(8080)
122 defer scoutingServer.Stop()
123
124 builder := flatbuffers.NewBuilder(1024)
125 builder.Finish((&request_all_matches.RequestAllMatchesT{}).Pack(builder))
126
127 response, err := debug.RequestAllMatches("http://localhost:8080", builder.FinishedBytes())
128 if err != nil {
129 t.Fatal("Failed to request all matches: ", err)
130 }
131
132 expected := request_all_matches_response.RequestAllMatchesResponseT{
133 MatchList: []*request_all_matches_response.MatchT{
134 // MatchNumber, Round, CompLevel
135 // R1, R2, R3, B1, B2, B3
136 {
137 1, 1, "qual",
138 5, 42, 600, 971, 400, 200,
139 },
140 {
141 2, 1, "qual",
142 6, 43, 601, 972, 401, 201,
143 },
144 {
145 3, 1, "qual",
146 7, 44, 602, 973, 402, 202,
147 },
148 },
149 }
150 if len(expected.MatchList) != len(response.MatchList) {
151 t.Fatal("Expected ", expected, ", but got ", *response)
152 }
153 for i, match := range expected.MatchList {
154 if !reflect.DeepEqual(*match, *response.MatchList[i]) {
155 t.Fatal("Expected for match", i, ":", *match, ", but got:", *response.MatchList[i])
156 }
157 }
158}
159
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800160// Validates that we can request the full match list.
161func TestRequestMatchesForTeam(t *testing.T) {
162 db := MockDatabase{
163 matches: []db.Match{
164 {
165 MatchNumber: 1, Round: 1, CompLevel: "qual",
166 R1: 5, R2: 42, R3: 600, B1: 971, B2: 400, B3: 200,
167 },
168 {
169 MatchNumber: 2, Round: 1, CompLevel: "qual",
170 R1: 6, R2: 43, R3: 601, B1: 972, B2: 401, B3: 201,
171 },
172 },
173 }
174 scoutingServer := server.NewScoutingServer()
175 HandleRequests(&db, scoutingServer)
176 scoutingServer.Start(8080)
177 defer scoutingServer.Stop()
178
179 builder := flatbuffers.NewBuilder(1024)
180 builder.Finish((&request_matches_for_team.RequestMatchesForTeamT{
181 Team: 971,
182 }).Pack(builder))
183
184 response, err := debug.RequestMatchesForTeam("http://localhost:8080", builder.FinishedBytes())
185 if err != nil {
186 t.Fatal("Failed to request all matches: ", err)
187 }
188
189 expected := request_matches_for_team_response.RequestMatchesForTeamResponseT{
190 MatchList: []*request_matches_for_team_response.MatchT{
191 // MatchNumber, Round, CompLevel
192 // R1, R2, R3, B1, B2, B3
193 {
194 1, 1, "qual",
195 5, 42, 600, 971, 400, 200,
196 },
197 },
198 }
199 if len(expected.MatchList) != len(response.MatchList) {
200 t.Fatal("Expected ", expected, ", but got ", *response)
201 }
202 for i, match := range expected.MatchList {
203 if !reflect.DeepEqual(*match, *response.MatchList[i]) {
204 t.Fatal("Expected for match", i, ":", *match, ", but got:", *response.MatchList[i])
205 }
206 }
207}
208
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800209// A mocked database we can use for testing. Add functionality to this as
210// needed for your tests.
211
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800212type MockDatabase struct {
213 matches []db.Match
214}
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800215
216func (database *MockDatabase) AddToMatch(db.Match) error {
217 return nil
218}
219
220func (database *MockDatabase) AddToStats(db.Stats) error {
221 return nil
222}
223
224func (database *MockDatabase) ReturnMatches() ([]db.Match, error) {
Philipp Schradercbf5c6a2022-02-27 23:25:19 -0800225 return database.matches, nil
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800226}
227
228func (database *MockDatabase) ReturnStats() ([]db.Stats, error) {
229 return []db.Stats{}, nil
230}
231
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800232func (database *MockDatabase) QueryMatches(requestedTeam int32) ([]db.Match, error) {
233 var matches []db.Match
234 for _, match := range database.matches {
235 for _, team := range []int32{match.R1, match.R2, match.R3, match.B1, match.B2, match.B3} {
236 if team == requestedTeam {
237 matches = append(matches, match)
238 break
239 }
240 }
241 }
242 return matches, nil
Philipp Schrader8747f1b2022-02-23 23:56:22 -0800243}
244
245func (database *MockDatabase) QueryStats(int) ([]db.Stats, error) {
246 return []db.Stats{}, nil
247}