veyron/lib/modules: allow Cleanup/Shutdown to access stderr and stdout.
Change-Id: I3447e4908720339ffc0d8f82cc3a77764ce02532
diff --git a/lib/expect/expect.go b/lib/expect/expect.go
index c36bec4..8f0bb72 100644
--- a/lib/expect/expect.go
+++ b/lib/expect/expect.go
@@ -100,16 +100,20 @@
s.verbose = v
}
-func (s *Session) log(format string, args ...interface{}) {
+func (s *Session) log(err error, format string, args ...interface{}) {
if !s.verbose {
return
}
_, path, line, _ := runtime.Caller(2)
+ errstr := ""
+ if err != nil {
+ errstr = err.Error() + ": "
+ }
loc := fmt.Sprintf("%s:%d", filepath.Base(path), line)
o := strings.TrimRight(fmt.Sprintf(format, args...), "\n\t ")
- vlog.VI(2).Infof("%s: %s", loc, o)
+ vlog.VI(2).Infof("%s: %s%s", loc, errstr, o)
if s.t == nil {
- fmt.Fprint(os.Stderr, loc, o)
+ fmt.Fprintf(os.Stderr, "%s: %s%s\n", loc, errstr, o)
return
}
s.t.Log(loc, o)
@@ -181,7 +185,7 @@
return
}
line, err := s.read(readLine)
- s.log("Expect: %v: %s", err, line)
+ s.log(err, "Expect: %s", line)
if err != nil {
s.error(err)
return
@@ -217,7 +221,7 @@
return [][]string{}
}
l, m, err := s.expectRE(pattern, n)
- s.log("ExpectRE: %v: %s", err, l)
+ s.log(err, "ExpectVar: %s", l)
if err != nil {
s.error(err)
return [][]string{}
@@ -235,7 +239,7 @@
return ""
}
l, m, err := s.expectRE(name+"=(.*)", 1)
- s.log("ExpectVar: %v: %s", err, l)
+ s.log(err, "ExpectVar: %s", l)
if err != nil {
s.error(err)
return ""
@@ -255,7 +259,7 @@
return ""
}
l, err := s.read(readLine)
- s.log("Readline: %v: %s", err, l)
+ s.log(err, "Readline: %s", l)
if err != nil {
s.error(err)
}
diff --git a/lib/modules/core/core_test.go b/lib/modules/core/core_test.go
index 6d1731d..a9094bb 100644
--- a/lib/modules/core/core_test.go
+++ b/lib/modules/core/core_test.go
@@ -21,7 +21,7 @@
func TestCommands(t *testing.T) {
shell := core.NewShell()
- defer shell.Cleanup(os.Stderr)
+ defer shell.Cleanup(nil, os.Stderr)
for _, c := range []string{core.RootMTCommand, core.MTCommand} {
if len(shell.Help(c)) == 0 {
t.Fatalf("missing command %q", c)
@@ -37,9 +37,9 @@
sh := core.NewShell()
return sh, func() {
if testing.Verbose() {
- sh.Cleanup(os.Stderr)
+ sh.Cleanup(os.Stderr, os.Stderr)
} else {
- sh.Cleanup(nil)
+ sh.Cleanup(nil, nil)
}
}
}
@@ -56,7 +56,6 @@
s.ExpectVar("MT_ADDR")
s.ExpectVar("PID")
root.CloseStdin()
- s.Expect("PASS")
}
func startMountTables(t *testing.T, sh *modules.Shell, mountPoints ...string) (map[string]string, error) {
@@ -235,7 +234,7 @@
if got, want := resolverSession.ExpectVar("R0"), addr; got != want {
t.Errorf("got %v, want %v", got, want)
}
- if err = resolver.Shutdown(nil); err != nil {
+ if err = resolver.Shutdown(nil, os.Stderr); err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -252,7 +251,7 @@
if got, want := resolverSession.ExpectVar("R0"), addr; got != want {
t.Fatalf("got %v, want %v", got, want)
}
- if err := resolver.Shutdown(nil); err != nil {
+ if err := resolver.Shutdown(nil, os.Stderr); err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -261,7 +260,7 @@
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
- if err := nsroots.Shutdown(nil); err != nil {
+ if err := nsroots.Shutdown(nil, os.Stderr); err != nil {
t.Fatalf("unexpected error: %s", err)
}
@@ -276,16 +275,11 @@
if got, want := resolverSession.ExpectVar("R0"), addr; got != want {
t.Fatalf("got %v, want %v", got, want)
}
- if err := resolver.Shutdown(nil); err != nil {
+ if err := resolver.Shutdown(nil, os.Stderr); err != nil {
t.Fatalf("unexpected error: %s", err)
}
}
func TestHelperProcess(t *testing.T) {
- if !modules.IsTestHelperProcess() {
- return
- }
- if err := modules.Dispatch(); err != nil {
- t.Fatalf("failed: %v", err)
- }
+ modules.DispatchInTest()
}
diff --git a/lib/modules/core/echo.go b/lib/modules/core/echo.go
index f3c3fce..459e7fe 100644
--- a/lib/modules/core/echo.go
+++ b/lib/modules/core/echo.go
@@ -37,10 +37,10 @@
}
func echoServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 2 {
+ if len(args) != 3 {
return fmt.Errorf("wrong # args")
}
- id, mp := args[0], args[1]
+ id, mp := args[1], args[2]
disp := &treeDispatcher{id: id}
server, err := rt.R().NewServer()
if err != nil {
@@ -62,11 +62,11 @@
}
func echoClient(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) < 2 {
+ if len(args) < 3 {
return fmt.Errorf("wrong # args")
}
- name := args[0]
- args = args[1:]
+ name := args[1]
+ args = args[2:]
client := rt.R().Client()
for _, a := range args {
ctxt := rt.R().NewContext()
diff --git a/lib/modules/core/misc.go b/lib/modules/core/misc.go
index 033fd09..47f6ba9 100644
--- a/lib/modules/core/misc.go
+++ b/lib/modules/core/misc.go
@@ -13,9 +13,9 @@
func sleep(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
d := time.Second
- if len(args) > 0 {
+ if len(args) > 1 {
var err error
- if d, err = time.ParseDuration(args[0]); err != nil {
+ if d, err = time.ParseDuration(args[1]); err != nil {
return err
}
}
@@ -42,10 +42,10 @@
}
func mountServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 3 {
+ if len(args) != 4 {
return fmt.Errorf("wrong # args")
}
- mp, server, ttlstr := args[0], args[1], args[2]
+ mp, server, ttlstr := args[1], args[2], args[3]
ttl, err := time.ParseDuration(ttlstr)
if err != nil {
return fmt.Errorf("failed to parse time from %q", ttlstr)
@@ -59,11 +59,11 @@
}
func namespaceCache(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 1 {
+ if len(args) != 2 {
return fmt.Errorf("wrong # args")
}
disable := true
- switch args[0] {
+ switch args[1] {
case "on":
disable = false
case "off":
diff --git a/lib/modules/core/mounttable.go b/lib/modules/core/mounttable.go
index d21d2c0..b013862 100644
--- a/lib/modules/core/mounttable.go
+++ b/lib/modules/core/mounttable.go
@@ -23,14 +23,14 @@
}
func mountTable(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 1 {
+ if len(args) != 2 {
return fmt.Errorf("expected exactly one argument: <mount point>")
}
return runMT(false, stdin, stdout, stderr, env, args...)
}
func rootMountTable(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 0 {
+ if len(args) != 1 {
return fmt.Errorf("expected no arguments")
}
return runMT(true, stdin, stdout, stderr, env, args...)
@@ -44,7 +44,7 @@
}
mp := ""
if !root {
- mp = args[0]
+ mp = args[1]
}
mt, err := mounttable.NewMountTable("")
if err != nil {
@@ -67,6 +67,7 @@
func ls(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
details := false
+ args = args[1:] // skip over comamnd name
if len(args) > 0 && args[0] == "-l" {
details = true
args = args[1:]
@@ -106,10 +107,10 @@
type resolver func(ctx context.T, name string) (names []string, err error)
func resolve(fn resolver, stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
- if len(args) != 1 {
+ if len(args) != 2 {
return fmt.Errorf("wrong # args")
}
- name := args[0]
+ name := args[1]
servers, err := fn(rt.R().NewContext(), name)
if err != nil {
fmt.Fprintf(stdout, "RN=0\n")
@@ -132,5 +133,8 @@
func setNamespaceRoots(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
ns := rt.R().Namespace()
- return ns.SetRoots(args...)
+ if len(args) < 2 {
+ return fmt.Errorf("wrong # args")
+ }
+ return ns.SetRoots(args[1:]...)
}
diff --git a/lib/modules/exec.go b/lib/modules/exec.go
index b2a12da..5be34de 100644
--- a/lib/modules/exec.go
+++ b/lib/modules/exec.go
@@ -1,11 +1,9 @@
package modules
import (
- "bufio"
"flag"
"fmt"
"io"
- "io/ioutil"
"os"
"os/exec"
"strings"
@@ -137,7 +135,8 @@
newargs := append(testFlags(), args...)
cmd := exec.Command(os.Args[0], newargs...)
cmd.Env = append(sh.mergeOSEnvSlice(), eh.entryPoint)
- stderr, err := ioutil.TempFile("", "__modules__"+strings.TrimLeft(eh.entryPoint, "-\n\t "))
+ fname := strings.TrimPrefix(eh.entryPoint, ShellEntryPoint+"=")
+ stderr, err := newLogfile(strings.TrimLeft(fname, "-\n\t "))
if err != nil {
return nil, err
}
@@ -164,28 +163,37 @@
return eh, err
}
-func (eh *execHandle) Shutdown(output io.Writer) error {
+func (eh *execHandle) Shutdown(stdout, stderr io.Writer) error {
eh.mu.Lock()
defer eh.mu.Unlock()
eh.stdin.Close()
+ logFile := eh.stderr.Name()
defer eh.sh.forget(eh)
- if eh.stderr != nil {
- defer func() {
- eh.stderr.Close()
- os.Remove(eh.stderr.Name())
- }()
- if output == nil {
- return eh.cmd.Wait()
- }
- if _, err := eh.stderr.Seek(0, 0); err != nil {
- return eh.cmd.Wait()
- }
- scanner := bufio.NewScanner(eh.stderr)
- for scanner.Scan() {
- fmt.Fprintf(output, "%s\n", scanner.Text())
- }
+
+ defer func() {
+ os.Remove(logFile)
+ }()
+
+ if stdout == nil && stderr == nil {
+ return eh.cmd.Wait()
}
- return eh.cmd.Wait()
+ // Read from stdin before waiting for the child process to ensure
+ // that we get to read all of its output.
+ readTo(eh.stdout, stdout)
+
+ procErr := eh.cmd.Wait()
+
+ // Stderr is buffered to a file, so we can safely read it after we
+ // wait for the process.
+ eh.stderr.Close()
+ stderrFile, err := os.Open(logFile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "failed to open %q: %s", logFile, err)
+ return procErr
+ }
+ readTo(stderrFile, stderr)
+ stderrFile.Close()
+ return procErr
}
const ShellEntryPoint = "VEYRON_SHELL_HELPER_PROCESS_ENTRY_POINT"
@@ -196,7 +204,25 @@
child.mains[name] = main
}
+// DispatchInTest will execute the requested subproccess command from within
+// a unit test run as a subprocess.
+func DispatchInTest() {
+ if !IsTestHelperProcess() {
+ return
+ }
+ if err := child.dispatch(); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed: %s\n", err)
+ os.Exit(1)
+ }
+ os.Exit(0)
+}
+
+// Dispatch will execute the request subprocess command from a within a
+// a subprocess that is not a unit test.
func Dispatch() error {
+ if IsTestHelperProcess() {
+ return fmt.Errorf("use DispatchInTest in unittests")
+ }
return child.dispatch()
}
diff --git a/lib/modules/func.go b/lib/modules/func.go
index f44127b..6273c64 100644
--- a/lib/modules/func.go
+++ b/lib/modules/func.go
@@ -1,7 +1,6 @@
package modules
import (
- "bufio"
"fmt"
"io"
"os"
@@ -12,12 +11,13 @@
r, w *os.File
}
type functionHandle struct {
- mu sync.Mutex
- main Main
- stdin, stderr, stdout pipe
- err error
- sh *Shell
- wg sync.WaitGroup
+ mu sync.Mutex
+ main Main
+ stdin, stdout pipe
+ stderr *os.File
+ err error
+ sh *Shell
+ wg sync.WaitGroup
}
func newFunctionHandle(main Main) command {
@@ -33,7 +33,7 @@
func (fh *functionHandle) Stderr() io.Reader {
fh.mu.Lock()
defer fh.mu.Unlock()
- return fh.stderr.r
+ return os.NewFile(fh.stderr.Fd(), "stderr")
}
func (fh *functionHandle) Stdin() io.Writer {
@@ -52,19 +52,24 @@
fh.mu.Lock()
defer fh.mu.Unlock()
fh.sh = sh
- for _, p := range []*pipe{&fh.stdin, &fh.stdout, &fh.stderr} {
+ for _, p := range []*pipe{&fh.stdin, &fh.stdout} {
var err error
if p.r, p.w, err = os.Pipe(); err != nil {
return nil, err
}
}
+ stderr, err := newLogfile(args[0])
+ if err != nil {
+ return nil, err
+ }
+ fh.stderr = stderr
fh.wg.Add(1)
go func() {
fh.mu.Lock()
stdin := fh.stdin.r
stdout := fh.stdout.w
- stderr := fh.stderr.w
+ stderr := fh.stderr
main := fh.main
fh.mu.Unlock()
@@ -76,7 +81,6 @@
fh.mu.Lock()
fh.stdin.r.Close()
fh.stdout.w.Close()
- fh.stderr.w.Close()
fh.err = err
fh.mu.Unlock()
fh.wg.Done()
@@ -84,26 +88,34 @@
return fh, nil
}
-func (fh *functionHandle) Shutdown(output io.Writer) error {
+func (fh *functionHandle) Shutdown(stdout_w, stderr_w io.Writer) error {
fh.mu.Lock()
fh.stdin.w.Close()
- stderr := fh.stderr.r
+ stdout := fh.stdout.r
+ stderr := fh.stderr
fh.mu.Unlock()
- if output != nil {
- scanner := bufio.NewScanner(stderr)
- for scanner.Scan() {
- l := scanner.Text()
- fmt.Fprintf(output, "%s\n", l)
- }
+ // Read stdout until EOF to ensure that we read all of it.
+ readTo(stdout, stdout_w)
+ fh.wg.Wait()
+
+ fh.mu.Lock()
+ funcErr := fh.err
+ fh.mu.Unlock()
+
+ // Safe to close stderr now.
+ stderr.Close()
+ stderr, err := os.Open(stderr.Name())
+ if err == nil {
+ readTo(stderr, stderr_w)
+ stderr.Close()
+ } else {
+ fmt.Fprintf(os.Stderr, "failed to open %q: %s", stderr.Name(), err)
}
- fh.wg.Wait()
fh.mu.Lock()
fh.stdout.r.Close()
- fh.stderr.r.Close()
- err := fh.err
fh.sh.forget(fh)
fh.mu.Unlock()
- return err
+ return funcErr
}
diff --git a/lib/modules/modules_internal_test.go b/lib/modules/modules_internal_test.go
index 000819b..c5e686e 100644
--- a/lib/modules/modules_internal_test.go
+++ b/lib/modules/modules_internal_test.go
@@ -43,7 +43,7 @@
assertNumHandles(t, sh, 2)
for i, h := range []Handle{hs, hf} {
- if got := h.Shutdown(nil); got != nil {
+ if got := h.Shutdown(nil, nil); got != nil {
t.Errorf("%d: got %q, want %q", i, got, nil)
}
}
@@ -53,6 +53,6 @@
hf, _ = sh.Start("echof", "c")
assertNumHandles(t, sh, 2)
- sh.Cleanup(nil)
+ sh.Cleanup(nil, nil)
assertNumHandles(t, sh, 0)
}
diff --git a/lib/modules/modules_test.go b/lib/modules/modules_test.go
index cd7db53..7320eb6 100644
--- a/lib/modules/modules_test.go
+++ b/lib/modules/modules_test.go
@@ -2,9 +2,9 @@
import (
"bufio"
+ "bytes"
"fmt"
"io"
- "os"
"testing"
"time"
@@ -13,9 +13,31 @@
func init() {
modules.RegisterChild("envtest", PrintEnv)
+ modules.RegisterChild("echo", Echo)
modules.RegisterChild("errortest", ErrorMain)
}
+func Echo(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+ for _, a := range args {
+ fmt.Fprintf(stdout, "stdout: %s\n", a)
+ fmt.Fprintf(stderr, "stderr: %s\n", a)
+ }
+ return nil
+}
+
+func Print(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+ for _, a := range args {
+ if v := env[a]; len(v) > 0 {
+ fmt.Fprintf(stdout, a+"="+v+"\n")
+ } else {
+ fmt.Fprintf(stderr, "missing %s\n", a)
+ }
+ }
+ modules.WaitForEOF(stdin)
+ fmt.Fprintf(stdout, "done\n")
+ return nil
+}
+
func PrintEnv(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
for _, a := range args {
if v := env[a]; len(v) > 0 {
@@ -53,7 +75,14 @@
t.Fatalf("unexpected error: %s", err)
}
defer func() {
- sh.Cleanup(os.Stderr)
+ var stdout, stderr bytes.Buffer
+ sh.Cleanup(&stdout, &stderr)
+ if len(stdout.String()) != 0 {
+ t.Errorf("unexpected stdout: %q", stdout.String())
+ }
+ if len(stderr.String()) != 0 {
+ t.Errorf("unexpected stderr: %q", stderr.String())
+ }
}()
scanner := bufio.NewScanner(h.Stdout())
if !waitForInput(scanner) {
@@ -71,13 +100,14 @@
if got, want := scanner.Text(), "done"; got != want {
t.Errorf("got %q, want %q", got, want)
}
- if err := h.Shutdown(nil); err != nil {
+ if err := h.Shutdown(nil, nil); err != nil {
t.Fatalf("unexpected error: %s", err)
}
}
func TestChild(t *testing.T) {
sh := modules.NewShell()
+ defer sh.Cleanup(nil, nil)
key, val := "simpleVar", "foo & bar"
sh.SetVar(key, val)
sh.AddSubprocess("envtest", "envtest: <variables to print>...")
@@ -86,6 +116,7 @@
func TestFunction(t *testing.T) {
sh := modules.NewShell()
+ defer sh.Cleanup(nil, nil)
key, val := "simpleVar", "foo & bar & baz"
sh.SetVar(key, val)
sh.AddFunction("envtest", PrintEnv, "envtest: <variables to print>...")
@@ -94,35 +125,67 @@
func TestErrorChild(t *testing.T) {
sh := modules.NewShell()
+ defer sh.Cleanup(nil, nil)
sh.AddSubprocess("errortest", "")
h, err := sh.Start("errortest")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
- if got, want := h.Shutdown(nil), "exit status 1"; got == nil || got.Error() != want {
+ if got, want := h.Shutdown(nil, nil), "exit status 1"; got == nil || got.Error() != want {
t.Errorf("got %q, want %q", got, want)
}
}
+func testShutdown(t *testing.T, sh *modules.Shell) {
+ result := ""
+ args := []string{"a", "b c", "ddd"}
+ if _, err := sh.Start("echo", args...); err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ var stdoutBuf bytes.Buffer
+ var stderrBuf bytes.Buffer
+ sh.Cleanup(&stdoutBuf, &stderrBuf)
+ stdoutOutput, stderrOutput := "stdout: echo\n", "stderr: echo\n"
+ for _, a := range args {
+ stdoutOutput += fmt.Sprintf("stdout: %s\n", a)
+ stderrOutput += fmt.Sprintf("stderr: %s\n", a)
+ }
+ if got, want := stdoutBuf.String(), stdoutOutput+result; got != want {
+ t.Errorf("got %q want %q", got, want)
+ }
+ if got, want := stderrBuf.String(), stderrOutput; got != want {
+ t.Errorf("got %q want %q", got, want)
+ }
+
+}
+
+func TestShutdownSubprocess(t *testing.T) {
+ sh := modules.NewShell()
+ sh.AddSubprocess("echo", "[args]*")
+ testShutdown(t, sh)
+}
+
+func TestShutdownFunction(t *testing.T) {
+ sh := modules.NewShell()
+ sh.AddFunction("echo", Echo, "[args]*")
+ testShutdown(t, sh)
+}
+
func TestErrorFunc(t *testing.T) {
sh := modules.NewShell()
+ defer sh.Cleanup(nil, nil)
sh.AddFunction("errortest", ErrorMain, "")
h, err := sh.Start("errortest")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
- if got, want := h.Shutdown(nil), "an error"; got != nil && got.Error() != want {
+ if got, want := h.Shutdown(nil, nil), "an error"; got != nil && got.Error() != want {
t.Errorf("got %q, want %q", got, want)
}
}
func TestHelperProcess(t *testing.T) {
- if !modules.IsTestHelperProcess() {
- return
- }
- if err := modules.Dispatch(); err != nil {
- t.Fatalf("failed: %v", err)
- }
+ modules.DispatchInTest()
}
// TODO(cnicolaou): more complete tests for environment variables,
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index 561e3b2..26c3869 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -175,7 +175,7 @@
sh.mu.Unlock()
return nil, fmt.Errorf("command %q is not available", command)
}
- expanded := sh.expand(args...)
+ expanded := append([]string{command}, sh.expand(args...)...)
sh.mu.Unlock()
h, err := cmd.factory().start(sh, expanded...)
if err != nil {
@@ -238,10 +238,9 @@
}
// Cleanup calls Shutdown on all of the Handles currently being tracked
-// by the Shell. Any buffered output from the command's stderr stream
-// will be written to the supplied io.Writer. If the io.Writer is nil
-// then any such output is lost.
-func (sh *Shell) Cleanup(output io.Writer) {
+// by the Shell and writes to stdout and stderr as per the Shutdown
+// method in the Handle interface.
+func (sh *Shell) Cleanup(stdout, stderr io.Writer) {
sh.mu.Lock()
handles := make(map[Handle]struct{})
for k, v := range sh.handles {
@@ -250,7 +249,7 @@
sh.handles = make(map[Handle]struct{})
sh.mu.Unlock()
for k, _ := range handles {
- k.Shutdown(output)
+ k.Shutdown(stdout, stderr)
}
if len(sh.idfile) > 0 {
os.Remove(sh.idfile)
@@ -277,10 +276,11 @@
CloseStdin()
// Shutdown closes the Stdin for the command and then reads output
- // from the command's stdout until it encounters EOF and writes that
- // output to the supplied io.Writer. It returns any error returned by
- // the command.
- Shutdown(io.Writer) error
+ // from the command's stdout until it encounters EOF, waits for
+ // the command to complete and then reads all of its stderr output.
+ // The stdout and stderr contents are written to the corresponding
+ // io.Writers if they are non-nil, otherwise the content is discarded.
+ Shutdown(stdout, stderr io.Writer) error
}
// command is used to abstract the implementations of inprocess and subprocess
diff --git a/lib/modules/util.go b/lib/modules/util.go
new file mode 100644
index 0000000..21fc4c2
--- /dev/null
+++ b/lib/modules/util.go
@@ -0,0 +1,27 @@
+package modules
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+func newLogfile(prefix string) (*os.File, error) {
+ f, err := ioutil.TempFile("", "__modules__"+prefix)
+ if err != nil {
+ return nil, err
+ }
+ return f, nil
+}
+
+func readTo(r io.Reader, w io.Writer) {
+ if w == nil {
+ return
+ }
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ fmt.Fprintf(w, "%s\n", scanner.Text())
+ }
+}
diff --git a/tools/naming/simulator/commands.go b/tools/naming/simulator/commands.go
index 3ec00dc..b11a3da 100644
--- a/tools/naming/simulator/commands.go
+++ b/tools/naming/simulator/commands.go
@@ -105,7 +105,7 @@
func readStderr(state *cmdState) (string, error) {
var b bytes.Buffer
- if err := state.Handle.Shutdown(&b); err != nil && err != io.EOF {
+ if err := state.Handle.Shutdown(nil, &b); err != nil && err != io.EOF {
return b.String(), err
}
return b.String(), nil
@@ -182,7 +182,7 @@
func quit(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
r := ""
for k, h := range handles {
- if err := h.Handle.Shutdown(os.Stdout); err != nil {
+ if err := h.Handle.Shutdown(os.Stdout, os.Stdout); err != nil {
r += fmt.Sprintf("%s: %v\n", k, err)
} else {
r += fmt.Sprintf("%s: ok\n", k)
diff --git a/tools/naming/simulator/driver.go b/tools/naming/simulator/driver.go
index b9c91ba..60028b5 100644
--- a/tools/naming/simulator/driver.go
+++ b/tools/naming/simulator/driver.go
@@ -100,7 +100,6 @@
if os.Getenv(modules.ShellEntryPoint) != "" {
// Subprocess, run the requested command.
if err := modules.Dispatch(); err != nil {
- fmt.Fprintf(os.Stdout, "failed: %v\n", err)
fmt.Fprintf(os.Stderr, "failed: %v\n", err)
return
}
@@ -108,7 +107,7 @@
}
shell := modules.NewShell()
- defer shell.Cleanup(os.Stderr)
+ defer shell.Cleanup(os.Stderr, os.Stderr)
if os.Getenv("VEYRON_IDENTITY") == "" {
shell.CreateAndUseNewID()
}
diff --git a/tools/naming/simulator/t.scr b/tools/naming/simulator/t.scr
deleted file mode 100644
index adf0571..0000000
--- a/tools/naming/simulator/t.scr
+++ /dev/null
@@ -1,5 +0,0 @@
-mount a b
-set w=$_
-read $w
-read $w
-wait $w
diff --git a/tools/naming/simulator/test.sh b/tools/naming/simulator/test.sh
new file mode 100755
index 0000000..040625c
--- /dev/null
+++ b/tools/naming/simulator/test.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# Test the simulator command-line tool.
+#
+
+source "${VEYRON_ROOT}/scripts/lib/shell_test.sh"
+
+main() {
+ # Build binaries.
+ cd "${TMPDIR}"
+ local -r PKG=veyron.io/veyron/veyron/tools/naming/simulator
+ veyron go build "${PKG}" || shell_test::fail "line ${LINENO}: failed to build simulator"
+
+ local -r DIR=$(shell::go_package_dir "${PKG}")
+ local file
+ for file in ${DIR}/*.scr; do
+ echo $file
+ ./simulator < $file > /dev/null 2>&1 || shell_test::fail "failed for $file"
+ done
+ shell_test::pass
+}
+
+main "$@"