feat(platform): filter vehicle rows by service status
This commit is contained in:
@@ -49,6 +49,22 @@ func TestHandlerVehicles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHandlerVehiclesFiltersServiceStatus(t *testing.T) {
|
||||||
|
handler := NewHandler(NewService(NewMockStore()))
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/api/vehicles?limit=10&serviceStatus=degraded", nil)
|
||||||
|
handler.ServeHTTP(rec, req)
|
||||||
|
if rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("status = %d body=%s", rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
if !strings.Contains(rec.Body.String(), "LB9A32A24R0LS1426") {
|
||||||
|
t.Fatalf("degraded vehicles should include partially online vehicle: %s", rec.Body.String())
|
||||||
|
}
|
||||||
|
if strings.Contains(rec.Body.String(), "LMRKH9AC2R1004087") {
|
||||||
|
t.Fatalf("degraded vehicles should exclude healthy vehicle: %s", rec.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHandlerVehicleCoverage(t *testing.T) {
|
func TestHandlerVehicleCoverage(t *testing.T) {
|
||||||
handler := NewHandler(NewService(NewMockStore()))
|
handler := NewHandler(NewService(NewMockStore()))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
|||||||
@@ -61,10 +61,14 @@ func (m *MockStore) DashboardSummary(context.Context) (DashboardSummary, error)
|
|||||||
|
|
||||||
func (m *MockStore) Vehicles(_ context.Context, query url.Values) (Page[VehicleRow], error) {
|
func (m *MockStore) Vehicles(_ context.Context, query url.Values) (Page[VehicleRow], error) {
|
||||||
items := filterVehicles(m.vehicles, query)
|
items := filterVehicles(m.vehicles, query)
|
||||||
for index := range items {
|
enriched := make([]VehicleRow, 0, len(items))
|
||||||
items[index].ServiceStatus = m.vehicleRowServiceStatus(items[index])
|
for _, item := range items {
|
||||||
|
item.ServiceStatus = m.vehicleRowServiceStatus(item)
|
||||||
|
if keepServiceStatus(item.ServiceStatus, query.Get("serviceStatus")) {
|
||||||
|
enriched = append(enriched, item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return page(items, query), nil
|
return page(enriched, query), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockStore) vehicleRowServiceStatus(row VehicleRow) *VehicleServiceStatus {
|
func (m *MockStore) vehicleRowServiceStatus(row VehicleRow) *VehicleServiceStatus {
|
||||||
|
|||||||
@@ -27,6 +27,16 @@ func buildVehicleListSQL(query url.Values) SQLQuery {
|
|||||||
where = append(where, "s.protocol = ?")
|
where = append(where, "s.protocol = ?")
|
||||||
args = append(args, protocol)
|
args = append(args, protocol)
|
||||||
}
|
}
|
||||||
|
switch strings.TrimSpace(query.Get("serviceStatus")) {
|
||||||
|
case "identity_required":
|
||||||
|
where = append(where, "(b.vin IS NULL OR b.vin = '')")
|
||||||
|
case "offline":
|
||||||
|
where = append(where, "b.vin IS NOT NULL", "b.vin <> ''", "COALESCE(vs.source_count, 0) > 0", "COALESCE(vs.online_source_count, 0) = 0")
|
||||||
|
case "degraded":
|
||||||
|
where = append(where, "b.vin IS NOT NULL", "b.vin <> ''", "vs.source_count > 0", "vs.online_source_count > 0", "vs.online_source_count < vs.source_count")
|
||||||
|
case "healthy":
|
||||||
|
where = append(where, "b.vin IS NOT NULL", "b.vin <> ''", "vs.source_count > 0", "vs.online_source_count = vs.source_count")
|
||||||
|
}
|
||||||
countArgs := append([]any(nil), args...)
|
countArgs := append([]any(nil), args...)
|
||||||
args = append(args, limit, offset)
|
args = append(args, limit, offset)
|
||||||
fromSQL := `FROM vehicle_realtime_snapshot s ` +
|
fromSQL := `FROM vehicle_realtime_snapshot s ` +
|
||||||
|
|||||||
@@ -26,6 +26,23 @@ func TestBuildVehicleListSQL(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildVehicleListSQLFiltersServiceStatus(t *testing.T) {
|
||||||
|
query := url.Values{"serviceStatus": {"degraded"}, "limit": {"8"}}
|
||||||
|
built := buildVehicleListSQL(query)
|
||||||
|
for _, want := range []string{
|
||||||
|
"vs.source_count > 0",
|
||||||
|
"vs.online_source_count > 0",
|
||||||
|
"vs.online_source_count < vs.source_count",
|
||||||
|
} {
|
||||||
|
if !strings.Contains(built.Text, want) {
|
||||||
|
t.Fatalf("SQL missing vehicle list service status predicate %q: %s", want, built.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !strings.Contains(built.CountText, "vs.source_count > 0") || !strings.Contains(built.CountText, "vs.online_source_count < vs.source_count") {
|
||||||
|
t.Fatalf("count SQL should include vehicle list service status predicate: %s", built.CountText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBuildVehicleCoverageSQL(t *testing.T) {
|
func TestBuildVehicleCoverageSQL(t *testing.T) {
|
||||||
query := url.Values{"keyword": {"粤A"}, "protocol": {"GB32960"}, "coverage": {"multi"}, "online": {"online"}, "bindingStatus": {"bound"}, "limit": {"8"}, "offset": {"16"}}
|
query := url.Values{"keyword": {"粤A"}, "protocol": {"GB32960"}, "coverage": {"multi"}, "online": {"online"}, "bindingStatus": {"bound"}, "limit": {"8"}, "offset": {"16"}}
|
||||||
built := buildVehicleCoverageSQL(query)
|
built := buildVehicleCoverageSQL(query)
|
||||||
|
|||||||
Reference in New Issue
Block a user