summaryrefslogtreecommitdiffstats
path: root/plugin
diff options
context:
space:
mode:
authorChris <ccbrown112@gmail.com>2017-08-18 14:21:01 -0500
committerChristopher Speller <crspeller@gmail.com>2017-08-18 12:21:01 -0700
commitf720288c10c6de5794162053ba565ce090d4f9a3 (patch)
tree10a19962e44d495172ec8415488f007794115570 /plugin
parent42c6686602885ad04ae91ab33f82029a0455b3c7 (diff)
downloadchat-f720288c10c6de5794162053ba565ce090d4f9a3.tar.gz
chat-f720288c10c6de5794162053ba565ce090d4f9a3.tar.bz2
chat-f720288c10c6de5794162053ba565ce090d4f9a3.zip
windows support for plugin ipc (#7251)
* windows support for plugin ipc * unix test fix
Diffstat (limited to 'plugin')
-rw-r--r--plugin/rpcplugin/ipc_test.go2
-rw-r--r--plugin/rpcplugin/main_test.go7
-rw-r--r--plugin/rpcplugin/process_test.go2
-rw-r--r--plugin/rpcplugin/process_windows.go641
-rw-r--r--plugin/rpcplugin/supervisor_test.go12
5 files changed, 649 insertions, 15 deletions
diff --git a/plugin/rpcplugin/ipc_test.go b/plugin/rpcplugin/ipc_test.go
index bf4df3017..25cd197be 100644
--- a/plugin/rpcplugin/ipc_test.go
+++ b/plugin/rpcplugin/ipc_test.go
@@ -16,7 +16,7 @@ func TestIPC(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(dir)
- pingpong := filepath.Join(dir, "pingpong")
+ pingpong := filepath.Join(dir, "pingpong.exe")
compileGo(t, `
package main
diff --git a/plugin/rpcplugin/main_test.go b/plugin/rpcplugin/main_test.go
index b54364bad..a796516e7 100644
--- a/plugin/rpcplugin/main_test.go
+++ b/plugin/rpcplugin/main_test.go
@@ -18,7 +18,7 @@ func TestMain(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(dir)
- plugin := filepath.Join(dir, "plugin")
+ plugin := filepath.Join(dir, "plugin.exe")
compileGo(t, `
package main
@@ -42,13 +42,16 @@ func TestMain(t *testing.T) {
}
`, plugin)
- p, ipc, err := NewProcess(context.Background(), plugin)
+ ctx, cancel := context.WithCancel(context.Background())
+ p, ipc, err := NewProcess(ctx, plugin)
require.NoError(t, err)
defer p.Wait()
muxer := NewMuxer(ipc, false)
defer muxer.Close()
+ defer cancel()
+
var api plugintest.API
hooks, err := ConnectMain(muxer)
diff --git a/plugin/rpcplugin/process_test.go b/plugin/rpcplugin/process_test.go
index b7984ad0a..96d89536c 100644
--- a/plugin/rpcplugin/process_test.go
+++ b/plugin/rpcplugin/process_test.go
@@ -29,7 +29,7 @@ func TestProcess(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(dir)
- ping := filepath.Join(dir, "ping")
+ ping := filepath.Join(dir, "ping.exe")
compileGo(t, `
package main
diff --git a/plugin/rpcplugin/process_windows.go b/plugin/rpcplugin/process_windows.go
index 7be03cacd..069f147c1 100644
--- a/plugin/rpcplugin/process_windows.go
+++ b/plugin/rpcplugin/process_windows.go
@@ -2,16 +2,647 @@ package rpcplugin
import (
"context"
+ "errors"
"fmt"
"io"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "strings"
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+
+ pkgerrors "github.com/pkg/errors"
)
+type process struct {
+ command *cmd
+}
+
func newProcess(ctx context.Context, path string) (Process, io.ReadWriteCloser, error) {
- // TODO
- return nil, nil, fmt.Errorf("not yet supported")
+ ipc, childFiles, err := NewIPC()
+ if err != nil {
+ return nil, nil, err
+ }
+ defer childFiles[0].Close()
+ defer childFiles[1].Close()
+
+ cmd := commandContext(ctx, path)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ cmd.ExtraFiles = childFiles
+ cmd.Env = append(os.Environ(),
+ fmt.Sprintf("MM_IPC_FD0=%v", childFiles[0].Fd()),
+ fmt.Sprintf("MM_IPC_FD1=%v", childFiles[1].Fd()),
+ )
+ err = cmd.Start()
+ if err != nil {
+ ipc.Close()
+ return nil, nil, err
+ }
+
+ return &process{
+ command: cmd,
+ }, ipc, nil
+}
+
+func (p *process) Wait() error {
+ return p.command.Wait()
+}
+
+func inheritedProcessIPC() (io.ReadWriteCloser, error) {
+ fd0, err := strconv.ParseUint(os.Getenv("MM_IPC_FD0"), 0, 64)
+ if err != nil {
+ return nil, pkgerrors.Wrapf(err, "unable to get ipc file descriptor 0")
+ }
+ fd1, err := strconv.ParseUint(os.Getenv("MM_IPC_FD1"), 0, 64)
+ if err != nil {
+ return nil, pkgerrors.Wrapf(err, "unable to get ipc file descriptor 1")
+ }
+ return InheritedIPC(uintptr(fd0), uintptr(fd1))
+}
+
+// XXX: EVERYTHING BELOW THIS IS COPIED / PASTED STANDARD LIBRARY CODE!
+// IT CAN BE DELETED IF / WHEN THIS ISSUE IS RESOLVED: https://github.com/golang/go/issues/21085
+
+// Just about all of os/exec/exec.go is copied / pasted below, altered to use our modified startProcess functions even
+// further below.
+
+type cmd struct {
+ // Path is the path of the command to run.
+ //
+ // This is the only field that must be set to a non-zero
+ // value. If Path is relative, it is evaluated relative
+ // to Dir.
+ Path string
+
+ // Args holds command line arguments, including the command as Args[0].
+ // If the Args field is empty or nil, Run uses {Path}.
+ //
+ // In typical use, both Path and Args are set by calling Command.
+ Args []string
+
+ // Env specifies the environment of the process.
+ // If Env is nil, Run uses the current process's environment.
+ Env []string
+
+ // Dir specifies the working directory of the command.
+ // If Dir is the empty string, Run runs the command in the
+ // calling process's current directory.
+ Dir string
+
+ // Stdin specifies the process's standard input.
+ // If Stdin is nil, the process reads from the null device (os.DevNull).
+ // If Stdin is an *os.File, the process's standard input is connected
+ // directly to that file.
+ // Otherwise, during the execution of the command a separate
+ // goroutine reads from Stdin and delivers that data to the command
+ // over a pipe. In this case, Wait does not complete until the goroutine
+ // stops copying, either because it has reached the end of Stdin
+ // (EOF or a read error) or because writing to the pipe returned an error.
+ Stdin io.Reader
+
+ // Stdout and Stderr specify the process's standard output and error.
+ //
+ // If either is nil, Run connects the corresponding file descriptor
+ // to the null device (os.DevNull).
+ //
+ // If Stdout and Stderr are the same writer, at most one
+ // goroutine at a time will call Write.
+ Stdout io.Writer
+ Stderr io.Writer
+
+ // ExtraFiles specifies additional open files to be inherited by the
+ // new process. It does not include standard input, standard output, or
+ // standard error. If non-nil, entry i becomes file descriptor 3+i.
+ //
+ // BUG(rsc): On OS X 10.6, child processes may sometimes inherit unwanted fds.
+ // https://golang.org/issue/2603
+ ExtraFiles []*os.File
+
+ // SysProcAttr holds optional, operating system-specific attributes.
+ // Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
+ SysProcAttr *syscall.SysProcAttr
+
+ // Process is the underlying process, once started.
+ Process *os.Process
+
+ // ProcessState contains information about an exited process,
+ // available after a call to Wait or Run.
+ ProcessState *os.ProcessState
+
+ ctx context.Context // nil means none
+ lookPathErr error // LookPath error, if any.
+ finished bool // when Wait was called
+ childFiles []*os.File
+ closeAfterStart []io.Closer
+ closeAfterWait []io.Closer
+ goroutine []func() error
+ errch chan error // one send per goroutine
+ waitDone chan struct{}
+}
+
+func command(name string, arg ...string) *cmd {
+ cmd := &cmd{
+ Path: name,
+ Args: append([]string{name}, arg...),
+ }
+ if filepath.Base(name) == name {
+ if lp, err := exec.LookPath(name); err != nil {
+ cmd.lookPathErr = err
+ } else {
+ cmd.Path = lp
+ }
+ }
+ return cmd
}
-func inheritedProcessIPC() (*IPC, error) {
- // TODO
- return nil, fmt.Errorf("not yet supported")
+func commandContext(ctx context.Context, name string, arg ...string) *cmd {
+ if ctx == nil {
+ panic("nil Context")
+ }
+ cmd := command(name, arg...)
+ cmd.ctx = ctx
+ return cmd
+}
+
+func interfaceEqual(a, b interface{}) bool {
+ defer func() {
+ recover()
+ }()
+ return a == b
+}
+
+func (c *cmd) envv() []string {
+ if c.Env != nil {
+ return c.Env
+ }
+ return os.Environ()
+}
+
+func (c *cmd) argv() []string {
+ if len(c.Args) > 0 {
+ return c.Args
+ }
+ return []string{c.Path}
+}
+
+var skipStdinCopyError func(error) bool
+
+func (c *cmd) stdin() (f *os.File, err error) {
+ if c.Stdin == nil {
+ f, err = os.Open(os.DevNull)
+ if err != nil {
+ return
+ }
+ c.closeAfterStart = append(c.closeAfterStart, f)
+ return
+ }
+
+ if f, ok := c.Stdin.(*os.File); ok {
+ return f, nil
+ }
+
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return
+ }
+
+ c.closeAfterStart = append(c.closeAfterStart, pr)
+ c.closeAfterWait = append(c.closeAfterWait, pw)
+ c.goroutine = append(c.goroutine, func() error {
+ _, err := io.Copy(pw, c.Stdin)
+ if skip := skipStdinCopyError; skip != nil && skip(err) {
+ err = nil
+ }
+ if err1 := pw.Close(); err == nil {
+ err = err1
+ }
+ return err
+ })
+ return pr, nil
+}
+
+func (c *cmd) stdout() (f *os.File, err error) {
+ return c.writerDescriptor(c.Stdout)
+}
+
+func (c *cmd) stderr() (f *os.File, err error) {
+ if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
+ return c.childFiles[1], nil
+ }
+ return c.writerDescriptor(c.Stderr)
+}
+
+func (c *cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
+ if w == nil {
+ f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
+ if err != nil {
+ return
+ }
+ c.closeAfterStart = append(c.closeAfterStart, f)
+ return
+ }
+
+ if f, ok := w.(*os.File); ok {
+ return f, nil
+ }
+
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return
+ }
+
+ c.closeAfterStart = append(c.closeAfterStart, pw)
+ c.closeAfterWait = append(c.closeAfterWait, pr)
+ c.goroutine = append(c.goroutine, func() error {
+ _, err := io.Copy(w, pr)
+ pr.Close() // in case io.Copy stopped due to write error
+ return err
+ })
+ return pw, nil
+}
+
+func (c *cmd) closeDescriptors(closers []io.Closer) {
+ for _, fd := range closers {
+ fd.Close()
+ }
+}
+
+func lookExtensions(path, dir string) (string, error) {
+ if filepath.Base(path) == path {
+ path = filepath.Join(".", path)
+ }
+ if dir == "" {
+ return exec.LookPath(path)
+ }
+ if filepath.VolumeName(path) != "" {
+ return exec.LookPath(path)
+ }
+ if len(path) > 1 && os.IsPathSeparator(path[0]) {
+ return exec.LookPath(path)
+ }
+ dirandpath := filepath.Join(dir, path)
+ // We assume that LookPath will only add file extension.
+ lp, err := exec.LookPath(dirandpath)
+ if err != nil {
+ return "", err
+ }
+ ext := strings.TrimPrefix(lp, dirandpath)
+ return path + ext, nil
+}
+
+// Copied from os/exec/exec.go, altered to use osStartProcess (defined below).
+func (c *cmd) Start() error {
+ if c.lookPathErr != nil {
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
+ return c.lookPathErr
+ }
+ if runtime.GOOS == "windows" {
+ lp, err := lookExtensions(c.Path, c.Dir)
+ if err != nil {
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
+ return err
+ }
+ c.Path = lp
+ }
+ if c.Process != nil {
+ return errors.New("exec: already started")
+ }
+ if c.ctx != nil {
+ select {
+ case <-c.ctx.Done():
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
+ return c.ctx.Err()
+ default:
+ }
+ }
+
+ type F func(*cmd) (*os.File, error)
+ for _, setupFd := range []F{(*cmd).stdin, (*cmd).stdout, (*cmd).stderr} {
+ fd, err := setupFd(c)
+ if err != nil {
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
+ return err
+ }
+ c.childFiles = append(c.childFiles, fd)
+ }
+ c.childFiles = append(c.childFiles, c.ExtraFiles...)
+
+ var err error
+ c.Process, err = osStartProcess(c.Path, c.argv(), &os.ProcAttr{
+ Dir: c.Dir,
+ Files: c.childFiles,
+ Env: c.envv(),
+ Sys: c.SysProcAttr,
+ })
+ if err != nil {
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
+ return err
+ }
+
+ c.closeDescriptors(c.closeAfterStart)
+
+ c.errch = make(chan error, len(c.goroutine))
+ for _, fn := range c.goroutine {
+ go func(fn func() error) {
+ c.errch <- fn()
+ }(fn)
+ }
+
+ if c.ctx != nil {
+ c.waitDone = make(chan struct{})
+ go func() {
+ select {
+ case <-c.ctx.Done():
+ c.Process.Kill()
+ case <-c.waitDone:
+ }
+ }()
+ }
+
+ return nil
+}
+
+func (c *cmd) Wait() error {
+ if c.Process == nil {
+ return errors.New("exec: not started")
+ }
+ if c.finished {
+ return errors.New("exec: Wait was already called")
+ }
+ c.finished = true
+
+ state, err := c.Process.Wait()
+ if c.waitDone != nil {
+ close(c.waitDone)
+ }
+ c.ProcessState = state
+
+ var copyError error
+ for range c.goroutine {
+ if err := <-c.errch; err != nil && copyError == nil {
+ copyError = err
+ }
+ }
+
+ c.closeDescriptors(c.closeAfterWait)
+
+ if err != nil {
+ return err
+ } else if !state.Success() {
+ return &exec.ExitError{ProcessState: state}
+ }
+
+ return copyError
+}
+
+// Copied from os/exec_posix.go, altered to use syscallStartProcess (defined below).
+func osStartProcess(name string, argv []string, attr *os.ProcAttr) (p *os.Process, err error) {
+ // If there is no SysProcAttr (ie. no Chroot or changed
+ // UID/GID), double-check existence of the directory we want
+ // to chdir into. We can make the error clearer this way.
+ if attr != nil && attr.Sys == nil && attr.Dir != "" {
+ if _, err := os.Stat(attr.Dir); err != nil {
+ pe := err.(*os.PathError)
+ pe.Op = "chdir"
+ return nil, pe
+ }
+ }
+
+ sysattr := &syscall.ProcAttr{
+ Dir: attr.Dir,
+ Env: attr.Env,
+ Sys: attr.Sys,
+ }
+ if sysattr.Env == nil {
+ sysattr.Env = os.Environ()
+ }
+ for _, f := range attr.Files {
+ sysattr.Files = append(sysattr.Files, f.Fd())
+ }
+
+ pid, _, e := syscallStartProcess(name, argv, sysattr)
+ if e != nil {
+ return nil, &os.PathError{Op: "fork/exec", Path: name, Err: e}
+ }
+ return os.FindProcess(pid)
+}
+
+// Everything from this point on is copied from syscall/exec_windows.go
+
+func makeCmdLine(args []string) string {
+ var s string
+ for _, v := range args {
+ if s != "" {
+ s += " "
+ }
+ s += syscall.EscapeArg(v)
+ }
+ return s
+}
+
+func createEnvBlock(envv []string) *uint16 {
+ if len(envv) == 0 {
+ return &utf16.Encode([]rune("\x00\x00"))[0]
+ }
+ length := 0
+ for _, s := range envv {
+ length += len(s) + 1
+ }
+ length += 1
+
+ b := make([]byte, length)
+ i := 0
+ for _, s := range envv {
+ l := len(s)
+ copy(b[i:i+l], []byte(s))
+ copy(b[i+l:i+l+1], []byte{0})
+ i = i + l + 1
+ }
+ copy(b[i:i+1], []byte{0})
+
+ return &utf16.Encode([]rune(string(b)))[0]
+}
+
+func isSlash(c uint8) bool {
+ return c == '\\' || c == '/'
+}
+
+func normalizeDir(dir string) (name string, err error) {
+ ndir, err := syscall.FullPath(dir)
+ if err != nil {
+ return "", err
+ }
+ if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) {
+ // dir cannot have \\server\share\path form
+ return "", syscall.EINVAL
+ }
+ return ndir, nil
+}
+
+func volToUpper(ch int) int {
+ if 'a' <= ch && ch <= 'z' {
+ ch += 'A' - 'a'
+ }
+ return ch
+}
+
+func joinExeDirAndFName(dir, p string) (name string, err error) {
+ if len(p) == 0 {
+ return "", syscall.EINVAL
+ }
+ if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) {
+ // \\server\share\path form
+ return p, nil
+ }
+ if len(p) > 1 && p[1] == ':' {
+ // has drive letter
+ if len(p) == 2 {
+ return "", syscall.EINVAL
+ }
+ if isSlash(p[2]) {
+ return p, nil
+ } else {
+ d, err := normalizeDir(dir)
+ if err != nil {
+ return "", err
+ }
+ if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
+ return syscall.FullPath(d + "\\" + p[2:])
+ } else {
+ return syscall.FullPath(p)
+ }
+ }
+ } else {
+ // no drive letter
+ d, err := normalizeDir(dir)
+ if err != nil {
+ return "", err
+ }
+ if isSlash(p[0]) {
+ return syscall.FullPath(d[:2] + p)
+ } else {
+ return syscall.FullPath(d + "\\" + p)
+ }
+ }
+}
+
+var zeroProcAttr syscall.ProcAttr
+var zeroSysProcAttr syscall.SysProcAttr
+
+// Has minor changes to support file inheritance.
+func syscallStartProcess(argv0 string, argv []string, attr *syscall.ProcAttr) (pid int, handle uintptr, err error) {
+ if len(argv0) == 0 {
+ return 0, 0, syscall.EWINDOWS
+ }
+ if attr == nil {
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
+ }
+
+ if len(attr.Files) < 3 {
+ return 0, 0, syscall.EINVAL
+ }
+
+ if len(attr.Dir) != 0 {
+ // StartProcess assumes that argv0 is relative to attr.Dir,
+ // because it implies Chdir(attr.Dir) before executing argv0.
+ // Windows CreateProcess assumes the opposite: it looks for
+ // argv0 relative to the current directory, and, only once the new
+ // process is started, it does Chdir(attr.Dir). We are adjusting
+ // for that difference here by making argv0 absolute.
+ var err error
+ argv0, err = joinExeDirAndFName(attr.Dir, argv0)
+ if err != nil {
+ return 0, 0, err
+ }
+ }
+ argv0p, err := syscall.UTF16PtrFromString(argv0)
+ if err != nil {
+ return 0, 0, err
+ }
+
+ var cmdline string
+ // Windows CreateProcess takes the command line as a single string:
+ // use attr.CmdLine if set, else build the command line by escaping
+ // and joining each argument with spaces
+ if sys.CmdLine != "" {
+ cmdline = sys.CmdLine
+ } else {
+ cmdline = makeCmdLine(argv)
+ }
+
+ var argvp *uint16
+ if len(cmdline) != 0 {
+ argvp, err = syscall.UTF16PtrFromString(cmdline)
+ if err != nil {
+ return 0, 0, err
+ }
+ }
+
+ var dirp *uint16
+ if len(attr.Dir) != 0 {
+ dirp, err = syscall.UTF16PtrFromString(attr.Dir)
+ if err != nil {
+ return 0, 0, err
+ }
+ }
+
+ // Acquire the fork lock so that no other threads
+ // create new fds that are not yet close-on-exec
+ // before we fork.
+ syscall.ForkLock.Lock()
+ defer syscall.ForkLock.Unlock()
+
+ p, _ := syscall.GetCurrentProcess()
+ fd := make([]syscall.Handle, len(attr.Files))
+ for i := range attr.Files {
+ if attr.Files[i] <= 0 {
+ continue
+ }
+ if i < 3 {
+ err := syscall.DuplicateHandle(p, syscall.Handle(attr.Files[i]), p, &fd[i], 0, true, syscall.DUPLICATE_SAME_ACCESS)
+ if err != nil {
+ return 0, 0, err
+ }
+ defer syscall.CloseHandle(syscall.Handle(fd[i]))
+ } else {
+ // This is the modification that allows files to be inherited.
+ syscall.SetHandleInformation(syscall.Handle(attr.Files[i]), syscall.HANDLE_FLAG_INHERIT, 1)
+ defer syscall.SetHandleInformation(syscall.Handle(attr.Files[i]), syscall.HANDLE_FLAG_INHERIT, 0)
+ }
+ }
+ si := new(syscall.StartupInfo)
+ si.Cb = uint32(unsafe.Sizeof(*si))
+ si.Flags = syscall.STARTF_USESTDHANDLES
+ if sys.HideWindow {
+ si.Flags |= syscall.STARTF_USESHOWWINDOW
+ si.ShowWindow = syscall.SW_HIDE
+ }
+ si.StdInput = fd[0]
+ si.StdOutput = fd[1]
+ si.StdErr = fd[2]
+
+ pi := new(syscall.ProcessInformation)
+
+ flags := sys.CreationFlags | syscall.CREATE_UNICODE_ENVIRONMENT
+ err = syscall.CreateProcess(argv0p, argvp, nil, nil, true, flags, createEnvBlock(attr.Env), dirp, si, pi)
+ if err != nil {
+ return 0, 0, err
+ }
+ defer syscall.CloseHandle(syscall.Handle(pi.Thread))
+
+ return int(pi.ProcessId), uintptr(pi.Process), nil
}
diff --git a/plugin/rpcplugin/supervisor_test.go b/plugin/rpcplugin/supervisor_test.go
index 1d046bf82..438ebe02a 100644
--- a/plugin/rpcplugin/supervisor_test.go
+++ b/plugin/rpcplugin/supervisor_test.go
@@ -18,7 +18,7 @@ func TestSupervisor(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(dir)
- backend := filepath.Join(dir, "backend")
+ backend := filepath.Join(dir, "backend.exe")
compileGo(t, `
package main
@@ -42,7 +42,7 @@ func TestSupervisor(t *testing.T) {
}
`, backend)
- ioutil.WriteFile(filepath.Join(dir, "plugin.json"), []byte(`{"id": "foo", "backend": {"executable": "backend"}}`), 0600)
+ ioutil.WriteFile(filepath.Join(dir, "plugin.json"), []byte(`{"id": "foo", "backend": {"executable": "backend.exe"}}`), 0600)
bundle := plugin.BundleInfoForPath(dir)
supervisor, err := SupervisorProvider(bundle)
@@ -58,7 +58,7 @@ func TestSupervisor_StartTimeout(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(dir)
- backend := filepath.Join(dir, "backend")
+ backend := filepath.Join(dir, "backend.exe")
compileGo(t, `
package main
@@ -68,7 +68,7 @@ func TestSupervisor_StartTimeout(t *testing.T) {
}
`, backend)
- ioutil.WriteFile(filepath.Join(dir, "plugin.json"), []byte(`{"id": "foo", "backend": {"executable": "backend"}}`), 0600)
+ ioutil.WriteFile(filepath.Join(dir, "plugin.json"), []byte(`{"id": "foo", "backend": {"executable": "backend.exe"}}`), 0600)
bundle := plugin.BundleInfoForPath(dir)
supervisor, err := SupervisorProvider(bundle)
@@ -82,7 +82,7 @@ func TestSupervisor_PluginCrash(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(dir)
- backend := filepath.Join(dir, "backend")
+ backend := filepath.Join(dir, "backend.exe")
compileGo(t, `
package main
@@ -109,7 +109,7 @@ func TestSupervisor_PluginCrash(t *testing.T) {
}
`, backend)
- ioutil.WriteFile(filepath.Join(dir, "plugin.json"), []byte(`{"id": "foo", "backend": {"executable": "backend"}}`), 0600)
+ ioutil.WriteFile(filepath.Join(dir, "plugin.json"), []byte(`{"id": "foo", "backend": {"executable": "backend.exe"}}`), 0600)
bundle := plugin.BundleInfoForPath(dir)
supervisor, err := SupervisorProvider(bundle)