1- package reexec
1+ package reexec_test
22
33import (
44 "context"
55 "errors"
66 "fmt"
77 "os"
8- "os/exec"
98 "path/filepath"
109 "reflect"
1110 "runtime"
1211 "strings"
1312 "testing"
1413 "time"
14+
15+ "github.com/moby/sys/reexec"
16+ "github.com/moby/sys/reexec/internal/reexecoverride"
1517)
1618
1719const (
@@ -21,23 +23,23 @@ const (
2123)
2224
2325func init () {
24- Register (testReExec , func () {
26+ reexec . Register (testReExec , func () {
2527 panic ("Return Error" )
2628 })
27- Register (testReExec2 , func () {
29+ reexec . Register (testReExec2 , func () {
2830 var args string
2931 if len (os .Args ) > 1 {
3032 args = fmt .Sprintf ("(args: %#v)" , os .Args [1 :])
3133 }
3234 fmt .Println ("Hello" , testReExec2 , args )
3335 os .Exit (0 )
3436 })
35- Register (testReExec3 , func () {
37+ reexec . Register (testReExec3 , func () {
3638 fmt .Println ("Hello " + testReExec3 )
3739 time .Sleep (1 * time .Second )
3840 os .Exit (0 )
3941 })
40- if Init () {
42+ if reexec . Init () {
4143 // Make sure we exit in case re-exec didn't os.Exit on its own.
4244 os .Exit (0 )
4345 }
@@ -73,7 +75,7 @@ func TestRegister(t *testing.T) {
7375 t .Errorf ("got %q, want %q" , r , tc .expectedErr )
7476 }
7577 }()
76- Register (tc .name , func () {})
78+ reexec . Register (tc .name , func () {})
7779 })
7880 }
7981}
@@ -102,7 +104,7 @@ func TestCommand(t *testing.T) {
102104 }
103105 for _ , tc := range tests {
104106 t .Run (tc .doc , func (t * testing.T ) {
105- cmd := Command (tc .cmdAndArgs ... )
107+ cmd := reexec . Command (tc .cmdAndArgs ... )
106108 if ! reflect .DeepEqual (cmd .Args , tc .cmdAndArgs ) {
107109 t .Fatalf ("got %+v, want %+v" , cmd .Args , tc .cmdAndArgs )
108110 }
@@ -169,7 +171,7 @@ func TestCommandContext(t *testing.T) {
169171 ctx , cancel := context .WithTimeout (context .Background (), 100 * time .Millisecond )
170172 defer cancel ()
171173
172- cmd := CommandContext (ctx , tc .cmdAndArgs ... )
174+ cmd := reexec . CommandContext (ctx , tc .cmdAndArgs ... )
173175 if ! reflect .DeepEqual (cmd .Args , tc .cmdAndArgs ) {
174176 t .Fatalf ("got %+v, want %+v" , cmd .Args , tc .cmdAndArgs )
175177 }
@@ -202,18 +204,17 @@ func TestCommandContext(t *testing.T) {
202204// can resolve a path that can be used to re-execute the current test binary
203205// when it falls back to the argv[0]-based implementation.
204206//
205- // It invokes the binary via naiveSelf (intentionally bypassing the Linux
206- // /proc/self/exe fast-path) so the fallback logic is exercised consistently
207- // across platforms.
207+ // It forces Self() to bypass the Linux /proc/self/exe fast-path via
208+ // [reexecoverride.OverrideArgv0] so that the fallback logic is exercised
209+ // consistently across platforms.
208210func TestRunNaiveSelf (t * testing.T ) {
209211 ctx , cancel := context .WithTimeout (context .Background (), 100 * time .Millisecond )
210212 defer cancel ()
211213
212- // Similar to [rexec.CommandContext], but using naiveSelf to skip the
213- // optimized "/proc/self/exe" on Linux.
214- cmd := exec .CommandContext (ctx , naiveSelf (os .Args [0 ]), testReExec2 )
215- cmd .Args = cmd .Args [1 :]
214+ // Force Self() to use naiveSelf(os.Args[0]), instead of "/proc/self/exe" on Linux.
215+ reexecoverride .OverrideArgv0 (t , os .Args [0 ])
216216
217+ cmd := reexec .CommandContext (ctx , testReExec2 )
217218 out , err := cmd .CombinedOutput ()
218219 if err != nil {
219220 t .Fatalf ("Unable to start command: %v" , err )
@@ -227,12 +228,23 @@ func TestRunNaiveSelf(t *testing.T) {
227228}
228229
229230func TestNaiveSelfResolve (t * testing.T ) {
231+ t .Run ("fast path on Linux" , func (t * testing.T ) {
232+ if runtime .GOOS != "linux" {
233+ t .Skip ("only supported on Linux" )
234+ }
235+ resolved := reexec .Self ()
236+ expected := "/proc/self/exe"
237+ if resolved != expected {
238+ t .Errorf ("got %v, want %v" , resolved , expected )
239+ }
240+ })
230241 t .Run ("resolve in PATH" , func (t * testing.T ) {
231242 executable := "sh"
232243 if runtime .GOOS == "windows" {
233244 executable = "cmd"
234245 }
235- resolved := naiveSelf (executable )
246+ reexecoverride .OverrideArgv0 (t , executable )
247+ resolved := reexec .Self ()
236248 if resolved == executable {
237249 t .Errorf ("did not resolve via PATH; got %q" , resolved )
238250 }
@@ -246,7 +258,8 @@ func TestNaiveSelfResolve(t *testing.T) {
246258 if err != nil {
247259 t .Fatal (err )
248260 }
249- resolved := naiveSelf (executable )
261+ reexecoverride .OverrideArgv0 (t , executable )
262+ resolved := reexec .Self ()
250263 if resolved != want {
251264 t .Errorf ("expected absolute path; got %q, want %q" , resolved , want )
252265 }
@@ -257,14 +270,16 @@ func TestNaiveSelfResolve(t *testing.T) {
257270 if err != nil {
258271 t .Fatal (err )
259272 }
260- resolved := naiveSelf (executable )
273+ reexecoverride .OverrideArgv0 (t , executable )
274+ resolved := reexec .Self ()
261275 if resolved != want {
262276 t .Errorf ("expected absolute path; got %q, want %q" , resolved , want )
263277 }
264278 })
265279 t .Run ("absolute path unchanged" , func (t * testing.T ) {
266280 executable := filepath .Join (os .TempDir (), "some-executable" )
267- resolved := naiveSelf (executable )
281+ reexecoverride .OverrideArgv0 (t , executable )
282+ resolved := reexec .Self ()
268283 if resolved != executable {
269284 t .Errorf ("should not modify absolute paths; got %q, want %q" , resolved , executable )
270285 }
0 commit comments