orama/pkg/cli/sandbox/state_test.go
anonpenguin23 fa826f0d00 refactor(sandbox): integrate rootwallet SSH keys
- replace standalone sandbox keys with "sandbox/root" vault entry
- update inspector config to use vault targets (no passwords/keys)
- make sandbox default active environment
- add vault helpers and tests for remotessh
2026-03-10 05:25:41 +02:00

218 lines
5.5 KiB
Go

package sandbox
import (
"os"
"path/filepath"
"testing"
"time"
)
func TestSaveAndLoadState(t *testing.T) {
// Use temp dir for test
tmpDir := t.TempDir()
origHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", origHome)
state := &SandboxState{
Name: "test-sandbox",
CreatedAt: time.Date(2026, 2, 25, 10, 0, 0, 0, time.UTC),
Domain: "test.example.com",
Status: StatusRunning,
Servers: []ServerState{
{ID: 1, Name: "sbx-test-1", IP: "1.1.1.1", Role: "nameserver", FloatingIP: "10.0.0.1", WgIP: "10.0.0.1"},
{ID: 2, Name: "sbx-test-2", IP: "2.2.2.2", Role: "nameserver", FloatingIP: "10.0.0.2", WgIP: "10.0.0.2"},
{ID: 3, Name: "sbx-test-3", IP: "3.3.3.3", Role: "node", WgIP: "10.0.0.3"},
{ID: 4, Name: "sbx-test-4", IP: "4.4.4.4", Role: "node", WgIP: "10.0.0.4"},
{ID: 5, Name: "sbx-test-5", IP: "5.5.5.5", Role: "node", WgIP: "10.0.0.5"},
},
}
if err := SaveState(state); err != nil {
t.Fatalf("SaveState() error = %v", err)
}
// Verify file exists
expected := filepath.Join(tmpDir, ".orama", "sandboxes", "test-sandbox.yaml")
if _, err := os.Stat(expected); err != nil {
t.Fatalf("state file not created at %s: %v", expected, err)
}
// Load back
loaded, err := LoadState("test-sandbox")
if err != nil {
t.Fatalf("LoadState() error = %v", err)
}
if loaded.Name != "test-sandbox" {
t.Errorf("name = %s, want test-sandbox", loaded.Name)
}
if loaded.Domain != "test.example.com" {
t.Errorf("domain = %s, want test.example.com", loaded.Domain)
}
if loaded.Status != StatusRunning {
t.Errorf("status = %s, want running", loaded.Status)
}
if len(loaded.Servers) != 5 {
t.Errorf("servers = %d, want 5", len(loaded.Servers))
}
}
func TestLoadState_NotFound(t *testing.T) {
tmpDir := t.TempDir()
origHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", origHome)
_, err := LoadState("nonexistent")
if err == nil {
t.Error("LoadState() expected error for nonexistent sandbox")
}
}
func TestDeleteState(t *testing.T) {
tmpDir := t.TempDir()
origHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", origHome)
state := &SandboxState{
Name: "to-delete",
Status: StatusRunning,
}
if err := SaveState(state); err != nil {
t.Fatalf("SaveState() error = %v", err)
}
if err := DeleteState("to-delete"); err != nil {
t.Fatalf("DeleteState() error = %v", err)
}
_, err := LoadState("to-delete")
if err == nil {
t.Error("LoadState() should fail after DeleteState()")
}
}
func TestListStates(t *testing.T) {
tmpDir := t.TempDir()
origHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", origHome)
// Create 2 sandboxes
for _, name := range []string{"sandbox-a", "sandbox-b"} {
if err := SaveState(&SandboxState{Name: name, Status: StatusRunning}); err != nil {
t.Fatalf("SaveState(%s) error = %v", name, err)
}
}
states, err := ListStates()
if err != nil {
t.Fatalf("ListStates() error = %v", err)
}
if len(states) != 2 {
t.Errorf("ListStates() returned %d, want 2", len(states))
}
}
func TestFindActiveSandbox(t *testing.T) {
tmpDir := t.TempDir()
origHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", origHome)
// No sandboxes
active, err := FindActiveSandbox()
if err != nil {
t.Fatalf("FindActiveSandbox() error = %v", err)
}
if active != nil {
t.Error("expected nil when no sandboxes exist")
}
// Add one running sandbox
if err := SaveState(&SandboxState{Name: "active-one", Status: StatusRunning}); err != nil {
t.Fatal(err)
}
if err := SaveState(&SandboxState{Name: "errored-one", Status: StatusError}); err != nil {
t.Fatal(err)
}
active, err = FindActiveSandbox()
if err != nil {
t.Fatalf("FindActiveSandbox() error = %v", err)
}
if active == nil || active.Name != "active-one" {
t.Errorf("FindActiveSandbox() = %v, want active-one", active)
}
}
func TestToNodes(t *testing.T) {
state := &SandboxState{
Servers: []ServerState{
{IP: "1.1.1.1", Role: "nameserver"},
{IP: "2.2.2.2", Role: "node"},
},
}
nodes := state.ToNodes("sandbox/root")
if len(nodes) != 2 {
t.Fatalf("ToNodes() returned %d nodes, want 2", len(nodes))
}
if nodes[0].Host != "1.1.1.1" {
t.Errorf("node[0].Host = %s, want 1.1.1.1", nodes[0].Host)
}
if nodes[0].User != "root" {
t.Errorf("node[0].User = %s, want root", nodes[0].User)
}
if nodes[0].VaultTarget != "sandbox/root" {
t.Errorf("node[0].VaultTarget = %s, want sandbox/root", nodes[0].VaultTarget)
}
if nodes[0].SSHKey != "" {
t.Errorf("node[0].SSHKey = %s, want empty (set by PrepareNodeKeys)", nodes[0].SSHKey)
}
if nodes[0].Environment != "sandbox" {
t.Errorf("node[0].Environment = %s, want sandbox", nodes[0].Environment)
}
}
func TestNameserverAndRegularNodes(t *testing.T) {
state := &SandboxState{
Servers: []ServerState{
{Role: "nameserver"},
{Role: "nameserver"},
{Role: "node"},
{Role: "node"},
{Role: "node"},
},
}
ns := state.NameserverNodes()
if len(ns) != 2 {
t.Errorf("NameserverNodes() = %d, want 2", len(ns))
}
regular := state.RegularNodes()
if len(regular) != 3 {
t.Errorf("RegularNodes() = %d, want 3", len(regular))
}
}
func TestGenesisServer(t *testing.T) {
state := &SandboxState{
Servers: []ServerState{
{Name: "first"},
{Name: "second"},
},
}
if state.GenesisServer().Name != "first" {
t.Errorf("GenesisServer().Name = %s, want first", state.GenesisServer().Name)
}
empty := &SandboxState{}
if empty.GenesisServer().Name != "" {
t.Error("GenesisServer() on empty state should return zero value")
}
}