package service import ( "os" "path/filepath" "strings" "testing" "3588AdminBackend/internal/config" "3588AdminBackend/internal/storage" ) func TestConfigPreviewServiceListsSources(t *testing.T) { root := t.TempDir() mustWrite(t, filepath.Join(root, "configs", "templates", "std_workshop_face_recognition_shoe_alarm.json"), `{}`) mustWrite(t, filepath.Join(root, "configs", "profiles", "local_3588_test.json"), `{}`) mustWrite(t, filepath.Join(root, "configs", "overlays", "face_debug.json"), `{}`) svc := NewConfigPreviewService(&config.Config{MediaRepoPath: root}) sources, err := svc.ListSources() if err != nil { t.Fatalf("ListSources: %v", err) } if sources.Root != root { t.Fatalf("expected root %q, got %q", root, sources.Root) } if got := sourceNames(sources.Templates); strings.Join(got, ",") != "std_workshop_face_recognition_shoe_alarm" { t.Fatalf("unexpected templates: %v", got) } if got := sourceNames(sources.Profiles); strings.Join(got, ",") != "local_3588_test" { t.Fatalf("unexpected profiles: %v", got) } if got := sourceNames(sources.Overlays); strings.Join(got, ",") != "face_debug" { t.Fatalf("unexpected overlays: %v", got) } } func TestConfigPreviewServiceRejectsUnsafeNames(t *testing.T) { root := t.TempDir() svc := NewConfigPreviewService(&config.Config{MediaRepoPath: root}) _, err := svc.Render(ConfigPreviewRequest{ Template: "../secret", Profile: "local_3588_test", ConfigID: "preview", ConfigVersion: "v1", }) if err == nil { t.Fatal("expected unsafe template name to be rejected") } } func TestConfigPreviewServiceImportsAssetsIntoSQLite(t *testing.T) { root := t.TempDir() mustWrite(t, filepath.Join(root, "configs", "templates", "helmet.json"), `{"name":"helmet","description":"helmet template","template":{"nodes":[],"edges":[]}}`) mustWrite(t, filepath.Join(root, "configs", "profiles", "gate_a.json"), `{"name":"gate_a","business_name":"Gate A","description":"gate profile","instances":[{"name":"cam1","template":"helmet","params":{"display_name":"Gate A","rtsp_url":"rtsp://10.0.0.1/live"}}]}`) mustWrite(t, filepath.Join(root, "configs", "overlays", "night_relaxed.json"), `{"name":"night_relaxed","description":"overlay","instance_overrides":{"cam1":{"override":{}}}}`) store, err := storage.OpenSQLite(filepath.Join(t.TempDir(), "app.db")) if err != nil { t.Fatalf("OpenSQLite: %v", err) } defer store.Close() repo := storage.NewAssetsRepo(store.DB()) svc := NewConfigPreviewService(&config.Config{MediaRepoPath: root}, repo) result, err := svc.ImportAssetsFromMediaRepo() if err != nil { t.Fatalf("ImportAssetsFromMediaRepo: %v", err) } if result.Templates != 0 || result.Profiles != 1 || result.Overlays != 1 { t.Fatalf("unexpected import result: %#v", result) } sources, err := svc.ListSources() if err != nil { t.Fatalf("ListSources: %v", err) } if got := sourceNames(sources.Templates); len(got) != 1 || got[0] != "helmet" { t.Fatalf("unexpected templates after import: %#v", got) } if record, err := repo.GetTemplate("helmet"); err != nil { t.Fatalf("GetTemplate: %v", err) } else if record != nil { t.Fatalf("expected builtin template to remain outside sqlite, got %#v", record) } } func TestConfigPreviewServiceExportsAssetJSONFromSQLite(t *testing.T) { store, err := storage.OpenSQLite(filepath.Join(t.TempDir(), "app.db")) if err != nil { t.Fatalf("OpenSQLite: %v", err) } defer store.Close() repo := storage.NewAssetsRepo(store.DB()) const raw = "{\n \"name\": \"helmet\",\n \"template\": {\n \"nodes\": [],\n \"edges\": []\n }\n}\n" if err := repo.SaveTemplate("helmet", "helmet template", raw); err != nil { t.Fatalf("SaveTemplate: %v", err) } svc := NewConfigPreviewService(&config.Config{}, repo) body, filename, err := svc.ExportAssetJSON("templates", "helmet") if err != nil { t.Fatalf("ExportAssetJSON: %v", err) } if filename != "helmet.json" { t.Fatalf("unexpected export filename: %q", filename) } if string(body) != raw { t.Fatalf("unexpected export body: %s", string(body)) } } func sourceNames(items []ConfigSource) []string { out := make([]string, 0, len(items)) for _, item := range items { out = append(out, item.Name) } return out } func mustWrite(t *testing.T, path string, body string) { t.Helper() if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { t.Fatalf("mkdir %s: %v", filepath.Dir(path), err) } if err := os.WriteFile(path, []byte(body), 0644); err != nil { t.Fatalf("write %s: %v", path, err) } }