package topdata import ( "encoding/json" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "gitea.westgate.pw/ShadowsOverWestgate/sow-tools/internal/project" ) func TestDeployWikiDryRunDoesNotWriteRemoteOrManifest(t *testing.T) { root := t.TempDir() sourceDir := filepath.Join(root, "pages") if err := os.MkdirAll(filepath.Join(sourceDir, "skills"), 0755); err != nil { t.Fatalf("create source dir: %v", err) } generated := "\n

Athletics

\n

Generated athletics page

\n\n" if err := os.WriteFile(filepath.Join(sourceDir, "skills", "athletics.html"), []byte(generated), 0644); err != nil { t.Fatalf("write source page: %v", err) } old := "\n

Athletics

\n

Existing athletics page

\n\n" oldHash := computeManagedHash(old) manifestPath := filepath.Join(root, "deploy-manifest.json") if err := saveDeployManifest(manifestPath, wikiDeployManifest{ Version: "nodebb-v1", Pages: map[string]wikiDeployManifestPage{ "skills:athletics": {Hash: oldHash, TID: 7, PID: 42, CID: 3}, }, }); err != nil { t.Fatalf("write deploy manifest: %v", err) } updateCalls := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got := r.Header.Get("Authorization"); got != "Bearer nodebb-token" { t.Fatalf("unexpected authorization header %q", got) } switch { case r.Method == http.MethodGet && r.URL.Path == "/api/v3/posts/42": w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]any{"response": map[string]any{"pid": 42, "tid": 7, "content": old}}) case r.Method == http.MethodPut && r.URL.Path == "/api/v3/posts/42": updateCalls++ w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]any{"response": map[string]any{"pid": 42, "tid": 7}}) default: t.Fatalf("unexpected request %s %s", r.Method, r.URL.Path) } })) defer server.Close() result, err := DeployWikiWithOptions(&project.Project{}, DeployWikiOptions{ SourceDir: sourceDir, Endpoint: server.URL, Token: "nodebb-token", ManifestPath: manifestPath, DryRun: true, }, nil) if err != nil { t.Fatalf("DeployWikiWithOptions dry run failed: %v", err) } if result.Updated != 1 { t.Fatalf("expected one planned update, got %d", result.Updated) } if updateCalls != 0 { t.Fatalf("expected dry run not to update NodeBB posts, got %d calls", updateCalls) } after := loadDeployManifest(manifestPath) if after.Pages["skills:athletics"].Hash != oldHash { t.Fatalf("expected dry run not to rewrite manifest") } } func TestDeployWikiCreatesNodeBBTopicAndWritesManifest(t *testing.T) { root := t.TempDir() sourceDir := filepath.Join(root, "pages") if err := os.MkdirAll(filepath.Join(sourceDir, "skills"), 0755); err != nil { t.Fatalf("create source dir: %v", err) } generated := "\n

Athletics

\n

Generated athletics page

\n\n" if err := os.WriteFile(filepath.Join(sourceDir, "skills", "athletics.html"), []byte(generated), 0644); err != nil { t.Fatalf("write source page: %v", err) } createCalls := 0 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got := r.Header.Get("Authorization"); got != "Bearer nodebb-token" { t.Fatalf("unexpected authorization header %q", got) } if r.Method != http.MethodPost || r.URL.Path != "/api/v3/topics" { t.Fatalf("unexpected request %s %s", r.Method, r.URL.Path) } createCalls++ var req struct { CID int `json:"cid"` Title string `json:"title"` Content string `json:"content"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { t.Fatalf("decode create request: %v", err) } if req.CID != 5 || req.Title != "Athletics" || req.Content != generated { t.Fatalf("unexpected create request: %#v", req) } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]any{ "response": map[string]any{ "tid": 11, "mainPost": map[string]any{ "pid": 42, "tid": 11, }, }, }) })) defer server.Close() manifestPath := filepath.Join(root, "deploy-manifest.json") result, err := DeployWikiWithOptions(&project.Project{}, DeployWikiOptions{ SourceDir: sourceDir, Endpoint: server.URL, Token: "nodebb-token", ManifestPath: manifestPath, CategoryIDs: map[string]int{"skills": 5}, AllowCreates: true, }, nil) if err != nil { t.Fatalf("DeployWikiWithOptions create failed: %v", err) } if result.Created != 1 || createCalls != 1 { t.Fatalf("expected one created topic, result=%d calls=%d", result.Created, createCalls) } manifest := loadDeployManifest(manifestPath) entry := manifest.Pages["skills:athletics"] if entry.TID != 11 || entry.PID != 42 || entry.CID != 5 || entry.Hash != computeManagedHash(generated) { t.Fatalf("unexpected manifest entry: %#v", entry) } } func TestDeployWikiCreatesNodeBBTopicWithFallbackForShortTitle(t *testing.T) { root := t.TempDir() sourceDir := filepath.Join(root, "pages") if err := os.MkdirAll(filepath.Join(sourceDir, "spells"), 0755); err != nil { t.Fatalf("create source dir: %v", err) } generated := "\n

Aid

\n

Generated spell page

\n\n" if err := os.WriteFile(filepath.Join(sourceDir, "spells", "aid.html"), []byte(generated), 0644); err != nil { t.Fatalf("write source page: %v", err) } server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost || r.URL.Path != "/api/v3/topics" { t.Fatalf("unexpected request %s %s", r.Method, r.URL.Path) } var req struct { Title string `json:"title"` Content string `json:"content"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { t.Fatalf("decode create request: %v", err) } if req.Title != "Spells: Aid" { t.Fatalf("expected fallback title, got %q", req.Title) } if req.Content != generated { t.Fatalf("expected page body to keep short h1 unchanged:\n%s", req.Content) } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]any{ "response": map[string]any{ "tid": 11, "mainPost": map[string]any{ "pid": 42, "tid": 11, }, }, }) })) defer server.Close() _, err := DeployWikiWithOptions(&project.Project{}, DeployWikiOptions{ SourceDir: sourceDir, Endpoint: server.URL, Token: "nodebb-token", ManifestPath: filepath.Join(root, "deploy-manifest.json"), CategoryIDs: map[string]int{"spells": 5}, AllowCreates: true, }, nil) if err != nil { t.Fatalf("DeployWikiWithOptions create failed: %v", err) } }