Scouting App: Add View data webserver

Add methods to return all Notes, Stats, and Driver Rankings.

Signed-off-by: Filip Kujawa <filip.j.kujawa@gmail.com>
Change-Id: I0cc8531c9aa34e8dbccf08cada9957272537024f
diff --git a/scouting/db/db.go b/scouting/db/db.go
index 55f2310..8a28db4 100644
--- a/scouting/db/db.go
+++ b/scouting/db/db.go
@@ -189,6 +189,18 @@
 	return matches, result.Error
 }
 
+func (database *Database) ReturnAllNotes() ([]NotesData, error) {
+	var notes []NotesData
+	result := database.Find(&notes)
+	return notes, result.Error
+}
+
+func (database *Database) ReturnAllDriverRankings() ([]DriverRankingData, error) {
+	var rankings []DriverRankingData
+	result := database.Find(&rankings)
+	return rankings, result.Error
+}
+
 func (database *Database) ReturnAllShifts() ([]Shift, error) {
 	var shifts []Shift
 	result := database.Find(&shifts)
diff --git a/scouting/webserver/requests/BUILD b/scouting/webserver/requests/BUILD
index 5c9ede4..53bc385 100644
--- a/scouting/webserver/requests/BUILD
+++ b/scouting/webserver/requests/BUILD
@@ -12,8 +12,12 @@
         "//scouting/webserver/requests/messages:error_response_go_fbs",
         "//scouting/webserver/requests/messages:refresh_match_list_go_fbs",
         "//scouting/webserver/requests/messages:refresh_match_list_response_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_driver_rankings_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_driver_rankings_response_go_fbs",
         "//scouting/webserver/requests/messages:request_all_matches_go_fbs",
         "//scouting/webserver/requests/messages:request_all_matches_response_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_notes_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
         "//scouting/webserver/requests/messages:request_data_scouting_go_fbs",
         "//scouting/webserver/requests/messages:request_data_scouting_response_go_fbs",
         "//scouting/webserver/requests/messages:request_matches_for_team_go_fbs",
@@ -47,8 +51,12 @@
         "//scouting/webserver/requests/messages:error_response_go_fbs",
         "//scouting/webserver/requests/messages:refresh_match_list_go_fbs",
         "//scouting/webserver/requests/messages:refresh_match_list_response_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_driver_rankings_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_driver_rankings_response_go_fbs",
         "//scouting/webserver/requests/messages:request_all_matches_go_fbs",
         "//scouting/webserver/requests/messages:request_all_matches_response_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_notes_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
         "//scouting/webserver/requests/messages:request_data_scouting_go_fbs",
         "//scouting/webserver/requests/messages:request_data_scouting_response_go_fbs",
         "//scouting/webserver/requests/messages:request_matches_for_team_go_fbs",
diff --git a/scouting/webserver/requests/debug/BUILD b/scouting/webserver/requests/debug/BUILD
index f826831..454d030 100644
--- a/scouting/webserver/requests/debug/BUILD
+++ b/scouting/webserver/requests/debug/BUILD
@@ -9,7 +9,9 @@
     deps = [
         "//scouting/webserver/requests/messages:error_response_go_fbs",
         "//scouting/webserver/requests/messages:refresh_match_list_response_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_driver_rankings_response_go_fbs",
         "//scouting/webserver/requests/messages:request_all_matches_response_go_fbs",
+        "//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
         "//scouting/webserver/requests/messages:request_data_scouting_response_go_fbs",
         "//scouting/webserver/requests/messages:request_matches_for_team_response_go_fbs",
         "//scouting/webserver/requests/messages:request_notes_for_team_response_go_fbs",
diff --git a/scouting/webserver/requests/debug/cli/cli_test.py b/scouting/webserver/requests/debug/cli/cli_test.py
index d4310e9..5cfeb61 100644
--- a/scouting/webserver/requests/debug/cli/cli_test.py
+++ b/scouting/webserver/requests/debug/cli/cli_test.py
@@ -141,6 +141,73 @@
             CompLevel: (string) (len=5) "quals"
             }"""), stdout)
 
+    def test_submit_and_request_notes(self):
+        self.refresh_match_list(year=2020, event_code="fake")
+
+        # First submit some data to be added to the database.
+        json_path = write_json_request({
+            "team": 100,
+            "notes": "A very inspiring and useful comment",
+            "good_driving": True,
+            "bad_driving": False,
+            "sketchy_climb": False,
+            "solid_climb": True,
+            "good_defense": False,
+            "bad_defense": False,
+        })
+        exit_code, _, stderr = run_debug_cli(["-submitNotes", json_path])
+        self.assertEqual(exit_code, 0, stderr)
+
+        # Now request the data back with zero indentation. That let's us
+        # validate the data easily.
+        json_path = write_json_request({})
+        exit_code, stdout, stderr = run_debug_cli(
+            ["-requestAllNotes", json_path, "-indent="])
+
+        self.assertEqual(exit_code, 0, stderr)
+        self.assertIn(
+            textwrap.dedent("""\
+            {
+            Team: (int32) 100,
+            Notes: (string) (len=35) "A very inspiring and useful comment",
+            GoodDriving: (bool) true,
+            BadDriving: (bool) false,
+            SketchyClimb: (bool) false,
+            SolidClimb: (bool) true,
+            GoodDefense: (bool) false,
+            BadDefense: (bool) false
+            }"""), stdout)
+
+    def test_submit_and_request_driver_ranking(self):
+        self.refresh_match_list(year=2020, event_code="fake")
+
+        # First submit some data to be added to the database.
+        json_path = write_json_request({
+            "matchNumber": 100,
+            "rank1": 101,
+            "rank2": 202,
+            "rank3": 303,
+        })
+        exit_code, _, stderr = run_debug_cli(
+            ["-submitDriverRanking", json_path])
+        self.assertEqual(exit_code, 0, stderr)
+
+        # Now request the data back with zero indentation. That let's us
+        # validate the data easily.
+        json_path = write_json_request({})
+        exit_code, stdout, stderr = run_debug_cli(
+            ["-requestAllDriverRankings", json_path, "-indent="])
+
+        self.assertEqual(exit_code, 0, stderr)
+        self.assertIn(
+            textwrap.dedent("""\
+            {
+            MatchNumber: (int32) 100,
+            Rank1: (int32) 101,
+            Rank2: (int32) 202,
+            Rank3: (int32) 303
+            }"""), stdout)
+
     def test_request_all_matches(self):
         self.refresh_match_list()
 
diff --git a/scouting/webserver/requests/debug/cli/main.go b/scouting/webserver/requests/debug/cli/main.go
index d338b5f..ec38270 100644
--- a/scouting/webserver/requests/debug/cli/main.go
+++ b/scouting/webserver/requests/debug/cli/main.go
@@ -85,12 +85,20 @@
 		"The end point where the server is listening.")
 	submitDataScoutingPtr := flag.String("submitDataScouting", "",
 		"If specified, parse the file as a SubmitDataScouting JSON request.")
+	submitDriverRankingPtr := flag.String("submitDriverRanking", "",
+		"If specified, parse the file as a submitDriverRanking JSON request.")
+	submitNotesPtr := flag.String("submitNotes", "",
+		"If specified, parse the file as a submitNotes JSON request.")
 	requestAllMatchesPtr := flag.String("requestAllMatches", "",
 		"If specified, parse the file as a RequestAllMatches JSON request.")
 	requestMatchesForTeamPtr := flag.String("requestMatchesForTeam", "",
 		"If specified, parse the file as a RequestMatchesForTeam JSON request.")
 	requestDataScoutingPtr := flag.String("requestDataScouting", "",
 		"If specified, parse the file as a RequestDataScouting JSON request.")
+	requestAllDriverRankingsPtr := flag.String("requestAllDriverRankings", "",
+		"If specified, parse the file as a requestAllDriverRankings JSON request.")
+	requestAllNotesPtr := flag.String("requestAllNotes", "",
+		"If specified, parse the file as a requestAllNotes JSON request.")
 	refreshMatchListPtr := flag.String("refreshMatchList", "",
 		"If specified, parse the file as a RefreshMatchList JSON request.")
 	flag.Parse()
@@ -109,6 +117,20 @@
 		debug.SubmitDataScouting)
 
 	maybePerformRequest(
+		"submitNotes",
+		"scouting/webserver/requests/messages/submit_notes.fbs",
+		*submitNotesPtr,
+		*addressPtr,
+		debug.SubmitNotes)
+
+	maybePerformRequest(
+		"submitDriverRanking",
+		"scouting/webserver/requests/messages/submit_driver_ranking.fbs",
+		*submitDriverRankingPtr,
+		*addressPtr,
+		debug.SubmitDriverRanking)
+
+	maybePerformRequest(
 		"RequestAllMatches",
 		"scouting/webserver/requests/messages/request_all_matches.fbs",
 		*requestAllMatchesPtr,
@@ -130,6 +152,20 @@
 		debug.RequestDataScouting)
 
 	maybePerformRequest(
+		"requestAllDriverRankings",
+		"scouting/webserver/requests/messages/request_all_driver_rankings.fbs",
+		*requestAllDriverRankingsPtr,
+		*addressPtr,
+		debug.RequestAllDriverRankings)
+
+	maybePerformRequest(
+		"requestAllNotes",
+		"scouting/webserver/requests/messages/request_all_notes.fbs",
+		*requestAllNotesPtr,
+		*addressPtr,
+		debug.RequestAllNotes)
+
+	maybePerformRequest(
 		"RefreshMatchList",
 		"scouting/webserver/requests/messages/refresh_match_list.fbs",
 		*refreshMatchListPtr,
diff --git a/scouting/webserver/requests/debug/debug.go b/scouting/webserver/requests/debug/debug.go
index fc0896c..08cf67c 100644
--- a/scouting/webserver/requests/debug/debug.go
+++ b/scouting/webserver/requests/debug/debug.go
@@ -11,7 +11,9 @@
 
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list_response"
+	"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_response"
+	"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_data_scouting_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
@@ -117,6 +119,12 @@
 		request_all_matches_response.GetRootAsRequestAllMatchesResponse)
 }
 
+func RequestAllDriverRankings(server string, requestBytes []byte) (*request_all_driver_rankings_response.RequestAllDriverRankingsResponseT, error) {
+	return sendMessage[request_all_driver_rankings_response.RequestAllDriverRankingsResponseT](
+		server+"/requests/request/all_driver_rankings", requestBytes,
+		request_all_driver_rankings_response.GetRootAsRequestAllDriverRankingsResponse)
+}
+
 func RequestMatchesForTeam(server string, requestBytes []byte) (*request_matches_for_team_response.RequestMatchesForTeamResponseT, error) {
 	return sendMessage[request_matches_for_team_response.RequestMatchesForTeamResponseT](
 		server+"/requests/request/matches_for_team", requestBytes,
@@ -147,6 +155,12 @@
 		request_notes_for_team_response.GetRootAsRequestNotesForTeamResponse)
 }
 
+func RequestAllNotes(server string, requestBytes []byte) (*request_all_notes_response.RequestAllNotesResponseT, error) {
+	return sendMessage[request_all_notes_response.RequestAllNotesResponseT](
+		server+"/requests/request/all_notes", requestBytes,
+		request_all_notes_response.GetRootAsRequestAllNotesResponse)
+}
+
 func RequestShiftSchedule(server string, requestBytes []byte) (*request_shift_schedule_response.RequestShiftScheduleResponseT, error) {
 	return sendMessage[request_shift_schedule_response.RequestShiftScheduleResponseT](
 		server+"/requests/request/shift_schedule", requestBytes,
diff --git a/scouting/webserver/requests/messages/BUILD b/scouting/webserver/requests/messages/BUILD
index c14a857..392ee80 100644
--- a/scouting/webserver/requests/messages/BUILD
+++ b/scouting/webserver/requests/messages/BUILD
@@ -5,8 +5,12 @@
     "error_response",
     "submit_data_scouting",
     "submit_data_scouting_response",
+    "request_all_driver_rankings",
+    "request_all_driver_rankings_response",
     "request_all_matches",
     "request_all_matches_response",
+    "request_all_notes",
+    "request_all_notes_response",
     "request_matches_for_team",
     "request_matches_for_team_response",
     "request_data_scouting",
diff --git a/scouting/webserver/requests/messages/request_all_driver_rankings.fbs b/scouting/webserver/requests/messages/request_all_driver_rankings.fbs
new file mode 100644
index 0000000..dbd51fb
--- /dev/null
+++ b/scouting/webserver/requests/messages/request_all_driver_rankings.fbs
@@ -0,0 +1,6 @@
+namespace scouting.webserver.requests;
+
+table RequestAllDriverRankings {
+}
+
+root_type RequestAllDriverRankings;
diff --git a/scouting/webserver/requests/messages/request_all_driver_rankings_response.fbs b/scouting/webserver/requests/messages/request_all_driver_rankings_response.fbs
new file mode 100644
index 0000000..dcc9712
--- /dev/null
+++ b/scouting/webserver/requests/messages/request_all_driver_rankings_response.fbs
@@ -0,0 +1,14 @@
+namespace scouting.webserver.requests;
+
+table Ranking {
+    matchNumber:int (id: 0);
+    rank1:int (id: 1);
+    rank2:int (id: 2);
+    rank3:int (id: 3);
+}
+
+table RequestAllDriverRankingsResponse {
+    driver_ranking_list:[Ranking] (id:0);
+}
+
+root_type RequestAllDriverRankingsResponse;
diff --git a/scouting/webserver/requests/messages/request_all_notes.fbs b/scouting/webserver/requests/messages/request_all_notes.fbs
new file mode 100644
index 0000000..f89e0c4
--- /dev/null
+++ b/scouting/webserver/requests/messages/request_all_notes.fbs
@@ -0,0 +1,6 @@
+namespace scouting.webserver.requests;
+
+table RequestAllNotes {
+}
+
+root_type RequestAllNotes;
diff --git a/scouting/webserver/requests/messages/request_all_notes_response.fbs b/scouting/webserver/requests/messages/request_all_notes_response.fbs
new file mode 100644
index 0000000..a69861b
--- /dev/null
+++ b/scouting/webserver/requests/messages/request_all_notes_response.fbs
@@ -0,0 +1,18 @@
+namespace scouting.webserver.requests;
+
+table Note {
+    team:int (id: 0);
+    notes:string (id: 1);
+    good_driving:bool (id: 2);
+    bad_driving:bool (id: 3);
+    sketchy_climb:bool (id: 4);
+    solid_climb:bool (id: 5);
+    good_defense:bool (id: 6);
+    bad_defense:bool (id: 7);
+}
+
+table RequestAllNotesResponse {
+    note_list:[Note] (id:0);
+}
+
+root_type RequestAllNotesResponse;
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index 12bc3da..a7f1a77 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -15,8 +15,12 @@
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list_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_data_scouting"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_data_scouting_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team"
@@ -41,6 +45,10 @@
 type SubmitDataScoutingResponseT = submit_data_scouting_response.SubmitDataScoutingResponseT
 type RequestAllMatches = request_all_matches.RequestAllMatches
 type RequestAllMatchesResponseT = request_all_matches_response.RequestAllMatchesResponseT
+type RequestAllDriverRankings = request_all_driver_rankings.RequestAllDriverRankings
+type RequestAllDriverRankingsResponseT = request_all_driver_rankings_response.RequestAllDriverRankingsResponseT
+type RequestAllNotes = request_all_notes.RequestAllNotes
+type RequestAllNotesResponseT = request_all_notes_response.RequestAllNotesResponseT
 type RequestMatchesForTeam = request_matches_for_team.RequestMatchesForTeam
 type RequestMatchesForTeamResponseT = request_matches_for_team_response.RequestMatchesForTeamResponseT
 type RequestDataScouting = request_data_scouting.RequestDataScouting
@@ -65,6 +73,8 @@
 	AddToShift(db.Shift) error
 	AddToStats(db.Stats) error
 	ReturnMatches() ([]db.Match, error)
+	ReturnAllNotes() ([]db.NotesData, error)
+	ReturnAllDriverRankings() ([]db.DriverRankingData, error)
 	ReturnAllShifts() ([]db.Shift, error)
 	ReturnStats() ([]db.Stats, error)
 	QueryMatches(int32) ([]db.Match, error)
@@ -647,10 +657,90 @@
 	w.Write(builder.FinishedBytes())
 }
 
+type requestAllNotesHandler struct {
+	db Database
+}
+
+func (handler requestAllNotesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+	requestBytes, err := io.ReadAll(req.Body)
+	if err != nil {
+		respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
+		return
+	}
+
+	_, success := parseRequest(w, requestBytes, "RequestAllNotes", request_all_notes.GetRootAsRequestAllNotes)
+	if !success {
+		return
+	}
+
+	notes, err := handler.db.ReturnAllNotes()
+	if err != nil {
+		respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
+		return
+	}
+
+	var response RequestAllNotesResponseT
+	for _, note := range notes {
+		response.NoteList = append(response.NoteList, &request_all_notes_response.NoteT{
+			Team:         note.TeamNumber,
+			Notes:        note.Notes,
+			GoodDriving:  note.GoodDriving,
+			BadDriving:   note.BadDriving,
+			SketchyClimb: note.SketchyClimb,
+			SolidClimb:   note.SolidClimb,
+			GoodDefense:  note.GoodDefense,
+			BadDefense:   note.BadDefense,
+		})
+	}
+
+	builder := flatbuffers.NewBuilder(50 * 1024)
+	builder.Finish((&response).Pack(builder))
+	w.Write(builder.FinishedBytes())
+}
+
+type requestAllDriverRankingsHandler struct {
+	db Database
+}
+
+func (handler requestAllDriverRankingsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+	requestBytes, err := io.ReadAll(req.Body)
+	if err != nil {
+		respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
+		return
+	}
+
+	_, success := parseRequest(w, requestBytes, "RequestAllDriverRankings", request_all_driver_rankings.GetRootAsRequestAllDriverRankings)
+	if !success {
+		return
+	}
+
+	rankings, err := handler.db.ReturnAllDriverRankings()
+	if err != nil {
+		respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Failed to query database: ", err))
+		return
+	}
+
+	var response RequestAllDriverRankingsResponseT
+	for _, ranking := range rankings {
+		response.DriverRankingList = append(response.DriverRankingList, &request_all_driver_rankings_response.RankingT{
+			MatchNumber: ranking.MatchNumber,
+			Rank1:       ranking.Rank1,
+			Rank2:       ranking.Rank2,
+			Rank3:       ranking.Rank3,
+		})
+	}
+
+	builder := flatbuffers.NewBuilder(50 * 1024)
+	builder.Finish((&response).Pack(builder))
+	w.Write(builder.FinishedBytes())
+}
+
 func HandleRequests(db Database, scrape ScrapeMatchList, scoutingServer server.ScoutingServer) {
 	scoutingServer.HandleFunc("/requests", unknown)
 	scoutingServer.Handle("/requests/submit/data_scouting", submitDataScoutingHandler{db})
 	scoutingServer.Handle("/requests/request/all_matches", requestAllMatchesHandler{db})
+	scoutingServer.Handle("/requests/request/all_notes", requestAllNotesHandler{db})
+	scoutingServer.Handle("/requests/request/all_driver_rankings", requestAllDriverRankingsHandler{db})
 	scoutingServer.Handle("/requests/request/matches_for_team", requestMatchesForTeamHandler{db})
 	scoutingServer.Handle("/requests/request/data_scouting", requestDataScoutingHandler{db})
 	scoutingServer.Handle("/requests/refresh_match_list", refreshMatchListHandler{db, scrape})
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index 55b789b..ed8a3b5 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -13,8 +13,12 @@
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/error_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list_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_data_scouting"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_data_scouting_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_matches_for_team"
@@ -590,6 +594,136 @@
 	}
 }
 
+// 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, scrapeEmtpyMatchList, 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,
+				SketchyClimb: true,
+				SolidClimb:   false,
+				GoodDefense:  true,
+				BadDefense:   false,
+			},
+			{
+				TeamNumber:   972,
+				Notes:        "More Notes",
+				GoodDriving:  false,
+				BadDriving:   false,
+				SketchyClimb: false,
+				SolidClimb:   true,
+				GoodDefense:  false,
+				BadDefense:   true,
+			},
+		},
+	}
+	scoutingServer := server.NewScoutingServer()
+	HandleRequests(&db, scrapeEmtpyMatchList, 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,
+				SketchyClimb: true,
+				SolidClimb:   false,
+				GoodDefense:  true,
+				BadDefense:   false,
+			},
+			{
+				Team:         972,
+				Notes:        "More Notes",
+				GoodDriving:  false,
+				BadDriving:   false,
+				SketchyClimb: false,
+				SolidClimb:   true,
+				GoodDefense:  false,
+				BadDefense:   true,
+			},
+		},
+	}
+	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])
+		}
+	}
+}
+
 // A mocked database we can use for testing. Add functionality to this as
 // needed for your tests.
 
@@ -651,6 +785,10 @@
 	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
@@ -669,6 +807,10 @@
 	return nil
 }
 
+func (database *MockDatabase) ReturnAllDriverRankings() ([]db.DriverRankingData, error) {
+	return database.driver_ranking, nil
+}
+
 // Returns an empty match list from the fake The Blue Alliance scraping.
 func scrapeEmtpyMatchList(int32, string) ([]scraping.Match, error) {
 	return nil, nil