chore: auto-commit (97 archivos)
- .claude/CLAUDE.md - .claude/agents/fn-recopilador/SKILL.md - .claude/rules/INDEX.md - .claude/rules/cpp_apps.md - bash/functions/infra/build_cpp_windows.sh - cpp/CMakeLists.txt - cpp/PATTERNS.md - cpp/framework/app_base.cpp - cpp/framework/app_base.h - dev/issues/README.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
package infra
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// createTestProposalsDB crea una BD en memoria con el schema minimo de proposals
|
||||
// para los tests de ProposalFromFailure.
|
||||
func createTestProposalsDB(t *testing.T) string {
|
||||
t.Helper()
|
||||
f, err := os.CreateTemp("", "proposals_test_*.db")
|
||||
if err != nil {
|
||||
t.Fatalf("create temp db: %v", err)
|
||||
}
|
||||
f.Close()
|
||||
path := f.Name()
|
||||
t.Cleanup(func() { os.Remove(path) })
|
||||
|
||||
db, err := sql.Open("sqlite3", "file:"+path+"?_journal_mode=WAL")
|
||||
if err != nil {
|
||||
t.Fatalf("open temp db: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS proposals (
|
||||
id TEXT PRIMARY KEY,
|
||||
kind TEXT NOT NULL CHECK(kind IN ('new_function','new_type','improve_function','improve_type','new_pipeline')),
|
||||
target_id TEXT NOT NULL DEFAULT '',
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
evidence TEXT NOT NULL DEFAULT '{}',
|
||||
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending','approved','rejected','implemented')),
|
||||
created_by TEXT NOT NULL DEFAULT '',
|
||||
reviewed_by TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
)`)
|
||||
if err != nil {
|
||||
t.Fatalf("create proposals table: %v", err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func TestProposalFromFailure(t *testing.T) {
|
||||
t.Run("no inserta nada cuando todos los checks pasan", func(t *testing.T) {
|
||||
dbPath := createTestProposalsDB(t)
|
||||
results := []CheckResult{
|
||||
{ID: "check-ok", Status: "pass", Severity: "critical"},
|
||||
{ID: "check-skip", Status: "skip", Severity: "warning"},
|
||||
}
|
||||
ids, err := ProposalFromFailure(dbPath, "app_test", results, "exec_001")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(ids) != 0 {
|
||||
t.Errorf("expected 0 proposals, got %d", len(ids))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("inserta proposal por cada check fallido", func(t *testing.T) {
|
||||
dbPath := createTestProposalsDB(t)
|
||||
results := []CheckResult{
|
||||
{ID: "check-api", Status: "fail", Severity: "critical", ExitCode: 1, Error: "connection refused"},
|
||||
{ID: "check-perf", Status: "fail", Severity: "warning", ExitCode: 0, Stdout: "slow"},
|
||||
{ID: "check-ok", Status: "pass", Severity: "critical"},
|
||||
}
|
||||
ids, err := ProposalFromFailure(dbPath, "app_test", results, "exec_002")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(ids) != 2 {
|
||||
t.Errorf("expected 2 proposals, got %d: %v", len(ids), ids)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("proposal critica usa kind new_function", func(t *testing.T) {
|
||||
dbPath := createTestProposalsDB(t)
|
||||
results := []CheckResult{
|
||||
{ID: "check-critical", Status: "fail", Severity: "critical", ExitCode: 2},
|
||||
}
|
||||
ids, err := ProposalFromFailure(dbPath, "app_x", results, "exec_003")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(ids) != 1 {
|
||||
t.Fatalf("expected 1 proposal, got %d", len(ids))
|
||||
}
|
||||
|
||||
db, _ := sql.Open("sqlite3", "file:"+dbPath)
|
||||
defer db.Close()
|
||||
var kind, status, createdBy string
|
||||
err = db.QueryRow("SELECT kind, status, created_by FROM proposals WHERE id = ?", ids[0]).Scan(&kind, &status, &createdBy)
|
||||
if err != nil {
|
||||
t.Fatalf("query proposal: %v", err)
|
||||
}
|
||||
if kind != "new_function" {
|
||||
t.Errorf("expected kind=new_function, got %q", kind)
|
||||
}
|
||||
if status != "pending" {
|
||||
t.Errorf("expected status=pending, got %q", status)
|
||||
}
|
||||
if createdBy != "reactive_loop" {
|
||||
t.Errorf("expected created_by=reactive_loop, got %q", createdBy)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("proposal warning usa kind improve_function", func(t *testing.T) {
|
||||
dbPath := createTestProposalsDB(t)
|
||||
results := []CheckResult{
|
||||
{ID: "check-warning", Status: "fail", Severity: "warning"},
|
||||
}
|
||||
ids, err := ProposalFromFailure(dbPath, "app_y", results, "exec_004")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(ids) != 1 {
|
||||
t.Fatalf("expected 1 proposal, got %d", len(ids))
|
||||
}
|
||||
|
||||
db, _ := sql.Open("sqlite3", "file:"+dbPath)
|
||||
defer db.Close()
|
||||
var kind string
|
||||
_ = db.QueryRow("SELECT kind FROM proposals WHERE id = ?", ids[0]).Scan(&kind)
|
||||
if kind != "improve_function" {
|
||||
t.Errorf("expected kind=improve_function, got %q", kind)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("proposals tienen timestamp reciente", func(t *testing.T) {
|
||||
dbPath := createTestProposalsDB(t)
|
||||
before := time.Now().UTC().Add(-time.Second)
|
||||
results := []CheckResult{
|
||||
{ID: "check-ts", Status: "fail", Severity: "critical"},
|
||||
}
|
||||
ids, err := ProposalFromFailure(dbPath, "app_z", results, "exec_005")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
after := time.Now().UTC().Add(time.Second)
|
||||
|
||||
db, _ := sql.Open("sqlite3", "file:"+dbPath)
|
||||
defer db.Close()
|
||||
var createdAt string
|
||||
_ = db.QueryRow("SELECT created_at FROM proposals WHERE id = ?", ids[0]).Scan(&createdAt)
|
||||
ts, err := time.Parse(time.RFC3339, createdAt)
|
||||
if err != nil {
|
||||
t.Fatalf("parse created_at: %v", err)
|
||||
}
|
||||
if ts.Before(before) || ts.After(after) {
|
||||
t.Errorf("created_at %v out of expected range [%v, %v]", ts, before, after)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user