feat(timeline): fix chronology, status resolution, and component history UI
This commit is contained in:
@@ -1,23 +1,19 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"reanimator/internal/ingest"
|
||||
"reanimator/internal/repository"
|
||||
"reanimator/internal/repository/migrate"
|
||||
)
|
||||
|
||||
func TestIngestLogBundleIdempotent(t *testing.T) {
|
||||
func TestRemovedIngestRoutesReturnNotFound(t *testing.T) {
|
||||
dsn := os.Getenv("DATABASE_DSN")
|
||||
if dsn == "" {
|
||||
t.Skip("DATABASE_DSN not set")
|
||||
@@ -36,50 +32,29 @@ func TestIngestLogBundleIdempotent(t *testing.T) {
|
||||
t.Fatalf("cleanup: %v", err)
|
||||
}
|
||||
|
||||
projectID := insertProject(t, db, "Core")
|
||||
assetID := insertAsset(t, db, projectID, "server-01", "ASSET-01")
|
||||
|
||||
mux := http.NewServeMux()
|
||||
RegisterIngestRoutes(mux, IngestDependencies{Service: ingest.NewService(db)})
|
||||
RegisterIngestRoutes(mux, IngestDependencies{Service: nil})
|
||||
RegisterFailureRoutes(mux, FailureDependencies{Failures: nil})
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
collectedAt := time.Now().UTC().Format(time.RFC3339)
|
||||
payload := map[string]any{
|
||||
"asset_id": assetID,
|
||||
"collected_at": collectedAt,
|
||||
"components": []map[string]any{
|
||||
{"vendor_serial": "VSN-001"},
|
||||
{"vendor_serial": "VSN-002"},
|
||||
},
|
||||
}
|
||||
body, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal payload: %v", err)
|
||||
}
|
||||
|
||||
resp, err := http.Post(server.URL+"/ingest/logbundle", "application/json", bytes.NewReader(body))
|
||||
resp, err := http.Post(server.URL+"/ingest/logbundle", "application/json", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("post: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("expected 201, got %d", resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
t.Fatalf("expected 404 for /ingest/logbundle, got %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
resp, err = http.Post(server.URL+"/ingest/logbundle", "application/json", bytes.NewReader(body))
|
||||
resp, err = http.Post(server.URL+"/ingest/failures", "application/json", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("post duplicate: %v", err)
|
||||
t.Fatalf("post failure ingest: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("expected 200 on duplicate, got %d", resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
t.Fatalf("expected 404 for /ingest/failures, got %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
assertCount(t, db, "log_bundles", 1)
|
||||
assertCount(t, db, "observations", 2)
|
||||
assertCountQuery(t, db, "SELECT COUNT(*) FROM installations WHERE removed_at IS NULL", 2)
|
||||
assertCountQuery(t, db, "SELECT COUNT(*) FROM parts WHERE first_seen_at IS NOT NULL", 2)
|
||||
}
|
||||
|
||||
func applyMigrations(db *sql.DB) error {
|
||||
|
||||
Reference in New Issue
Block a user