summaryrefslogtreecommitdiff
path: root/internal/namespace/bootstrap_test.go
diff options
context:
space:
mode:
authorJames O'Doherty <james@theodohertyfamily.com>2026-06-13 11:51:04 -0400
committerJames O'Doherty <james@theodohertyfamily.com>2026-06-13 11:51:04 -0400
commit29621ecbd1e77e6e1a70b6b3ea8fbe3a56e47df3 (patch)
treefa54976bbb0c4e9db59c983e7cb4e60c5119d18b /internal/namespace/bootstrap_test.go
parentf8afb7d5889f5c8b6ea256fd078fa8426d21c7be (diff)
refactor: implement dependency injection and enable parallel testing
This commit refactors the core system operations to use a manager-based dependency injection pattern, eliminating global state and resolving data races in the test suite. Architecture: - Introduced NetworkManager and NetworkOps interface in internal/network to abstract netlink calls. - Introduced MountOps and FileSystem interfaces in internal/namespace to abstract mount and filesystem operations. - Introduced TunnelManager in internal/wireguard to coordinate tunnel lifecycle using the new abstractions. - Updated internal/cli and internal/manager to use these managers. Testing: - Restored t.Parallel() to unit tests in internal/network and internal/wireguard. - Implemented setupParallelEnv and an enhanced mockFS in wireguard_unit_test.go to ensure complete test isolation. - Added bootstrap_test.go to verify launcher preparation logic in internal/namespace without requiring syscall.Exec. - Resolved data races in internal/network tests. CLI: - Added support for -h, --help, and -help flags for the main command. Verification: - Passed all tests (unit, integration, E2E). - Verified zero data races with 'go test -race'. - Passed golangci-lint and go vet.
Diffstat (limited to 'internal/namespace/bootstrap_test.go')
-rw-r--r--internal/namespace/bootstrap_test.go111
1 files changed, 111 insertions, 0 deletions
diff --git a/internal/namespace/bootstrap_test.go b/internal/namespace/bootstrap_test.go
new file mode 100644
index 0000000..eff04e2
--- /dev/null
+++ b/internal/namespace/bootstrap_test.go
@@ -0,0 +1,111 @@
+//go:build linux
+
+package namespace
+
+import (
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestPrepareBootstrap(t *testing.T) {
+ t.Parallel()
+
+ // We are testing the environment and argument preparation.
+ // This will actually open some FDs (memfd, netns, socket),
+ // which is fine for an integration-style unit test.
+ config, err := PrepareBootstrap()
+ if err != nil {
+ t.Fatalf("PrepareBootstrap failed: %v", err)
+ }
+
+ // 1. Verify ExecPath is correct (should be a fd in /proc/self/fd)
+ if !strings.HasPrefix(config.ExecPath, "/proc/self/fd/") {
+ t.Errorf("expected ExecPath to be in /proc/self/fd/, got %s", config.ExecPath)
+ }
+
+ // 2. Verify Arguments are preserved and expanded
+ if len(config.Args) == 0 || config.Args[0] == "" {
+ t.Error("args should not be empty")
+ }
+
+ // 3. Verify Host NetNS FD is present in Env
+ foundNetNs := false
+ for _, env := range config.Env {
+ if strings.HasPrefix(env, "WG_WRAP_HOST_NETNS_FD=") {
+ foundNetNs = true
+ break
+ }
+ }
+ if !foundNetNs {
+ t.Error("WG_WRAP_HOST_NETNS_FD missing from environment")
+ }
+
+ // 4. Verify Host Socket FD is present in Env
+ foundSocket := false
+ for _, env := range config.Env {
+ if strings.HasPrefix(env, "WG_WRAP_HOST_SOCKET_FD=") {
+ foundSocket = true
+ break
+ }
+ }
+ if !foundSocket {
+ t.Error("WG_WRAP_HOST_SOCKET_FD missing from environment")
+ }
+
+ // 5. Verify FDs are tracked for cleanup
+ if len(config.Fds) < 2 {
+ t.Errorf("expected at least 2 FDs (launcher, netns), got %d", len(config.Fds))
+ }
+}
+
+func TestPrepareBootstrapJoin(t *testing.T) {
+ t.Parallel()
+
+ targetPid := 1234
+ config, err := PrepareBootstrapJoin(targetPid)
+ if err != nil {
+ t.Fatalf("PrepareBootstrapJoin failed: %v", err)
+ }
+
+ // 1. Verify Join PID is present in Env
+ foundJoinPid := false
+ expectedPidEnv := "WG_WRAP_JOIN_PID=1234"
+ for _, env := range config.Env {
+ if env == expectedPidEnv {
+ foundJoinPid = true
+ break
+ }
+ }
+ if !foundJoinPid {
+ t.Errorf("expected %s in environment", expectedPidEnv)
+ }
+
+ // 2. Verify Joined flag is present
+ foundJoined := false
+ for _, env := range config.Env {
+ if env == "WG_WRAP_JOINED=1" {
+ foundJoined = true
+ break
+ }
+ }
+ if !foundJoined {
+ t.Error("WG_WRAP_JOINED=1 missing from environment")
+ }
+}
+
+func TestPrepareBootstrap_NullByteValidation(t *testing.T) {
+ // Temporarily inject a null byte into os.Args to test validation
+ // Note: os.Args is a slice, so we can modify it.
+ oldArgs := os.Args
+ defer func() { os.Args = oldArgs }()
+
+ os.Args = append(os.Args, "bad\x00arg")
+
+ _, err := PrepareBootstrap()
+ if err == nil {
+ t.Error("expected error when argument contains null byte, got nil")
+ } else if !strings.Contains(err.Error(), "contains null byte") {
+ t.Errorf("expected null byte error, got: %v", err)
+ }
+}