Merge "veyron/runtimes/google/rt: use modules instead of blackbox."
diff --git a/lib/modules/exec.go b/lib/modules/exec.go
index 5ca6f09..341b60f 100644
--- a/lib/modules/exec.go
+++ b/lib/modules/exec.go
@@ -133,7 +133,10 @@
eh.mu.Lock()
defer eh.mu.Unlock()
eh.sh = sh
- newargs := append(testFlags(), args...)
+ // Take care to not pass the command line as an arg to the child
+ // process since that'll prevent parsing any subsequent args by
+ // the flag package.
+ newargs := append(testFlags(), args[1:]...)
cmd := exec.Command(os.Args[0], newargs...)
cmd.Env = append(sh.mergeOSEnvSlice(), eh.entryPoint)
fname := strings.TrimPrefix(eh.entryPoint, ShellEntryPoint+"=")
@@ -280,7 +283,8 @@
}
}(os.Getppid())
- return m.fn(os.Stdin, os.Stdout, os.Stderr, osEnvironMap(), flag.Args()...)
+ args := append([]string{command}, flag.Args()...)
+ return m.fn(os.Stdin, os.Stdout, os.Stderr, osEnvironMap(), args...)
}
func (child *childRegistrar) addSubprocesses(sh *Shell, pattern string) error {
diff --git a/lib/testutil/init.go b/lib/testutil/init.go
index 9cc119f..07fa6d4 100644
--- a/lib/testutil/init.go
+++ b/lib/testutil/init.go
@@ -20,6 +20,7 @@
// flag.Parse in init() is the right solution?
_ "testing"
"time"
+
_ "veyron.io/veyron/veyron/services/mgmt/suidhelper/impl/flag"
// Import blackbox to ensure that it gets to define its flags.
diff --git a/runtimes/google/rt/mgmt_test.go b/runtimes/google/rt/mgmt_test.go
index e15eaa2..bd0c97b 100644
--- a/runtimes/google/rt/mgmt_test.go
+++ b/runtimes/google/rt/mgmt_test.go
@@ -2,10 +2,12 @@
import (
"fmt"
+ "io"
"os"
"reflect"
"strings"
"testing"
+ "time"
"veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/ipc"
@@ -13,8 +15,9 @@
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/services/mgmt/appcycle"
+ "veyron.io/veyron/veyron/lib/expect"
+ "veyron.io/veyron/veyron/lib/modules"
_ "veyron.io/veyron/veyron/lib/testutil"
- "veyron.io/veyron/veyron/lib/testutil/blackbox"
"veyron.io/veyron/veyron/lib/testutil/security"
"veyron.io/veyron/veyron/profiles"
"veyron.io/veyron/veyron/runtimes/google/rt"
@@ -22,6 +25,18 @@
"veyron.io/veyron/veyron/services/mgmt/node"
)
+const (
+ noWaitersCmd = "noWaiters"
+ forceStopCmd = "forceStop"
+ appCmd = "app"
+)
+
+func init() {
+ modules.RegisterChild(noWaitersCmd, "", noWaiters)
+ modules.RegisterChild(forceStopCmd, "", forceStop)
+ modules.RegisterChild(appCmd, "", app)
+}
+
// TestBasic verifies that the basic plumbing works: LocalStop calls result in
// stop messages being sent on the channel passed to WaitForStop.
func TestBasic(t *testing.T) {
@@ -80,51 +95,57 @@
}
}
-func init() {
- blackbox.CommandTable["noWaiters"] = noWaiters
-}
-
-func noWaiters([]string) {
+func noWaiters(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
m, _ := rt.New()
- fmt.Println("ready")
- blackbox.WaitForEOFOnStdin()
+ fmt.Fprintf(stdout, "ready\n")
+ modules.WaitForEOF(stdin)
m.Stop()
os.Exit(42) // This should not be reached.
+ return nil
}
// TestNoWaiters verifies that the child process exits in the absence of any
// wait channel being registered with its runtime.
func TestNoWaiters(t *testing.T) {
- c := blackbox.HelperCommand(t, "noWaiters")
- defer c.Cleanup()
- c.Cmd.Start()
- c.Expect("ready")
- c.CloseStdin()
- c.ExpectEOFAndWaitForExitCode(fmt.Errorf("exit status %d", veyron2.UnhandledStopExitCode))
+ sh := modules.NewShell(noWaitersCmd)
+ defer sh.Cleanup(os.Stderr, os.Stderr)
+ h, err := sh.Start(noWaitersCmd)
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ expect.NewSession(t, h.Stdout(), time.Minute).Expect("ready")
+ want := fmt.Sprintf("exit status %d", veyron2.UnhandledStopExitCode)
+ if err = h.Shutdown(os.Stderr, os.Stderr); err == nil || err.Error() != want {
+ t.Errorf("got %v, want %s", err, want)
+ }
}
-func init() {
- blackbox.CommandTable["forceStop"] = forceStop
-}
-
-func forceStop([]string) {
+func forceStop(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
m, _ := rt.New()
- fmt.Println("ready")
- blackbox.WaitForEOFOnStdin()
+ fmt.Fprintf(stdout, "ready\n")
+ modules.WaitForEOF(stdin)
m.WaitForStop(make(chan string, 1))
m.ForceStop()
os.Exit(42) // This should not be reached.
+ return nil
}
// TestForceStop verifies that ForceStop causes the child process to exit
// immediately.
func TestForceStop(t *testing.T) {
- c := blackbox.HelperCommand(t, "forceStop")
- defer c.Cleanup()
- c.Cmd.Start()
- c.Expect("ready")
- c.CloseStdin()
- c.ExpectEOFAndWaitForExitCode(fmt.Errorf("exit status %d", veyron2.ForceStopExitCode))
+ sh := modules.NewShell(forceStopCmd)
+ defer sh.Cleanup(os.Stderr, os.Stderr)
+ h, err := sh.Start(forceStopCmd)
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ s := expect.NewSession(t, h.Stdout(), time.Minute)
+ s.Expect("ready")
+ err = h.Shutdown(os.Stderr, os.Stderr)
+ want := fmt.Sprintf("exit status %d", veyron2.UnhandledStopExitCode)
+ if err == nil || err.Error() != want {
+ t.Errorf("got %v, want %s", err, want)
+ }
}
func checkProgress(t *testing.T, ch <-chan veyron2.Task, progress, goal int) {
@@ -206,25 +227,21 @@
}
}
-func init() {
- blackbox.CommandTable["app"] = app
-}
-
-func app([]string) {
+func app(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
r, err := rt.New()
if err != nil {
- fmt.Printf("Error creating runtime: %v\n", err)
- return
+ return err
}
defer r.Cleanup()
ch := make(chan string, 1)
r.WaitForStop(ch)
- fmt.Printf("Got %s\n", <-ch)
+ fmt.Fprintf(stdout, "Got %s\n", <-ch)
r.AdvanceGoal(10)
- fmt.Println("Doing some work")
+ fmt.Fprintf(stdout, "Doing some work\n")
r.AdvanceProgress(2)
- fmt.Println("Doing some more work")
+ fmt.Fprintf(stdout, "Doing some more work\n")
r.AdvanceProgress(5)
+ return nil
}
type configServer struct {
@@ -258,27 +275,30 @@
}
-func setupRemoteAppCycleMgr(t *testing.T) (veyron2.Runtime, *blackbox.Child, appcycle.AppCycle, func()) {
+func setupRemoteAppCycleMgr(t *testing.T) (veyron2.Runtime, modules.Handle, appcycle.AppCycle, func()) {
// We need to use the public API since stubs are used below (and they
// refer to the global rt.R() function), but we take care to make sure
// that the "google" runtime we are trying to test in this package is
// the one being used.
r, _ := rt.New(veyron2.RuntimeOpt{veyron2.GoogleRuntimeName}, veyron2.ForceNewSecurityModel{})
- c := blackbox.HelperCommand(t, "app")
- childcreds := security.NewVeyronCredentials(r.Principal(), "app")
+
configServer, configServiceName, ch := createConfigServer(t, r)
- c.Cmd.Env = append(c.Cmd.Env, fmt.Sprintf("VEYRON_CREDENTIALS=%v", childcreds),
- fmt.Sprintf("%v=%v", mgmt.ParentNodeManagerConfigKey, configServiceName))
- c.Cmd.Start()
+ sh := modules.NewShell(appCmd)
+ sh.SetVar("VEYRON_CREDENTIALS", security.NewVeyronCredentials(r.Principal(), appCmd))
+ sh.SetVar(mgmt.ParentNodeManagerConfigKey, configServiceName)
+ h, err := sh.Start("app")
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
appCycleName := <-ch
appCycle, err := appcycle.BindAppCycle(appCycleName)
if err != nil {
t.Fatalf("Got error: %v", err)
}
- return r, c, appCycle, func() {
+ return r, h, appCycle, func() {
configServer.Stop()
- c.Cleanup()
- os.RemoveAll(childcreds)
+ sh.Cleanup(os.Stderr, os.Stderr)
// Don't do r.Cleanup() since the runtime needs to be used by
// more than one test case.
}
@@ -287,18 +307,25 @@
// TestRemoteForceStop verifies that the child process exits when sending it
// a remote ForceStop rpc.
func TestRemoteForceStop(t *testing.T) {
- r, c, appCycle, cleanup := setupRemoteAppCycleMgr(t)
+ r, h, appCycle, cleanup := setupRemoteAppCycleMgr(t)
defer cleanup()
if err := appCycle.ForceStop(r.NewContext()); err == nil || !strings.Contains(err.Error(), "EOF") {
t.Fatalf("Expected EOF error, got %v instead", err)
}
- c.ExpectEOFAndWaitForExitCode(fmt.Errorf("exit status %d", veyron2.ForceStopExitCode))
+ s := expect.NewSession(t, h.Stdout(), time.Minute)
+ s.ExpectEOF()
+ err := h.Shutdown(os.Stderr, os.Stderr)
+ want := fmt.Sprintf("exit status %d", veyron2.ForceStopExitCode)
+ if err == nil || err.Error() != want {
+ t.Errorf("got %v, want %s", err, want)
+ }
+
}
// TestRemoteStop verifies that the child shuts down cleanly when sending it
// a remote Stop rpc.
func TestRemoteStop(t *testing.T) {
- r, c, appCycle, cleanup := setupRemoteAppCycleMgr(t)
+ r, h, appCycle, cleanup := setupRemoteAppCycleMgr(t)
defer cleanup()
stream, err := appCycle.Stop(r.NewContext())
if err != nil {
@@ -323,8 +350,12 @@
if err := stream.Finish(); err != nil {
t.Errorf("Got error %v", err)
}
- c.Expect(fmt.Sprintf("Got %s", veyron2.RemoteStop))
- c.Expect("Doing some work")
- c.Expect("Doing some more work")
- c.ExpectEOFAndWait()
+ s := expect.NewSession(t, h.Stdout(), time.Minute)
+ s.Expect(fmt.Sprintf("Got %s", veyron2.RemoteStop))
+ s.Expect("Doing some work")
+ s.Expect("Doing some more work")
+ s.ExpectEOF()
+ if err := h.Shutdown(os.Stderr, os.Stderr); err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
}
diff --git a/runtimes/google/rt/rt_test.go b/runtimes/google/rt/rt_test.go
index 4faaf1c..51f2031 100644
--- a/runtimes/google/rt/rt_test.go
+++ b/runtimes/google/rt/rt_test.go
@@ -2,21 +2,24 @@
import (
"fmt"
+ "io"
"io/ioutil"
"os"
"reflect"
"regexp"
"testing"
-
- _ "veyron.io/veyron/veyron/lib/testutil"
- "veyron.io/veyron/veyron/lib/testutil/blackbox"
- irt "veyron.io/veyron/veyron/runtimes/google/rt"
+ "time"
"veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/vlog"
+
+ "veyron.io/veyron/veyron/lib/expect"
+ "veyron.io/veyron/veyron/lib/modules"
+ _ "veyron.io/veyron/veyron/lib/testutil"
+ irt "veyron.io/veyron/veyron/runtimes/google/rt"
)
type context struct {
@@ -37,11 +40,11 @@
func (*context) RemoteEndpoint() naming.Endpoint { return nil }
func init() {
- blackbox.CommandTable["child"] = child
+ modules.RegisterChild("child", "", child)
}
func TestHelperProcess(t *testing.T) {
- blackbox.HelperProcess(t)
+ modules.DispatchInTest()
}
func TestInit(t *testing.T) {
@@ -60,24 +63,24 @@
}
}
-func child(argv []string) {
+func child(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
r := rt.Init()
vlog.Infof("%s\n", r.Logger())
- fmt.Printf("%s\n", r.Logger())
- _ = r
- blackbox.WaitForEOFOnStdin()
+ fmt.Fprintf(stdout, "%s\n", r.Logger())
+ modules.WaitForEOF(stdin)
fmt.Printf("done\n")
+ return nil
}
func TestInitArgs(t *testing.T) {
- c := blackbox.HelperCommand(t, "child", "--logtostderr=true", "--vv=3", "--", "foobar")
- defer c.Cleanup()
- c.Cmd.Start()
- str, err := c.ReadLineFromChild()
+ sh := modules.NewShell("child")
+ defer sh.Cleanup(os.Stderr, os.Stderr)
+ h, err := sh.Start("child", "--logtostderr=true", "--vv=3", "--", "foobar")
if err != nil {
- t.Fatalf("failed to read from child: %v", err)
+ t.Fatalf("unexpected error: %s", err)
}
- expected := fmt.Sprintf("name=veyron "+
+ s := expect.NewSession(t, h.Stdout(), time.Minute)
+ s.Expect(fmt.Sprintf("name=veyron "+
"logdirs=[%s] "+
"logtostderr=true "+
"alsologtostderr=true "+
@@ -86,14 +89,11 @@
"stderrthreshold=2 "+
"vmodule= "+
"log_backtrace_at=:0",
- os.TempDir())
-
- if str != expected {
- t.Fatalf("incorrect child output: got %s, expected %s", str, expected)
- }
- c.CloseStdin()
- c.Expect("done")
- c.ExpectEOFAndWait()
+ os.TempDir()))
+ h.CloseStdin()
+ s.Expect("done")
+ s.ExpectEOF()
+ h.Shutdown(os.Stderr, os.Stderr)
}
func TestInitPrincipal(t *testing.T) {
diff --git a/runtimes/google/rt/signal_test.go b/runtimes/google/rt/signal_test.go
index c0f6235..5c400a9 100644
--- a/runtimes/google/rt/signal_test.go
+++ b/runtimes/google/rt/signal_test.go
@@ -1,56 +1,82 @@
package rt_test
import (
+ "bufio"
"fmt"
+ "io"
+ "os"
"syscall"
"testing"
+ "time"
"veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/rt"
- "veyron.io/veyron/veyron/lib/testutil/blackbox"
+ "veyron.io/veyron/veyron/lib/expect"
+ "veyron.io/veyron/veyron/lib/modules"
)
func init() {
- blackbox.CommandTable["withRuntime"] = withRuntime
- blackbox.CommandTable["withoutRuntime"] = withoutRuntime
+ modules.RegisterChild("withRuntime", "", withRuntime)
+ modules.RegisterChild("withoutRuntime", "", withoutRuntime)
}
-func simpleEchoProgram() {
- fmt.Println("ready")
- fmt.Println(blackbox.ReadLineFromStdin())
- blackbox.WaitForEOFOnStdin()
+func simpleEchoProgram(stdin io.Reader, stdout io.Writer) {
+ fmt.Fprintf(stdout, "ready\n")
+ scanner := bufio.NewScanner(stdin)
+ if scanner.Scan() {
+ fmt.Fprintf(stdout, "%s\n", scanner.Text())
+ }
+ modules.WaitForEOF(stdin)
}
-func withRuntime([]string) {
+func withRuntime(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
// Make sure that we use "google" runtime implementation in this
// package even though we have to use the public API which supports
// arbitrary runtime implementations.
rt.Init(veyron2.RuntimeOpt{veyron2.GoogleRuntimeName})
- simpleEchoProgram()
+ simpleEchoProgram(stdin, stdout)
+ return nil
}
-func withoutRuntime([]string) {
- simpleEchoProgram()
+func withoutRuntime(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+ simpleEchoProgram(stdin, stdout)
+ return nil
}
func TestWithRuntime(t *testing.T) {
- c := blackbox.HelperCommand(t, "withRuntime")
- defer c.Cleanup()
- c.Cmd.Start()
- c.Expect("ready")
- syscall.Kill(c.Cmd.Process.Pid, syscall.SIGHUP)
- c.WriteLine("foo")
- c.Expect("foo")
- c.CloseStdin()
- c.ExpectEOFAndWait()
+ sh := modules.NewShell("withRuntime")
+ defer sh.Cleanup(os.Stderr, os.Stderr)
+ h, err := sh.Start("withRuntime")
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ defer h.Shutdown(os.Stderr, os.Stderr)
+ s := expect.NewSession(t, h.Stdout(), time.Minute)
+ s.Expect("ready")
+ syscall.Kill(h.Pid(), syscall.SIGHUP)
+ h.Stdin().Write([]byte("foo\n"))
+ s.Expect("foo")
+ h.CloseStdin()
+ s.ExpectEOF()
}
func TestWithoutRuntime(t *testing.T) {
- c := blackbox.HelperCommand(t, "withoutRuntime")
- defer c.Cleanup()
- c.Cmd.Start()
- c.Expect("ready")
- syscall.Kill(c.Cmd.Process.Pid, syscall.SIGHUP)
- c.ExpectEOFAndWaitForExitCode(fmt.Errorf("exit status 2"))
+ sh := modules.NewShell("withoutRuntime")
+ defer sh.Cleanup(os.Stderr, os.Stderr)
+ h, err := sh.Start("withoutRuntime")
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ defer h.Shutdown(os.Stderr, os.Stderr)
+ s := expect.NewSession(t, h.Stdout(), time.Minute)
+ s.Expect("ready")
+ syscall.Kill(h.Pid(), syscall.SIGHUP)
+ s.ExpectEOF()
+ err = h.Shutdown(os.Stderr, os.Stderr)
+ want := "exit status 2"
+ if err == nil || err.Error() != want {
+ t.Errorf("got %s, want %s", err, want)
+
+ }
}