package agent import ( "os" "path/filepath" "strings" "testing" "time" ) // V2.0.1 ⑧: the sing-box core process is launched with // GOMEMLIMIT=32MiB and GOGC=50 in its environment — on the first // start and on every re-apply, since all launches go through // singboxProcess.start. The agent's own env is not modified, and // values the agent was itself started with are replaced (never // duplicated) for the child. func countEnv(env []string, want string) int { n := 0 for _, kv := range env { if kv == want { n++ } } return n } func TestSingboxCoreEnv(t *testing.T) { t.Setenv("GOMEMLIMIT", "999MiB") t.Setenv("GOGC", "off") env := singboxCoreEnv() if n := countEnv(env, "GOMEMLIMIT=32MiB"); n != 1 { t.Errorf("GOMEMLIMIT=32MiB appears %d times, want exactly 1 (%v)", n, env) } if n := countEnv(env, "GOGC=50"); n != 1 { t.Errorf("GOGC=50 appears %d times, want exactly 1", n) } for _, kv := range env { if kv == "GOMEMLIMIT=999MiB" || kv == "GOGC=off" { t.Errorf("agent's own %q leaked into the core env", kv) } } // The agent process env itself is untouched. if got := os.Getenv("GOMEMLIMIT"); got != "999MiB" { t.Errorf("agent env GOMEMLIMIT = %q, want the untouched 999MiB", got) } } // TestSingboxProcessStartCarriesCoreEnv starts a stand-in core // through the real launch path and reads back the environment the // child actually received (the script dumps its own env on start). func TestSingboxProcessStartCarriesCoreEnv(t *testing.T) { dir := t.TempDir() dump := filepath.Join(dir, "child-env.txt") binPath := filepath.Join(dir, "sing-box") script := "#!/bin/sh\nenv > '" + dump + "'\nexec sleep 3600\n" if err := os.WriteFile(binPath, []byte(script), 0o755); err != nil { t.Fatalf("write fake core: %v", err) } cfgPath := filepath.Join(dir, "cfg.json") if err := os.WriteFile(cfgPath, []byte("{}"), 0o600); err != nil { t.Fatalf("write config: %v", err) } t.Setenv("GOMEMLIMIT", "999MiB") p := &singboxProcess{} if err := p.start(binPath, cfgPath, filepath.Join(dir, "sing-box.log")); err != nil { t.Fatalf("start: %v", err) } defer p.stop() var childEnv []string deadline := time.Now().Add(5 * time.Second) for time.Now().Before(deadline) { if raw, err := os.ReadFile(dump); err == nil && len(raw) > 0 { childEnv = strings.Split(strings.TrimSpace(string(raw)), "\n") break } time.Sleep(50 * time.Millisecond) } if childEnv == nil { t.Fatal("fake core never dumped its environment") } if n := countEnv(childEnv, "GOMEMLIMIT=32MiB"); n != 1 { t.Errorf("child env GOMEMLIMIT=32MiB x%d, want 1 (%v)", n, childEnv) } if n := countEnv(childEnv, "GOGC=50"); n != 1 { t.Errorf("child env GOGC=50 x%d, want 1", n) } if n := countEnv(childEnv, "GOMEMLIMIT=999MiB"); n != 0 { t.Errorf("child inherited the agent's GOMEMLIMIT=999MiB (%v)", childEnv) } }