bootstrap: iniciar bitácora operativa
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package clusterlog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func runJSONCommand(t *testing.T, root, keyPath, stdin string, now time.Time, args ...string) ResultEnvelope {
|
||||
t.Helper()
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
app := New(Options{
|
||||
Root: root, JSON: true, SSHKey: keyPath, Stdout: &stdout, Stderr: &stderr,
|
||||
Stdin: strings.NewReader(stdin), Now: func() time.Time { return now }, Executable: "clusterlog",
|
||||
})
|
||||
if err := app.Run(args); err != nil {
|
||||
t.Fatalf("command %v failed: %v\nstderr: %s", args, err, stderr.String())
|
||||
}
|
||||
var envelope ResultEnvelope
|
||||
if err := json.Unmarshal(stdout.Bytes(), &envelope); err != nil {
|
||||
t.Fatalf("invalid command JSON for %v: %v\n%s", args, err, stdout.String())
|
||||
}
|
||||
if !envelope.OK {
|
||||
t.Fatalf("command returned non-ok envelope: %#v", envelope)
|
||||
}
|
||||
return envelope
|
||||
}
|
||||
|
||||
func envelopeDataMap(t *testing.T, envelope ResultEnvelope) map[string]any {
|
||||
t.Helper()
|
||||
data, ok := envelope.Data.(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("unexpected data type: %T", envelope.Data)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func TestCLIAdminMemoryReviewFlow(t *testing.T) {
|
||||
root := testProjectRoot(t)
|
||||
keyPath := filepath.Join(root, "ana.pub")
|
||||
if err := os.WriteFile(keyPath, []byte(testOpenSSHPublicKey(9, "ana@test")+"\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
now := time.Date(2026, 8, 12, 14, 0, 0, 123, time.UTC)
|
||||
runJSONCommand(t, root, keyPath, "", now,
|
||||
"admin", "add", "--id", "ana", "--name", "Ana Operadora", "--email", "ana@example.test")
|
||||
|
||||
memoryJSON := `{
|
||||
"title": "Reiniciar controlador de almacenamiento",
|
||||
"description": "Corrección controlada de un controlador degradado",
|
||||
"risk": "high",
|
||||
"tags": ["storage", "mantenimiento"],
|
||||
"systems": ["ceph"],
|
||||
"changes": ["Se drenó el nodo", "Se reinició el controlador"],
|
||||
"validation": ["El clúster volvió a HEALTH_OK"],
|
||||
"rollback": "Reintegrar el controlador anterior",
|
||||
"agent": "claude-code"
|
||||
}`
|
||||
envelope := runJSONCommand(t, root, keyPath, memoryJSON, now.Add(time.Minute),
|
||||
"memory", "create", "--from-json", "-")
|
||||
data := envelopeDataMap(t, envelope)
|
||||
entryID, ok := data["entry_id"].(string)
|
||||
if !ok || entryID == "" {
|
||||
t.Fatalf("missing entry id: %#v", data)
|
||||
}
|
||||
state, err := New(Options{}).BuildState(root)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(state.ReviewQueue) != 1 || !contains(state.ReviewQueue[0].MissingReviewers, "ana") {
|
||||
t.Fatalf("unexpected review queue: %#v", state.ReviewQueue)
|
||||
}
|
||||
|
||||
runJSONCommand(t, root, keyPath, "", now.Add(2*time.Minute), "review", "mark", entryID, "--note", "Validado")
|
||||
state, err = New(Options{}).BuildState(root)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(state.ReviewQueue) != 0 {
|
||||
t.Fatalf("reviewed item remained pending: %#v", state.ReviewQueue)
|
||||
}
|
||||
files, err := reviewEventFiles(root)
|
||||
if err != nil || len(files) != 1 {
|
||||
t.Fatalf("expected one independent review event file, got %v, err=%v", files, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user