mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-05-13 07:55:41 +00:00
test(#1188): red — /api/packets must return observer_iata per row
Adds three tests asserting the API surfaces observer_iata on:
- ungrouped /api/packets rows
- grouped /api/packets?groupByHash=true rows
- per-observation entries in /api/packets/{id} detail response
Currently fails: the SQL joins select obs.id, obs.name but not obs.iata.
Fixing the join in cmd/server/db.go is the green commit.
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
// Test (#1188): /api/packets response must include observer_iata per packet
|
||||
// so the frontend can render the IATA inline without per-row observer lookups.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestPacketsEndpointIncludesObserverIATA asserts the ungrouped packets endpoint
|
||||
// surfaces the joined observer's IATA on each packet row.
|
||||
func TestPacketsEndpointIncludesObserverIATA(t *testing.T) {
|
||||
_, router := setupTestServer(t)
|
||||
req := httptest.NewRequest("GET", "/api/packets?limit=10", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != 200 {
|
||||
t.Fatalf("expected 200, got %d", w.Code)
|
||||
}
|
||||
var body map[string]interface{}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
|
||||
t.Fatalf("invalid JSON: %v", err)
|
||||
}
|
||||
packets, ok := body["packets"].([]interface{})
|
||||
if !ok || len(packets) == 0 {
|
||||
t.Fatal("expected non-empty packets array")
|
||||
}
|
||||
|
||||
// Seeded observers: obs1 → SJC, obs2 → SFO. At least one packet row
|
||||
// must carry a non-empty observer_iata string.
|
||||
gotIATA := false
|
||||
for _, p := range packets {
|
||||
m, _ := p.(map[string]interface{})
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
if _, present := m["observer_iata"]; !present {
|
||||
t.Fatalf("packet missing observer_iata field; got keys: %v", keysOfMap(m))
|
||||
}
|
||||
if s, _ := m["observer_iata"].(string); s != "" {
|
||||
gotIATA = true
|
||||
}
|
||||
}
|
||||
if !gotIATA {
|
||||
t.Fatalf("expected at least one packet with non-empty observer_iata (seed has SJC/SFO)")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPacketsGroupedIncludesObserverIATA asserts the grouped (groupByHash)
|
||||
// view also surfaces observer_iata for the header row.
|
||||
func TestPacketsGroupedIncludesObserverIATA(t *testing.T) {
|
||||
_, router := setupTestServer(t)
|
||||
req := httptest.NewRequest("GET", "/api/packets?groupByHash=true&limit=10", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != 200 {
|
||||
t.Fatalf("expected 200, got %d", w.Code)
|
||||
}
|
||||
var body map[string]interface{}
|
||||
json.Unmarshal(w.Body.Bytes(), &body)
|
||||
packets, _ := body["packets"].([]interface{})
|
||||
if len(packets) == 0 {
|
||||
t.Fatal("expected non-empty grouped packets")
|
||||
}
|
||||
gotIATA := false
|
||||
for _, p := range packets {
|
||||
m, _ := p.(map[string]interface{})
|
||||
if _, present := m["observer_iata"]; !present {
|
||||
t.Fatalf("grouped packet missing observer_iata field; got keys: %v", keysOfMap(m))
|
||||
}
|
||||
if s, _ := m["observer_iata"].(string); s != "" {
|
||||
gotIATA = true
|
||||
}
|
||||
}
|
||||
if !gotIATA {
|
||||
t.Fatalf("expected at least one grouped packet with non-empty observer_iata")
|
||||
}
|
||||
}
|
||||
|
||||
// TestPacketDetailObservationsIncludeIATA asserts /api/packets/{id} returns
|
||||
// per-observation observer_iata so the detail pane can render it.
|
||||
func TestPacketDetailObservationsIncludeIATA(t *testing.T) {
|
||||
_, router := setupTestServer(t)
|
||||
// transmission_id 1 has two observations (obs1 SJC, obs2 SFO) from seedTestData
|
||||
req := httptest.NewRequest("GET", "/api/packets/1", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
if w.Code != 200 {
|
||||
t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
var body map[string]interface{}
|
||||
json.Unmarshal(w.Body.Bytes(), &body)
|
||||
obs, _ := body["observations"].([]interface{})
|
||||
if len(obs) == 0 {
|
||||
t.Fatalf("expected observations in detail response; body: %s", w.Body.String())
|
||||
}
|
||||
gotIATA := false
|
||||
for _, o := range obs {
|
||||
m, _ := o.(map[string]interface{})
|
||||
if _, present := m["observer_iata"]; !present {
|
||||
t.Fatalf("observation missing observer_iata field; got keys: %v", keysOfMap(m))
|
||||
}
|
||||
if s, _ := m["observer_iata"].(string); s != "" {
|
||||
gotIATA = true
|
||||
}
|
||||
}
|
||||
if !gotIATA {
|
||||
t.Fatalf("expected at least one observation with non-empty observer_iata")
|
||||
}
|
||||
}
|
||||
|
||||
func keysOfMap(m map[string]interface{}) []string {
|
||||
out := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
out = append(out, k)
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user