client *http.Client removed — all HTTP routes through transport.go. 75 test struct literals cleaned, 3 test assertions updated. Co-Authored-By: Virgil <virgil@lethean.io>
596 lines
17 KiB
Go
596 lines
17 KiB
Go
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
package agentic
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
core "dappco.re/go/core"
|
|
"dappco.re/go/core/forge"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// --- Shutdown ---
|
|
|
|
func TestPrep_Shutdown_Good(t *testing.T) {
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
err := s.Shutdown(context.Background())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
// --- Name ---
|
|
|
|
func TestPrep_Name_Good(t *testing.T) {
|
|
s := &PrepSubsystem{ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{})}
|
|
assert.Equal(t, "agentic", s.Name())
|
|
}
|
|
|
|
// --- findConsumersList ---
|
|
|
|
func TestPrep_FindConsumersList_Good_HasConsumers(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
// Create go.work
|
|
goWork := `go 1.22
|
|
|
|
use (
|
|
./core/go
|
|
./core/agent
|
|
./core/mcp
|
|
)`
|
|
os.WriteFile(filepath.Join(dir, "go.work"), []byte(goWork), 0o644)
|
|
|
|
// Create module dirs with go.mod
|
|
for _, mod := range []struct {
|
|
path string
|
|
content string
|
|
}{
|
|
{"core/go", "module forge.lthn.ai/core/go\n\ngo 1.22\n"},
|
|
{"core/agent", "module forge.lthn.ai/core/agent\n\nrequire forge.lthn.ai/core/go v0.7.0\n"},
|
|
{"core/mcp", "module forge.lthn.ai/core/mcp\n\nrequire forge.lthn.ai/core/go v0.7.0\n"},
|
|
} {
|
|
modDir := filepath.Join(dir, mod.path)
|
|
os.MkdirAll(modDir, 0o755)
|
|
os.WriteFile(filepath.Join(modDir, "go.mod"), []byte(mod.content), 0o644)
|
|
}
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
codePath: dir,
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
list, count := s.findConsumersList("go")
|
|
assert.Equal(t, 2, count)
|
|
assert.Contains(t, list, "agent")
|
|
assert.Contains(t, list, "mcp")
|
|
assert.Contains(t, list, "Breaking change risk")
|
|
}
|
|
|
|
func TestPrep_FindConsumersList_Good_NoConsumers(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
goWork := `go 1.22
|
|
|
|
use (
|
|
./core/go
|
|
)`
|
|
os.WriteFile(filepath.Join(dir, "go.work"), []byte(goWork), 0o644)
|
|
|
|
modDir := filepath.Join(dir, "core", "go")
|
|
os.MkdirAll(modDir, 0o755)
|
|
os.WriteFile(filepath.Join(modDir, "go.mod"), []byte("module forge.lthn.ai/core/go\n"), 0o644)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
codePath: dir,
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
list, count := s.findConsumersList("go")
|
|
assert.Equal(t, 0, count)
|
|
assert.Empty(t, list)
|
|
}
|
|
|
|
func TestPrep_FindConsumersList_Bad_NoGoWork(t *testing.T) {
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
codePath: t.TempDir(),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
list, count := s.findConsumersList("go")
|
|
assert.Equal(t, 0, count)
|
|
assert.Empty(t, list)
|
|
}
|
|
|
|
// --- pullWikiContent ---
|
|
|
|
func TestPrep_PullWikiContent_Good_WithPages(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case r.URL.Path == "/api/v1/repos/core/go-io/wiki/pages":
|
|
json.NewEncoder(w).Encode([]map[string]any{
|
|
{"title": "Home", "sub_url": "Home"},
|
|
{"title": "Architecture", "sub_url": "Architecture"},
|
|
})
|
|
case r.URL.Path == "/api/v1/repos/core/go-io/wiki/page/Home":
|
|
// "Hello World" base64
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"title": "Home",
|
|
"content_base64": "SGVsbG8gV29ybGQ=",
|
|
})
|
|
case r.URL.Path == "/api/v1/repos/core/go-io/wiki/page/Architecture":
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"title": "Architecture",
|
|
"content_base64": "TGF5ZXJlZA==",
|
|
})
|
|
default:
|
|
w.WriteHeader(404)
|
|
}
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
forge: forge.NewForge(srv.URL, "test-token"),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
content := s.pullWikiContent(context.Background(), "core", "go-io")
|
|
assert.Contains(t, content, "Hello World")
|
|
assert.Contains(t, content, "Layered")
|
|
assert.Contains(t, content, "### Home")
|
|
assert.Contains(t, content, "### Architecture")
|
|
}
|
|
|
|
func TestPrep_PullWikiContent_Good_NoPages(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewEncoder(w).Encode([]map[string]any{})
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
forge: forge.NewForge(srv.URL, "test-token"),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
content := s.pullWikiContent(context.Background(), "core", "go-io")
|
|
assert.Empty(t, content)
|
|
}
|
|
|
|
// --- getIssueBody ---
|
|
|
|
func TestPrep_GetIssueBody_Good(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"number": 15,
|
|
"title": "Fix tests",
|
|
"body": "The tests are broken in pkg/core",
|
|
})
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
forge: forge.NewForge(srv.URL, "test-token"),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
body := s.getIssueBody(context.Background(), "core", "go-io", 15)
|
|
assert.Contains(t, body, "tests are broken")
|
|
}
|
|
|
|
func TestPrep_GetIssueBody_Bad_NotFound(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(404)
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
forge: forge.NewForge(srv.URL, "test-token"),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
body := s.getIssueBody(context.Background(), "core", "go-io", 999)
|
|
assert.Empty(t, body)
|
|
}
|
|
|
|
// --- buildPrompt ---
|
|
|
|
func TestPrep_BuildPrompt_Good_BasicFields(t *testing.T) {
|
|
dir := t.TempDir()
|
|
// Create go.mod to detect language
|
|
os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
codePath: t.TempDir(),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
prompt, memories, consumers := s.buildPrompt(context.Background(), PrepInput{
|
|
Task: "Fix the tests",
|
|
Org: "core",
|
|
Repo: "go-io",
|
|
}, "dev", dir)
|
|
|
|
assert.Contains(t, prompt, "TASK: Fix the tests")
|
|
assert.Contains(t, prompt, "REPO: core/go-io on branch dev")
|
|
assert.Contains(t, prompt, "LANGUAGE: go")
|
|
assert.Contains(t, prompt, "CONSTRAINTS:")
|
|
assert.Contains(t, prompt, "CODEX.md")
|
|
assert.Equal(t, 0, memories)
|
|
assert.Equal(t, 0, consumers)
|
|
}
|
|
|
|
func TestPrep_BuildPrompt_Good_WithIssue(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"number": 42,
|
|
"title": "Bug report",
|
|
"body": "Steps to reproduce the bug",
|
|
})
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
forge: forge.NewForge(srv.URL, "test-token"),
|
|
codePath: t.TempDir(),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
prompt, _, _ := s.buildPrompt(context.Background(), PrepInput{
|
|
Task: "Fix the bug",
|
|
Org: "core",
|
|
Repo: "go-io",
|
|
Issue: 42,
|
|
}, "dev", dir)
|
|
|
|
assert.Contains(t, prompt, "ISSUE:")
|
|
assert.Contains(t, prompt, "Steps to reproduce")
|
|
}
|
|
|
|
// --- buildPrompt (naming convention tests) ---
|
|
|
|
func TestPrep_BuildPrompt_Good(t *testing.T) {
|
|
dir := t.TempDir()
|
|
// Create go.mod to detect language as "go"
|
|
os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
codePath: t.TempDir(),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
prompt, memories, consumers := s.buildPrompt(context.Background(), PrepInput{
|
|
Task: "Add unit tests",
|
|
Org: "core",
|
|
Repo: "go-io",
|
|
}, "dev", dir)
|
|
|
|
assert.Contains(t, prompt, "TASK: Add unit tests")
|
|
assert.Contains(t, prompt, "REPO: core/go-io on branch dev")
|
|
assert.Contains(t, prompt, "LANGUAGE: go")
|
|
assert.Contains(t, prompt, "BUILD: go build ./...")
|
|
assert.Contains(t, prompt, "TEST: go test ./...")
|
|
assert.Contains(t, prompt, "CONSTRAINTS:")
|
|
assert.Equal(t, 0, memories)
|
|
assert.Equal(t, 0, consumers)
|
|
}
|
|
|
|
func TestPrep_BuildPrompt_Bad(t *testing.T) {
|
|
// Empty repo path — still produces a prompt (no crash)
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
codePath: t.TempDir(),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
prompt, memories, consumers := s.buildPrompt(context.Background(), PrepInput{
|
|
Task: "Do something",
|
|
Org: "core",
|
|
Repo: "go-io",
|
|
}, "main", "")
|
|
|
|
assert.Contains(t, prompt, "TASK: Do something")
|
|
assert.Contains(t, prompt, "CONSTRAINTS:")
|
|
assert.Equal(t, 0, memories)
|
|
assert.Equal(t, 0, consumers)
|
|
}
|
|
|
|
func TestPrep_BuildPrompt_Ugly(t *testing.T) {
|
|
dir := t.TempDir()
|
|
os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
|
|
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"number": 99,
|
|
"title": "Critical bug",
|
|
"body": "Server crashes on startup",
|
|
})
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
forge: forge.NewForge(srv.URL, "test-token"),
|
|
codePath: t.TempDir(),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
prompt, _, _ := s.buildPrompt(context.Background(), PrepInput{
|
|
Task: "Fix critical bug",
|
|
Org: "core",
|
|
Repo: "go-io",
|
|
Persona: "reviewer",
|
|
PlanTemplate: "nonexistent-plan",
|
|
Issue: 99,
|
|
}, "agent/fix-bug", dir)
|
|
|
|
// Persona may or may not resolve, but prompt must still contain core fields
|
|
assert.Contains(t, prompt, "TASK: Fix critical bug")
|
|
assert.Contains(t, prompt, "REPO: core/go-io on branch agent/fix-bug")
|
|
assert.Contains(t, prompt, "ISSUE:")
|
|
assert.Contains(t, prompt, "Server crashes on startup")
|
|
assert.Contains(t, prompt, "CONSTRAINTS:")
|
|
}
|
|
|
|
func TestPrep_BuildPrompt_Ugly_WithGitLog(t *testing.T) {
|
|
dir := t.TempDir()
|
|
os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
|
|
|
|
// Init a real git repo with commits so git log path is covered
|
|
exec.Command("git", "init", "-b", "main", dir).Run()
|
|
exec.Command("git", "-C", dir, "config", "user.email", "t@t.com").Run()
|
|
exec.Command("git", "-C", dir, "config", "user.name", "T").Run()
|
|
exec.Command("git", "-C", dir, "add", ".").Run()
|
|
exec.Command("git", "-C", dir, "commit", "-m", "init").Run()
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
codePath: t.TempDir(),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
prompt, _, _ := s.buildPrompt(context.Background(), PrepInput{
|
|
Task: "Fix tests", Org: "core", Repo: "go-io",
|
|
}, "dev", dir)
|
|
|
|
assert.Contains(t, prompt, "RECENT CHANGES:")
|
|
assert.Contains(t, prompt, "init")
|
|
}
|
|
|
|
// --- runQA ---
|
|
|
|
func TestDispatch_RunQA_Good_PHPNoComposer(t *testing.T) {
|
|
dir := t.TempDir()
|
|
repoDir := filepath.Join(dir, "repo")
|
|
os.MkdirAll(repoDir, 0o755)
|
|
// composer.json present but no composer binary
|
|
os.WriteFile(filepath.Join(repoDir, "composer.json"), []byte(`{"name":"test"}`), 0o644)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
// Will fail (composer not found) — that's the expected path
|
|
result := s.runQA(dir)
|
|
assert.False(t, result)
|
|
}
|
|
|
|
// --- pullWikiContent Bad/Ugly ---
|
|
|
|
func TestPrep_PullWikiContent_Bad(t *testing.T) {
|
|
// Forge returns error on wiki pages
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(500)
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
forge: forge.NewForge(srv.URL, "test-token"),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
content := s.pullWikiContent(context.Background(), "core", "go-io")
|
|
assert.Empty(t, content)
|
|
}
|
|
|
|
func TestPrep_PullWikiContent_Ugly(t *testing.T) {
|
|
// Forge returns pages with empty content
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case r.URL.Path == "/api/v1/repos/core/go-io/wiki/pages":
|
|
json.NewEncoder(w).Encode([]map[string]any{
|
|
{"title": "EmptyPage", "sub_url": "EmptyPage"},
|
|
})
|
|
case r.URL.Path == "/api/v1/repos/core/go-io/wiki/page/EmptyPage":
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"title": "EmptyPage",
|
|
"content_base64": "",
|
|
})
|
|
default:
|
|
w.WriteHeader(404)
|
|
}
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
forge: forge.NewForge(srv.URL, "test-token"),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
content := s.pullWikiContent(context.Background(), "core", "go-io")
|
|
// Empty content_base64 means the page is skipped
|
|
assert.Empty(t, content)
|
|
}
|
|
|
|
// --- renderPlan Ugly ---
|
|
|
|
func TestPrep_RenderPlan_Ugly(t *testing.T) {
|
|
// Template with variables that don't exist in template — variables just won't match
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
// Passing variables that won't match any {{placeholder}} in the template
|
|
result := s.renderPlan("coding", map[string]string{
|
|
"nonexistent_var": "value1",
|
|
"another_missing": "value2",
|
|
}, "Test task")
|
|
// Should return the template rendered without substitution (if template exists)
|
|
// or empty if template doesn't exist. Either way, no panic.
|
|
_ = result
|
|
}
|
|
|
|
// --- brainRecall Ugly ---
|
|
|
|
func TestPrep_BrainRecall_Ugly(t *testing.T) {
|
|
// Server returns unexpected JSON structure
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(200)
|
|
// Return JSON that doesn't have "memories" key
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"unexpected_key": "unexpected_value",
|
|
"data": []string{"not", "the", "right", "shape"},
|
|
})
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
brainURL: srv.URL,
|
|
brainKey: "test-key",
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
recall, count := s.brainRecall(context.Background(), "go-io")
|
|
assert.Empty(t, recall, "unexpected JSON structure should yield no memories")
|
|
assert.Equal(t, 0, count)
|
|
}
|
|
|
|
// --- PrepWorkspace Ugly ---
|
|
|
|
func TestPrep_PrepWorkspace_Ugly(t *testing.T) {
|
|
root := t.TempDir()
|
|
t.Setenv("CORE_WORKSPACE", root)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
codePath: t.TempDir(),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
// Repo name "." — should be rejected as invalid
|
|
_, _, err := s.prepWorkspace(context.Background(), nil, PrepInput{
|
|
Repo: ".",
|
|
Issue: 1,
|
|
})
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid repo name")
|
|
|
|
// Repo name ".." — should be rejected as invalid
|
|
_, _, err2 := s.prepWorkspace(context.Background(), nil, PrepInput{
|
|
Repo: "..",
|
|
Issue: 1,
|
|
})
|
|
assert.Error(t, err2)
|
|
assert.Contains(t, err2.Error(), "invalid repo name")
|
|
}
|
|
|
|
// --- findConsumersList Ugly ---
|
|
|
|
func TestPrep_FindConsumersList_Ugly(t *testing.T) {
|
|
// go.work with modules that don't have go.mod
|
|
dir := t.TempDir()
|
|
|
|
goWork := "go 1.22\n\nuse (\n\t./core/go\n\t./core/missing\n)"
|
|
os.WriteFile(filepath.Join(dir, "go.work"), []byte(goWork), 0o644)
|
|
|
|
// Create only the first module dir with go.mod
|
|
modDir := filepath.Join(dir, "core", "go")
|
|
os.MkdirAll(modDir, 0o755)
|
|
os.WriteFile(filepath.Join(modDir, "go.mod"), []byte("module forge.lthn.ai/core/go\n"), 0o644)
|
|
|
|
// core/missing has no go.mod
|
|
os.MkdirAll(filepath.Join(dir, "core", "missing"), 0o755)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
codePath: dir,
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
// Should not panic, just skip missing go.mod entries
|
|
list, count := s.findConsumersList("go")
|
|
assert.Equal(t, 0, count)
|
|
assert.Empty(t, list)
|
|
}
|
|
|
|
// --- getIssueBody Ugly ---
|
|
|
|
func TestPrep_GetIssueBody_Ugly(t *testing.T) {
|
|
// Issue body with HTML/special chars
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
json.NewEncoder(w).Encode(map[string]any{
|
|
"number": 99,
|
|
"title": "Issue with <script>alert('xss')</script>",
|
|
"body": "Body has & HTML <tags> and \"quotes\" and 'apostrophes' <b>bold</b>",
|
|
})
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
|
|
s := &PrepSubsystem{
|
|
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
|
|
forge: forge.NewForge(srv.URL, "test-token"),
|
|
backoff: make(map[string]time.Time),
|
|
failCount: make(map[string]int),
|
|
}
|
|
|
|
body := s.getIssueBody(context.Background(), "core", "go-io", 99)
|
|
assert.NotEmpty(t, body)
|
|
assert.Contains(t, body, "HTML")
|
|
assert.Contains(t, body, "<script>")
|
|
}
|