veyron/tools/naming/simulator: tidy up error handling, make sleep interruptible.
Change-Id: I2fae361a21c10d5419075970c32c7d02c9831a18
diff --git a/lib/expect/expect.go b/lib/expect/expect.go
index d5f738d..c36bec4 100644
--- a/lib/expect/expect.go
+++ b/lib/expect/expect.go
@@ -58,11 +58,11 @@
// Session represents the state of an expect session.
type Session struct {
- input *bufio.Reader
- timeout time.Duration
- t Testing
- verbose bool
- err error
+ input *bufio.Reader
+ timeout time.Duration
+ t Testing
+ verbose bool
+ oerr, err error
}
type Testing interface {
@@ -81,10 +81,18 @@
}
// Error returns the error code (possibly nil) currently stored in the Session.
+// This will include the file and line of the calling function that experienced
+// the error. Use OriginalError to obtain the original error code.
func (s *Session) Error() error {
return s.err
}
+// OriginalError returns any error code (possibly nil) returned by the
+// underlying library routines called.
+func (s *Session) OriginalError() error {
+ return s.oerr
+}
+
// SetVerbosity enables/disable verbose debugging information, in particular,
// every line of input read will be logged via Testing.Logf or, if it is nil,
// to stderr.
@@ -120,6 +128,7 @@
// be incorrect.
func (s *Session) error(err error) error {
_, file, line, _ := runtime.Caller(2)
+ s.oerr = err
s.err = fmt.Errorf("%s:%d: %s", filepath.Base(file), line, err)
s.ReportError()
return s.err
diff --git a/lib/modules/core/misc.go b/lib/modules/core/misc.go
index e0c1496..033fd09 100644
--- a/lib/modules/core/misc.go
+++ b/lib/modules/core/misc.go
@@ -7,6 +7,8 @@
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
+
+ "veyron.io/veyron/veyron/lib/modules"
)
func sleep(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
@@ -17,10 +19,20 @@
return err
}
}
- fmt.Fprintf(stdout, "Sleeping for %s", d)
- // TODO(cnicolaou): we should probably also listen for stdin closing
- // and return before the sleep completes.
- time.Sleep(d)
+ fmt.Fprintf(stdout, "Sleeping for %s\n", d)
+ eof := make(chan struct{})
+ go func() {
+ modules.WaitForEOF(stdin)
+ close(eof)
+ }()
+
+ then := time.Now()
+ select {
+ case <-time.After(d):
+ fmt.Fprintf(stdout, "Slept for %s\n", time.Now().Sub(then))
+ case <-eof:
+ fmt.Fprintf(stdout, "Aborted after %s\n", time.Now().Sub(then))
+ }
return nil
}
diff --git a/lib/modules/func.go b/lib/modules/func.go
index 319a673..f44127b 100644
--- a/lib/modules/func.go
+++ b/lib/modules/func.go
@@ -70,9 +70,6 @@
err := main(stdin, stdout, stderr, sh.mergeOSEnv(), args...)
if err != nil {
- // Print the error to stdout to ensure that anyone reading
- // only stdout sees the error.
- fmt.Fprintf(stdout, "%s\n", err)
fmt.Fprintf(stderr, "%s\n", err)
}
diff --git a/tools/naming/simulator/ambiguity.scr b/tools/naming/simulator/ambiguity.scr
index 2974986..1df3410 100644
--- a/tools/naming/simulator/ambiguity.scr
+++ b/tools/naming/simulator/ambiguity.scr
@@ -37,9 +37,12 @@
mount $s2/b $s3/c 1h
echoServer "Echo" $s3/c
+set es_h=$_
ls $s1/...
wait $_
ls $s1/a
wait $_
+
+stop $es_h
diff --git a/tools/naming/simulator/commands.go b/tools/naming/simulator/commands.go
index b05538a..3ec00dc 100644
--- a/tools/naming/simulator/commands.go
+++ b/tools/naming/simulator/commands.go
@@ -1,7 +1,9 @@
package main
import (
+ "bytes"
"fmt"
+ "io"
"os"
"regexp"
"strings"
@@ -26,6 +28,7 @@
"read": {-1, "read <handle> [var]", true, read},
"eval": {1, "eval <handle>", true, eval},
"wait": {1, "wait <handle>", true, wait},
+ "stop": {1, "stop <handle>", true, stop},
"list": {0, "list", false, list},
"quit": {0, "quit", false, quit},
}
@@ -100,6 +103,14 @@
return "", nil
}
+func readStderr(state *cmdState) (string, error) {
+ var b bytes.Buffer
+ if err := state.Handle.Shutdown(&b); err != nil && err != io.EOF {
+ return b.String(), err
+ }
+ return b.String(), nil
+}
+
func handleWrapper(sh *modules.Shell, fn builtinCmd, args ...string) (string, error) {
if len(args) < 1 {
return "", fmt.Errorf("missing handle argument")
@@ -108,7 +119,16 @@
if state == nil {
return "", fmt.Errorf("invalid handle")
}
- return fn(sh, state, args...)
+ errstr := ""
+ r, err := fn(sh, state, args...)
+ if err != nil {
+ errstr, _ = readStderr(state)
+ errstr = strings.TrimSuffix(errstr, "\n")
+ if len(errstr) > 0 {
+ err = fmt.Errorf("%s: %v", errstr, err)
+ }
+ }
+ return r, err
}
func read(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
@@ -116,15 +136,14 @@
for _, a := range args[1:] {
sh.SetVar(a, l)
}
- err := state.Session.Error()
- if err != nil && strings.HasSuffix(err.Error(), "EOF") {
- return l, fmt.Errorf("EOF")
- }
- return l, state.Session.Error()
+ return l, state.Session.OriginalError()
}
func eval(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
l := state.Session.ReadLine()
+ if err := state.Session.OriginalError(); err != nil {
+ return l, err
+ }
k, v, err := parseVar(l)
if err != nil {
return "", err
@@ -133,11 +152,23 @@
return l, nil
}
-func wait(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
+func stop(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
state.Handle.CloseStdin()
+ return wait(sh, state, args...)
+}
+
+func wait(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
+ // Read and return stdout
r, err := state.Session.Finish(nil)
delete(handles, args[0])
- return r, err
+ if err != nil {
+ return r, err
+ }
+ // Now read and return the contents of stderr as e
+ if str, err := readStderr(state); err != nil && err != io.EOF {
+ return str, err
+ }
+ return r, nil
}
func list(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
diff --git a/tools/naming/simulator/echo.scr b/tools/naming/simulator/echo.scr
index eb5cefc..788d1b0 100644
--- a/tools/naming/simulator/echo.scr
+++ b/tools/naming/simulator/echo.scr
@@ -15,7 +15,7 @@
read $ec line
assert $line "text: test"
-wait $es
+stop $es
wait $ec
# now use a nameserver.
@@ -53,3 +53,4 @@
eval $r
assert $R0 $root//a/b
+stop $es
diff --git a/tools/naming/simulator/mt_complex.scr b/tools/naming/simulator/mt_complex.scr
index a16a1f1..3a23946 100644
--- a/tools/naming/simulator/mt_complex.scr
+++ b/tools/naming/simulator/mt_complex.scr
@@ -5,12 +5,14 @@
cache off
root
-eval $_
+set root_h=$_
+eval $root_h
set root=$MT_NAME
set NAMESPACE_ROOT=$root
mt tl/a
set m=$_
+set mt_a_h=$m
eval $m
eval $m
set mt_a_name=$MT_NAME
@@ -18,6 +20,7 @@
mt tl/b
set m=$_
+set mt_b_h=$m
eval $m
eval $m
set mt_b_name=$MT_NAME
@@ -98,7 +101,7 @@
assert $R0 /$es_E1_addr//
# let's have the echo server shut down
-wait $es_E1
+stop $es_E1
# and now, we can see the mount tables again.
ls ...
@@ -244,6 +247,8 @@
eval $r
# returns nothing since symlink is an 'interior' node.
assert $RN 0
+# don't close or wait for this command since it'll error out.
+
# resolveMT will return the original mount point
resolveMT tl/b/symlink
@@ -253,3 +258,9 @@
eval $r
assert $R0 /$mt_b_addr//$symlink_target
+stop $es_E3
+stop $es_E2
+
+quit
+
+