scobleclaw/pkg/floxenv/integration_test.go
agent-cos 163a3333d3 feat(pkg/floxenv): add Flox environment lifecycle management package
- Activate / Deactivate via flox activate --detach (with graceful SIGTERM→SIGKILL)
- Non-privileged IsAlive process check with Linux /proc fallback
- Dev-mode stub when flox is missing or FLOXENV_DEV_MODE=1
- Unit and integration tests

Closes #16
2026-05-29 23:40:22 -07:00

70 lines
1.8 KiB
Go

//go:build integration
package floxenv
import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
)
// TestIntegration_ActivateDeactivate exercises the real flox binary if present.
// Run with: go test -tags=integration ./pkg/floxenv
func TestIntegration_ActivateDeactivate(t *testing.T) {
if _, err := exec.LookPath(defaultFloxPath); err != nil {
t.Skip("flox not installed; skipping integration test")
}
// Verify that the installed flox supports --detach.
if out, err := exec.Command(defaultFloxPath, "activate", "--help").Output(); err == nil {
if !strings.Contains(string(out), "detach") {
t.Skip("installed flox does not support --detach; skipping integration test")
}
} else {
t.Skipf("unable to query flox activate help: %v", err)
}
tmpDir := t.TempDir()
manifest := filepath.Join(tmpDir, "flox.nix")
if err := os.WriteFile(manifest, []byte(`{
description = "test env";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }: {};
}`), 0600); err != nil {
t.Fatalf("write manifest: %v", err)
}
r := NewRegistry()
envID, pid, err := r.Activate(manifest)
if err != nil {
t.Fatalf("activate failed: %v", err)
}
if !IsAlive(pid) {
t.Fatalf("expected pid %d to be alive after activation", pid)
}
// Ensure we clean up even if the test panics.
t.Cleanup(func() {
_ = r.Deactivate(envID, pid)
})
// Give flox a moment to fully initialise detached state.
time.Sleep(500 * time.Millisecond)
if err := r.Deactivate(envID, pid); err != nil {
t.Fatalf("deactivate failed: %v", err)
}
// Polling isAlive because flox may take a moment to tear down.
for i := 0; i < 30; i++ {
if !IsAlive(pid) {
return
}
time.Sleep(100 * time.Millisecond)
}
t.Fatalf("expected pid %d to be dead after deactivate, but it is still alive", pid)
}