diff --git a/internal/api/handlers/channels_test.go b/internal/api/handlers/channels_test.go new file mode 100644 index 0000000..de066c3 --- /dev/null +++ b/internal/api/handlers/channels_test.go @@ -0,0 +1,108 @@ +package handlers + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-chi/chi/v5" +) + +func TestListChannels_InvalidLimit(t *testing.T) { + r := chi.NewRouter() + r.Get("/channels", listChannels(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/channels?limit=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListChannels_InvalidCursor(t *testing.T) { + r := chi.NewRouter() + r.Get("/channels", listChannels(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/channels?cursor=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListChannels_InvalidHash(t *testing.T) { + r := chi.NewRouter() + r.Get("/channels", listChannels(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/channels?hash=nothex!!", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListChannels_HashNotSingleByte(t *testing.T) { + r := chi.NewRouter() + r.Get("/channels", listChannels(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/channels?hash=aabb", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestGetChannel_InvalidID(t *testing.T) { + r := chi.NewRouter() + r.Get("/channels/{channelID}", getChannel(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/channels/notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListChannelMessages_InvalidChannelID(t *testing.T) { + r := chi.NewRouter() + r.Get("/channels/{channelID}/messages", listChannelMessages(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/channels/notanint/messages", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListChannelMessages_InvalidLimit(t *testing.T) { + r := chi.NewRouter() + r.Get("/channels/{channelID}/messages", listChannelMessages(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/channels/1/messages?limit=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListChannelMessages_InvalidSince(t *testing.T) { + r := chi.NewRouter() + r.Get("/channels/{channelID}/messages", listChannelMessages(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/channels/1/messages?since=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListChannelMessages_InvalidCursor(t *testing.T) { + r := chi.NewRouter() + r.Get("/channels/{channelID}/messages", listChannelMessages(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/channels/1/messages?cursor=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} diff --git a/internal/api/handlers/nodes_test.go b/internal/api/handlers/nodes_test.go new file mode 100644 index 0000000..eb087d1 --- /dev/null +++ b/internal/api/handlers/nodes_test.go @@ -0,0 +1,119 @@ +package handlers + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-chi/chi/v5" +) + +func TestGetNode_InvalidUUID(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes/{nodeId}", getNode(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes/not-a-uuid", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListNodeObservations_InvalidUUID(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes/{nodeId}/observations", listNodeObservations(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes/bad/observations", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListNodeObservations_InvalidCursor(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes/{nodeId}/observations", listNodeObservations(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes/00000000-0000-0000-0000-000000000001/observations?cursor=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListNodeObservations_InvalidLimit(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes/{nodeId}/observations", listNodeObservations(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes/00000000-0000-0000-0000-000000000001/observations?limit=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListNodes_InvalidType(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes", listNodes(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes?type=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListNodes_InvalidLimit(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes", listNodes(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes?limit=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListNodes_InvalidCursor(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes", listNodes(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes?cursor=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListNodes_InvalidPubkey(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes", listNodes(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes?pubkey=nothex!!", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListNodes_InvalidSupportsMultibytePaths(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes", listNodes(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes?supportsMultibytePaths=notabool", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListNodes_InvalidSupportsMultibyteTraces(t *testing.T) { + r := chi.NewRouter() + r.Get("/nodes", listNodes(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/nodes?supportsMultibyteTraces=notabool", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} diff --git a/internal/api/handlers/packets_test.go b/internal/api/handlers/packets_test.go new file mode 100644 index 0000000..1a5d4ce --- /dev/null +++ b/internal/api/handlers/packets_test.go @@ -0,0 +1,119 @@ +package handlers + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-chi/chi/v5" +) + +func TestGetPacket_InvalidHex(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets/{packetHash}", getPacket(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets/nothex!!", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListPackets_InvalidPayloadType(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets", listPackets(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets?payloadType=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListPackets_InvalidRouteType(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets", listPackets(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets?routeType=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListPackets_InvalidSince(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets", listPackets(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets?since=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListPackets_InvalidUntil(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets", listPackets(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets?until=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListPackets_InvalidCursor(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets", listPackets(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets?cursor=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListPackets_InvalidLimit(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets", listPackets(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets?limit=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListPacketsBackfill_MissingAfterID(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets/backfill", listPacketsBackfill(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets/backfill", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListPacketsBackfill_InvalidAfterID(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets/backfill", listPacketsBackfill(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets/backfill?afterObservationId=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} + +func TestListPacketsBackfill_InvalidLimit(t *testing.T) { + r := chi.NewRouter() + r.Get("/packets/backfill", listPacketsBackfill(stubReader{})) + req := httptest.NewRequest(http.MethodGet, "/packets/backfill?afterObservationId=1&limit=notanint", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("expected 400, got %d", w.Code) + } +} diff --git a/internal/api/handlers/routes_test.go b/internal/api/handlers/routes_test.go new file mode 100644 index 0000000..19e85be --- /dev/null +++ b/internal/api/handlers/routes_test.go @@ -0,0 +1,55 @@ +package handlers + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-chi/chi/v5" +) + +func TestSearchKnownRoutes_MissingParams(t *testing.T) { + r := chi.NewRouter() + r.Get("/routes/search", searchKnownRoutes(stubReader{})) + + tests := []struct { + name string + query string + }{ + {"missing all", ""}, + {"missing from and to", "?iata=YVR"}, + {"missing to", "?iata=YVR&from=aa"}, + {"missing iata", "?from=aa&to=bb"}, + } + for _, tt := range tests { + req := httptest.NewRequest(http.MethodGet, "/routes/search"+tt.query, nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("%s: expected 400, got %d", tt.name, w.Code) + } + } +} + +func TestSearchCrossIATARoutes_MissingParams(t *testing.T) { + r := chi.NewRouter() + r.Get("/routes/cross", searchCrossIATARoutes(stubReader{})) + + tests := []struct { + name string + query string + }{ + {"missing all", ""}, + {"missing toHash and toIata", "?fromHash=aa&fromIata=YVR"}, + {"missing fromIata", "?fromHash=aa&toHash=bb&toIata=YYJ"}, + {"missing fromHash", "?fromIata=YVR&toHash=bb&toIata=YYJ"}, + } + for _, tt := range tests { + req := httptest.NewRequest(http.MethodGet, "/routes/cross"+tt.query, nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + if w.Code != http.StatusBadRequest { + t.Errorf("%s: expected 400, got %d", tt.name, w.Code) + } + } +}