diff --git a/helper/export_test.go b/helper/export_test.go deleted file mode 100644 index 6bf18ce..0000000 --- a/helper/export_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package helper - -import ( - "os" - "os/exec" - "testing" -) - -// replace execCommand to have the resulting *exec.Cmd launch TestHelperChildStub -func ReplaceExecCommand(t *testing.T) { - t.Cleanup(func() { - execCommand = exec.Command - }) - - execCommand = func(name string, arg ...string) *exec.Cmd { - return exec.Command(os.Args[0], append([]string{"-test.run=TestHelperChildStub", "--", name}, arg...)...) - } -} diff --git a/helper/helper_test.go b/helper/helper_test.go index 6b27e68..2caada4 100644 --- a/helper/helper_test.go +++ b/helper/helper_test.go @@ -35,7 +35,7 @@ func prepareArgs() { } func TestHelper_StartNotify_Close_Wait(t *testing.T) { - helper.ReplaceExecCommand(t) + helper.InternalReplaceExecCommand(t) argsOnce.Do(prepareArgs) t.Run("start helper with status channel", func(t *testing.T) { @@ -106,7 +106,7 @@ func TestHelper_StartNotify_Close_Wait(t *testing.T) { }) } func TestHelper_Start_Close_Wait(t *testing.T) { - helper.ReplaceExecCommand(t) + helper.InternalReplaceExecCommand(t) argsOnce.Do(prepareArgs) var wt io.WriterTo diff --git a/helper/stub.go b/helper/stub.go new file mode 100644 index 0000000..32dc11e --- /dev/null +++ b/helper/stub.go @@ -0,0 +1,90 @@ +package helper + +import ( + "io" + "os" + "os/exec" + "strconv" + "syscall" + "testing" +) + +// InternalChildStub is an internal function but exported because it is cross-package; +// it is part of the implementation of the helper stub. +func InternalChildStub() { + // this test mocks the helper process + if os.Getenv(FortifyHelper) != "1" { + return + } + + // simulate args pipe behaviour + func() { + f := os.NewFile(3, "|0") + if f == nil { + panic("attempted to start helper without args pipe") + } + + if _, err := io.Copy(os.Stdout, f); err != nil { + panic("cannot read args: " + err.Error()) + } + }() + + var wait chan struct{} + + // simulate status pipe behaviour + if os.Getenv(FortifyStatus) == "1" { + wait = make(chan struct{}) + go func() { + f := os.NewFile(4, "|1") + if f == nil { + panic("attempted to start with status reporting without status pipe") + } + + if _, err := f.Write([]byte{'x'}); err != nil { + panic("cannot write to status pipe: " + err.Error()) + } + + // wait for status pipe close + var epoll int + if fd, err := syscall.EpollCreate1(0); err != nil { + panic("cannot open epoll fd: " + err.Error()) + } else { + defer func() { + if err = syscall.Close(fd); err != nil { + panic("cannot close epoll fd: " + err.Error()) + } + }() + epoll = fd + } + if err := syscall.EpollCtl(epoll, syscall.EPOLL_CTL_ADD, int(f.Fd()), &syscall.EpollEvent{}); err != nil { + panic("cannot add status pipe to epoll: " + err.Error()) + } + events := make([]syscall.EpollEvent, 1) + if _, err := syscall.EpollWait(epoll, events, -1); err != nil { + panic("cannot poll status pipe: " + err.Error()) + } + if events[0].Events != syscall.EPOLLERR { + panic(strconv.Itoa(int(events[0].Events))) + + } + close(wait) + }() + } + + if wait != nil { + <-wait + } +} + +// InternalReplaceExecCommand is an internal function but exported because it is cross-package; +// it is part of the implementation of the helper stub. +func InternalReplaceExecCommand(t *testing.T) { + t.Cleanup(func() { + execCommand = exec.Command + }) + + // replace execCommand to have the resulting *exec.Cmd launch TestHelperChildStub + execCommand = func(name string, arg ...string) *exec.Cmd { + return exec.Command(os.Args[0], append([]string{"-test.run=TestHelperChildStub", "--", name}, arg...)...) + } +} diff --git a/helper/stub_test.go b/helper/stub_test.go index 9f85ac6..5838c10 100644 --- a/helper/stub_test.go +++ b/helper/stub_test.go @@ -1,75 +1,11 @@ package helper_test import ( - "io" - "os" - "strconv" - "syscall" "testing" "git.ophivana.moe/cat/fortify/helper" ) func TestHelperChildStub(t *testing.T) { - // this test mocks the helper process - if os.Getenv(helper.FortifyHelper) != "1" { - return - } - // simulate args pipe behaviour - func() { - f := os.NewFile(3, "|0") - if f == nil { - panic("attempted to start helper without args pipe") - } - - if _, err := io.Copy(os.Stdout, f); err != nil { - panic("cannot read args: " + err.Error()) - } - }() - - var wait chan struct{} - - // simulate status pipe behaviour - if os.Getenv(helper.FortifyStatus) == "1" { - wait = make(chan struct{}) - go func() { - f := os.NewFile(4, "|1") - if f == nil { - panic("attempted to start with status reporting without status pipe") - } - - if _, err := f.Write([]byte{'x'}); err != nil { - panic("cannot write to status pipe: " + err.Error()) - } - - // wait for status pipe close - var epoll int - if fd, err := syscall.EpollCreate1(0); err != nil { - panic("cannot open epoll fd: " + err.Error()) - } else { - defer func() { - if err = syscall.Close(fd); err != nil { - panic("cannot close epoll fd: " + err.Error()) - } - }() - epoll = fd - } - if err := syscall.EpollCtl(epoll, syscall.EPOLL_CTL_ADD, int(f.Fd()), &syscall.EpollEvent{}); err != nil { - panic("cannot add status pipe to epoll: " + err.Error()) - } - events := make([]syscall.EpollEvent, 1) - if _, err := syscall.EpollWait(epoll, events, -1); err != nil { - panic("cannot poll status pipe: " + err.Error()) - } - if events[0].Events != syscall.EPOLLERR { - panic(strconv.Itoa(int(events[0].Events))) - - } - close(wait) - }() - } - - if wait != nil { - <-wait - } + helper.InternalChildStub() }