7b0b697b18
- Crea functions/infra/audit_e2e_coverage.go: AuditE2ECoverage(roots) escanea
app.md recursivamente, detecta e2e_checks: en frontmatter, retorna
E2ECoverageReport{total, with_checks, missing, coverage_pct}.
- Crea functions/infra/e2e_coverage_report.go: tipo E2ECoverageReport con
JSON tags (total, with_checks, missing, coverage_pct).
- Crea types/infra/e2e_coverage_report.md: metadata del tipo para registry.
- Crea functions/infra/audit_e2e_coverage.md: documentacion self-contained
con Ejemplo, Cuando usarla, Gotchas.
- Crea functions/infra/audit_e2e_coverage_test.go: 3 tests (empty, all-covered,
partial) — todos pasan.
- Edita cmd/fn/doctor.go: agrega case "e2e-coverage" -> doctorE2ECoverage().
Output text (tabla tabwriter + lista de apps missing) y --json (E2ECoverageReport).
Acceptance verificado:
fn doctor e2e-coverage --json -> {total, with_checks, missing, coverage_pct} OK
fn doctor e2e-coverage -> tabla text OK
go test ./functions/infra/... -> 3/3 PASS
fn show audit_e2e_coverage_go_infra -> indexada OK
task_run: task_d285372493cce2e6 iter 1
Co-authored-by: fn-orquestador <noreply@fn-registry>
117 lines
3.1 KiB
Go
117 lines
3.1 KiB
Go
package infra
|
|
|
|
import (
|
|
"math"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestAuditE2ECoverage_EmptyRoot(t *testing.T) {
|
|
dir := t.TempDir()
|
|
// Empty directory — no app.md files.
|
|
report, err := AuditE2ECoverage([]string{dir})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if report.Total != 0 {
|
|
t.Errorf("Total: got %d, want 0", report.Total)
|
|
}
|
|
if report.WithChecks != 0 {
|
|
t.Errorf("WithChecks: got %d, want 0", report.WithChecks)
|
|
}
|
|
if report.CoveragePct != 0.0 {
|
|
t.Errorf("CoveragePct: got %f, want 0.0", report.CoveragePct)
|
|
}
|
|
if len(report.Missing) != 0 {
|
|
t.Errorf("Missing: got %v, want empty", report.Missing)
|
|
}
|
|
}
|
|
|
|
func TestAuditE2ECoverage_AllCovered(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
apps := []struct {
|
|
subdir string
|
|
content string
|
|
}{
|
|
{
|
|
"apps/registry_dashboard",
|
|
"---\nname: registry_dashboard\ne2e_checks:\n - id: build\n cmd: go build .\n---\n",
|
|
},
|
|
{
|
|
"apps/kanban",
|
|
"---\nname: kanban\ne2e_checks:\n - id: tests\n cmd: go test ./...\n---\n",
|
|
},
|
|
}
|
|
|
|
for _, a := range apps {
|
|
full := filepath.Join(dir, a.subdir)
|
|
if err := os.MkdirAll(full, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(full, "app.md"), []byte(a.content), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
report, err := AuditE2ECoverage([]string{filepath.Join(dir, "apps")})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if report.Total != 2 {
|
|
t.Errorf("Total: got %d, want 2", report.Total)
|
|
}
|
|
if report.WithChecks != 2 {
|
|
t.Errorf("WithChecks: got %d, want 2", report.WithChecks)
|
|
}
|
|
if report.CoveragePct != 100.0 {
|
|
t.Errorf("CoveragePct: got %f, want 100.0", report.CoveragePct)
|
|
}
|
|
if len(report.Missing) != 0 {
|
|
t.Errorf("Missing: got %v, want empty", report.Missing)
|
|
}
|
|
}
|
|
|
|
func TestAuditE2ECoverage_PartialCoverage(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
covered := filepath.Join(dir, "apps", "registry_dashboard")
|
|
uncovered := filepath.Join(dir, "apps", "legacy_app")
|
|
for _, d := range []string{covered, uncovered} {
|
|
if err := os.MkdirAll(d, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// app.md with e2e_checks
|
|
covContent := "---\nname: registry_dashboard\ne2e_checks:\n - id: smoke\n cmd: ./registry_dashboard --help\n---\n"
|
|
if err := os.WriteFile(filepath.Join(covered, "app.md"), []byte(covContent), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// app.md without e2e_checks
|
|
uncovContent := "---\nname: legacy_app\ndescription: A legacy app without e2e coverage.\n---\n"
|
|
if err := os.WriteFile(filepath.Join(uncovered, "app.md"), []byte(uncovContent), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
report, err := AuditE2ECoverage([]string{filepath.Join(dir, "apps")})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if report.Total != 2 {
|
|
t.Errorf("Total: got %d, want 2", report.Total)
|
|
}
|
|
if report.WithChecks != 1 {
|
|
t.Errorf("WithChecks: got %d, want 1", report.WithChecks)
|
|
}
|
|
wantPct := 50.0
|
|
if math.Abs(report.CoveragePct-wantPct) > 0.01 {
|
|
t.Errorf("CoveragePct: got %f, want %f", report.CoveragePct, wantPct)
|
|
}
|
|
if len(report.Missing) != 1 {
|
|
t.Errorf("Missing len: got %d, want 1", len(report.Missing))
|
|
}
|
|
}
|