ananke/internal/state/intent_additional_test.go

140 lines
4.9 KiB
Go

package state
import (
"os"
"path/filepath"
"strings"
"testing"
"time"
)
// TestReadIntentHandlesMissingAndEmpty runs one orchestration or CLI step.
// Signature: TestReadIntentHandlesMissingAndEmpty(t *testing.T).
// Why: covers nil-state branches for missing and empty intent files.
func TestReadIntentHandlesMissingAndEmpty(t *testing.T) {
path := filepath.Join(t.TempDir(), "intent.json")
in, err := ReadIntent(path)
if err != nil {
t.Fatalf("read missing intent: %v", err)
}
if in.State != "" {
t.Fatalf("expected empty state for missing file, got %q", in.State)
}
if err := os.WriteFile(path, nil, 0o640); err != nil {
t.Fatalf("write empty intent file: %v", err)
}
in, err = ReadIntent(path)
if err != nil {
t.Fatalf("read empty intent file: %v", err)
}
if in.State != "" {
t.Fatalf("expected empty state for empty file, got %q", in.State)
}
}
// TestWriteIntentSetsUpdatedAtWhenZero runs one orchestration or CLI step.
// Signature: TestWriteIntentSetsUpdatedAtWhenZero(t *testing.T).
// Why: verifies write helper auto-populates timestamp for callers.
func TestWriteIntentSetsUpdatedAtWhenZero(t *testing.T) {
path := filepath.Join(t.TempDir(), "intent.json")
if err := WriteIntent(path, Intent{State: IntentNormal, Reason: "unit", Source: "test"}); err != nil {
t.Fatalf("write intent: %v", err)
}
in, err := ReadIntent(path)
if err != nil {
t.Fatalf("read intent: %v", err)
}
if in.UpdatedAt.IsZero() {
t.Fatalf("expected non-zero updated_at")
}
}
// TestParseIntentOutputErrorsOnBadUpdatedAt runs one orchestration or CLI step.
// Signature: TestParseIntentOutputErrorsOnBadUpdatedAt(t *testing.T).
// Why: covers parser error branch for malformed timestamp values.
func TestParseIntentOutputErrorsOnBadUpdatedAt(t *testing.T) {
raw := `intent=normal reason="x" source=y updated_at=not-a-time`
if _, err := ParseIntentOutput(raw); err == nil {
t.Fatalf("expected updated_at parse error")
}
}
// TestParseIntentOutputErrorsWhenMissingToken runs one orchestration or CLI step.
// Signature: TestParseIntentOutputErrorsWhenMissingToken(t *testing.T).
// Why: covers parser terminal error when intent token is absent.
func TestParseIntentOutputErrorsWhenMissingToken(t *testing.T) {
if _, err := ParseIntentOutput("no intent line here"); err == nil {
t.Fatalf("expected parse failure without intent token")
}
}
// TestParseIntentOutputWithoutReasonOrSource runs one orchestration or CLI step.
// Signature: TestParseIntentOutputWithoutReasonOrSource(t *testing.T).
// Why: covers parser branch where optional fields are omitted.
func TestParseIntentOutputWithoutReasonOrSource(t *testing.T) {
in, err := ParseIntentOutput("intent=shutdown_complete")
if err != nil {
t.Fatalf("parse intent output: %v", err)
}
if in.State != IntentShutdownComplete {
t.Fatalf("expected shutdown_complete, got %q", in.State)
}
}
// TestMustWriteIntentPersistsProvidedTimestampType runs one orchestration or CLI step.
// Signature: TestMustWriteIntentPersistsProvidedTimestampType(t *testing.T).
// Why: sanity check that written timestamps round-trip RFC3339 parsing.
func TestMustWriteIntentPersistsProvidedTimestampType(t *testing.T) {
path := filepath.Join(t.TempDir(), "intent.json")
if err := MustWriteIntent(path, IntentNormal, "ok", "test"); err != nil {
t.Fatalf("must write intent: %v", err)
}
in, err := ReadIntent(path)
if err != nil {
t.Fatalf("read intent: %v", err)
}
if time.Since(in.UpdatedAt) > time.Minute {
t.Fatalf("expected recent timestamp, got %s", in.UpdatedAt)
}
}
// TestWriteIntentFailsWhenParentIsFile runs one orchestration or CLI step.
// Signature: TestWriteIntentFailsWhenParentIsFile(t *testing.T).
// Why: covers mkdir failure branch when parent path is not a directory.
func TestWriteIntentFailsWhenParentIsFile(t *testing.T) {
tmp := t.TempDir()
parent := filepath.Join(tmp, "not-a-dir")
if err := os.WriteFile(parent, []byte("x"), 0o600); err != nil {
t.Fatalf("write parent file: %v", err)
}
err := WriteIntent(filepath.Join(parent, "intent.json"), Intent{State: IntentNormal})
if err == nil {
t.Fatalf("expected write failure for non-directory parent")
}
}
// TestReadIntentFailsOnPermissionError runs one orchestration or CLI step.
// Signature: TestReadIntentFailsOnPermissionError(t *testing.T).
// Why: covers read error branch distinct from not-exist and empty-file handling.
func TestReadIntentFailsOnPermissionError(t *testing.T) {
if os.Geteuid() == 0 {
t.Skip("permission semantics differ under root")
}
path := filepath.Join(t.TempDir(), "intent.json")
if err := os.WriteFile(path, []byte(`{"state":"normal"}`), 0o640); err != nil {
t.Fatalf("write intent file: %v", err)
}
if err := os.Chmod(path, 0o000); err != nil {
t.Fatalf("chmod intent file: %v", err)
}
defer os.Chmod(path, 0o640)
_, err := ReadIntent(path)
if err == nil {
t.Fatalf("expected permission error")
}
if strings.Contains(strings.ToLower(err.Error()), "not exist") {
t.Fatalf("expected permission-related error, got: %v", err)
}
}