ananke/internal/service/daemon_coverage_closeout_test.go

243 lines
8.0 KiB
Go

package service
import (
"context"
"io"
"log"
"os"
"path/filepath"
"strings"
"testing"
"time"
"scm.bstein.dev/bstein/ananke/internal/config"
"scm.bstein.dev/bstein/ananke/internal/metrics"
"scm.bstein.dev/bstein/ananke/internal/ups"
)
// TestDaemonRunMetricsEnabledBranchError runs one orchestration or CLI step.
// Signature: TestDaemonRunMetricsEnabledBranchError(t *testing.T).
// Why: covers Run path where metrics are enabled and startup fails before the ticker loop.
func TestDaemonRunMetricsEnabledBranchError(t *testing.T) {
stateDir := t.TempDir()
orch := newDaemonTestOrchestrator(t, stateDir)
d := &Daemon{
cfg: config.Config{
UPS: config.UPS{
Enabled: true,
PollSeconds: 1,
RuntimeSafetyFactor: 1.0,
DebounceCount: 1,
},
Metrics: config.Metrics{
Enabled: true,
BindAddr: "",
Path: "/metrics",
},
State: config.State{
IntentPath: filepath.Join(stateDir, "intent.json"),
},
},
orch: orch,
targets: []Target{
{
Name: "Pyrphoros",
Target: "pyrphoros@localhost",
Provider: &daemonFakeProvider{
samples: []ups.Sample{{OnBattery: false, RuntimeSeconds: 10000, RawStatus: "OL"}},
},
},
},
log: log.New(io.Discard, "", 0),
exporter: metrics.New(),
}
err := d.Run(context.Background())
if err == nil || !strings.Contains(err.Error(), "metrics.bind_addr must not be empty") {
t.Fatalf("expected metrics bind error from Run metrics-enabled path, got %v", err)
}
}
// TestDaemonRunProviderErrorContinueBranch runs one orchestration or CLI step.
// Signature: TestDaemonRunProviderErrorContinueBranch(t *testing.T).
// Why: covers provider-read error continue branch where telemetry timeout does not trigger.
func TestDaemonRunProviderErrorContinueBranch(t *testing.T) {
stateDir := t.TempDir()
orch := newDaemonTestOrchestrator(t, stateDir)
d := &Daemon{
cfg: config.Config{
UPS: config.UPS{
Enabled: true,
PollSeconds: 1,
RuntimeSafetyFactor: 1.0,
DebounceCount: 3,
TelemetryTimeoutSeconds: 120,
},
State: config.State{
IntentPath: filepath.Join(stateDir, "intent.json"),
},
},
orch: orch,
targets: []Target{
{
Name: "Statera",
Target: "statera@localhost",
Provider: &daemonFakeProvider{
errs: []error{context.DeadlineExceeded, context.DeadlineExceeded, context.DeadlineExceeded},
},
},
},
log: log.New(io.Discard, "", 0),
exporter: metrics.New(),
}
ctx, cancel := context.WithTimeout(context.Background(), 1200*time.Millisecond)
defer cancel()
if err := d.Run(ctx); err == nil {
t.Fatalf("expected context cancellation while exercising provider-error continue path")
}
}
// TestTriggerShutdownForwardedIntentWriteFailureWarningBranch runs one orchestration or CLI step.
// Signature: TestTriggerShutdownForwardedIntentWriteFailureWarningBranch(t *testing.T).
// Why: covers triggerShutdown branch where forwarded completion intent write fails but trigger still succeeds.
func TestTriggerShutdownForwardedIntentWriteFailureWarningBranch(t *testing.T) {
tmp := t.TempDir()
sshPath := filepath.Join(tmp, "ssh")
if err := os.WriteFile(sshPath, []byte("#!/usr/bin/env bash\nset -euo pipefail\necho forwarded\n"), 0o755); err != nil {
t.Fatalf("write fake ssh: %v", err)
}
t.Setenv("PATH", tmp+":"+os.Getenv("PATH"))
intentPath := filepath.Join(tmp, "intent-dir")
if err := os.MkdirAll(intentPath, 0o755); err != nil {
t.Fatalf("mkdir intent dir: %v", err)
}
d := &Daemon{
cfg: config.Config{
SSHUser: "atlas",
SSHPort: 2277,
State: config.State{
IntentPath: intentPath,
},
Coordination: config.Coordination{
ForwardShutdownHost: "titan-db",
ForwardShutdownConfig: "/etc/ananke/ananke.yaml",
CommandTimeoutSeconds: 3,
},
},
log: log.New(io.Discard, "", 0),
exporter: metrics.New(),
}
if err := d.triggerShutdown(context.Background(), "forwarded-intent-write-fail"); err != nil {
t.Fatalf("expected forwarded shutdown to succeed even when completion intent write fails, got %v", err)
}
}
// TestTriggerShutdownLocalIntentWriteFailureWarningBranch runs one orchestration or CLI step.
// Signature: TestTriggerShutdownLocalIntentWriteFailureWarningBranch(t *testing.T).
// Why: covers triggerShutdown local completion intent warning branch when write fails after successful shutdown.
func TestTriggerShutdownLocalIntentWriteFailureWarningBranch(t *testing.T) {
stateDir := t.TempDir()
orch := newDaemonTestOrchestrator(t, stateDir)
intentPath := filepath.Join(stateDir, "intent-dir")
if err := os.MkdirAll(intentPath, 0o755); err != nil {
t.Fatalf("mkdir intent dir: %v", err)
}
d := &Daemon{
cfg: config.Config{
State: config.State{
IntentPath: intentPath,
},
Shutdown: config.Shutdown{
EmergencySkipDrain: true,
EmergencySkipEtcd: true,
},
},
orch: orch,
log: log.New(io.Discard, "", 0),
exporter: metrics.New(),
}
if err := d.triggerShutdown(context.Background(), "local-intent-write-fail"); err != nil {
t.Fatalf("expected local shutdown success even when completion intent write fails, got %v", err)
}
}
// TestForwardShutdownDefaultTimeoutBranch runs one orchestration or CLI step.
// Signature: TestForwardShutdownDefaultTimeoutBranch(t *testing.T).
// Why: covers forwardShutdown default command-timeout branch when timeout config is unset.
func TestForwardShutdownDefaultTimeoutBranch(t *testing.T) {
tmp := t.TempDir()
sshPath := filepath.Join(tmp, "ssh")
if err := os.WriteFile(sshPath, []byte("#!/usr/bin/env bash\nset -euo pipefail\necho ok\n"), 0o755); err != nil {
t.Fatalf("write fake ssh: %v", err)
}
t.Setenv("PATH", tmp+":"+os.Getenv("PATH"))
d := &Daemon{
cfg: config.Config{
SSHUser: "atlas",
Coordination: config.Coordination{
ForwardShutdownHost: "titan-db",
ForwardShutdownConfig: "/etc/ananke/ananke.yaml",
CommandTimeoutSeconds: 0,
},
},
log: log.New(io.Discard, "", 0),
}
if err := d.forwardShutdown(context.Background(), "default-timeout-branch"); err != nil {
t.Fatalf("expected forward shutdown with default timeout to succeed, got %v", err)
}
}
// TestForwardShutdownKnownHostsRepairIncludesJumpHost runs one orchestration or CLI step.
// Signature: TestForwardShutdownKnownHostsRepairIncludesJumpHost(t *testing.T).
// Why: covers known-host repair host-list branch that appends the configured SSH jump host.
func TestForwardShutdownKnownHostsRepairIncludesJumpHost(t *testing.T) {
tmp := t.TempDir()
attemptMarker := filepath.Join(tmp, "attempt")
sshPath := filepath.Join(tmp, "ssh")
script := `#!/usr/bin/env bash
set -euo pipefail
marker="` + attemptMarker + `"
if [[ ! -f "$marker" ]]; then
echo "REMOTE HOST IDENTIFICATION HAS CHANGED!" >&2
touch "$marker"
exit 255
fi
echo "forwarded"
`
if err := os.WriteFile(sshPath, []byte(script), 0o755); err != nil {
t.Fatalf("write fake ssh: %v", err)
}
sshKeygenPath := filepath.Join(tmp, "ssh-keygen")
if err := os.WriteFile(sshKeygenPath, []byte("#!/usr/bin/env bash\nset -euo pipefail\nexit 0\n"), 0o755); err != nil {
t.Fatalf("write fake ssh-keygen: %v", err)
}
sshKeyscanPath := filepath.Join(tmp, "ssh-keyscan")
if err := os.WriteFile(sshKeyscanPath, []byte("#!/usr/bin/env bash\nset -euo pipefail\necho fake-key\n"), 0o755); err != nil {
t.Fatalf("write fake ssh-keyscan: %v", err)
}
t.Setenv("PATH", tmp+":"+os.Getenv("PATH"))
d := &Daemon{
cfg: config.Config{
SSHUser: "atlas",
SSHPort: 2277,
SSHConfigFile: filepath.Join(tmp, "ssh-config"),
SSHIdentityFile: filepath.Join(tmp, "id_ed25519"),
SSHJumpHost: "titan-jh",
Coordination: config.Coordination{
ForwardShutdownHost: "titan-db",
ForwardShutdownConfig: "/etc/ananke/ananke.yaml",
CommandTimeoutSeconds: 3,
},
},
log: log.New(io.Discard, "", 0),
}
if err := d.forwardShutdown(context.Background(), "repair-includes-jump-host"); err != nil {
t.Fatalf("expected forward shutdown to recover after known-host repair with jump host, got %v", err)
}
}