diff options
| author | James O'Doherty <james@theodohertyfamily.com> | 2026-06-13 11:51:04 -0400 |
|---|---|---|
| committer | James O'Doherty <james@theodohertyfamily.com> | 2026-06-13 11:51:04 -0400 |
| commit | 29621ecbd1e77e6e1a70b6b3ea8fbe3a56e47df3 (patch) | |
| tree | fa54976bbb0c4e9db59c983e7cb4e60c5119d18b /internal/namespace/bootstrap_test.go | |
| parent | f8afb7d5889f5c8b6ea256fd078fa8426d21c7be (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.go | 111 |
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) + } +} |
