veyron/tools/mgmt: migrate test.sh to v23tests.
MultiPart: 1/2
Change-Id: I83a4fd34246ecb7512ea257e61ea423f9e99b5fb
diff --git a/lib/testutil/v23tests/v23tests.go b/lib/testutil/v23tests/v23tests.go
index 9c15d25..e93850f 100644
--- a/lib/testutil/v23tests/v23tests.go
+++ b/lib/testutil/v23tests/v23tests.go
@@ -239,8 +239,10 @@
return syscall.Kill(pid, sig)
}
-func location(depth int) string {
- _, file, line, _ := runtime.Caller(depth + 1)
+// Caller returns a string of the form <filename>:<lineno> for the
+// caller specified by skip, where skip is as per runtime.Caller.
+func Caller(skip int) string {
+ _, file, line, _ := runtime.Caller(skip + 1)
return fmt.Sprintf("%s:%d", filepath.Base(file), line)
}
@@ -250,7 +252,7 @@
buf := bytes.Buffer{}
_, err := buf.ReadFrom(i.Stdout())
if err != nil {
- i.env.Fatalf("%s: ReadFrom() failed: %v", location(1), err)
+ i.env.Fatalf("%s: ReadFrom() failed: %v", Caller(1), err)
}
return buf.String()
}
@@ -273,7 +275,7 @@
// cause the current test to fail.
func (i *Invocation) WaitOrDie(stdout, stderr io.Writer) {
if err := i.Wait(stdout, stderr); err != nil {
- i.env.Fatalf("%s: FATAL: Wait() for pid %d failed: %v", location(1), i.handle.Pid(), err)
+ i.env.Fatalf("%s: FATAL: Wait() for pid %d failed: %v", Caller(1), i.handle.Pid(), err)
}
}
@@ -298,10 +300,14 @@
// Start starts the given binary with the given arguments.
func (b *Binary) Start(args ...string) *Invocation {
- loc := location(testutil.DepthToExternalCaller())
+ loc := Caller(testutil.DepthToExternalCaller())
vlog.Infof("%s: starting %s %s", loc, b.Path(), strings.Join(args, " "))
handle, err := b.env.shell.StartExternalCommand(b.envVars, append([]string{b.Path()}, args...)...)
if err != nil {
+ // TODO(cnicolaou): calling Fatalf etc from a goroutine often leads
+ // to deadlock. Need to make sure that we handle this here. Maybe
+ // it's best to just return an error? Or provide a StartWithError
+ // call for use from goroutines.
b.env.Fatalf("%s: StartExternalCommand(%v, %v) failed: %v", loc, b.Path(), strings.Join(args, ", "), err)
}
vlog.Infof("started PID %d\n", handle.Pid())
@@ -381,10 +387,12 @@
vlog.VI(2).Infof("%d: %s %v", i, inv.path, inv.args)
continue
}
- m := fmt.Sprintf("%d: %s: shutdown status: %v", i, inv.path, inv.shutdownErr)
- e.Log(m)
- vlog.VI(1).Info(m)
- vlog.VI(2).Infof("%d: %s %v", i, inv.path, inv.args)
+ if inv.shutdownErr != nil {
+ m := fmt.Sprintf("%d: %s: shutdown status: %v", i, inv.path, inv.shutdownErr)
+ e.Log(m)
+ vlog.VI(1).Info(m)
+ vlog.VI(2).Infof("%d: %s %v", i, inv.path, inv.args)
+ }
}
}
@@ -458,10 +466,11 @@
}
}
-// DebugShell drops the user into a debug shell. If there is no
-// controlling TTY, DebugShell will emit a warning message and take no
-// futher action.
-func (e *T) DebugShell() {
+// DebugShell drops the user into a debug shell with any environment
+// variables specified in env... (in VAR=VAL format) available to it.
+// If there is no controlling TTY, DebugShell will emit a warning message
+// and take no futher action.
+func (e *T) DebugShell(env ...string) {
// Get the current working directory.
cwd, err := os.Getwd()
if err != nil {
@@ -487,6 +496,7 @@
Files: []*os.File{file, file, file},
Dir: cwd,
}
+ // Set up agent for Child.
attr.Files = append(attr.Files, agentFile)
attr.Env = append(attr.Env, fmt.Sprintf("%s=%d", agent.FdVarName, len(attr.Files)-1))
@@ -495,6 +505,15 @@
attr.Env = append(attr.Env, v)
}
+ for i, td := range e.tempDirs {
+ attr.Env = append(attr.Env, fmt.Sprintf("V23_TMP_DIR%d=%s", i, td))
+ }
+
+ if len(e.cachedBinDir) > 0 {
+ attr.Env = append(attr.Env, "V23_BIN_DIR="+e.cachedBinDir)
+ }
+ attr.Env = append(attr.Env, env...)
+
// Start up a new shell.
writeStringOrDie(e, file, ">> Starting a new interactive shell\n")
writeStringOrDie(e, file, "Hit CTRL-D to resume the test\n")
@@ -505,9 +524,9 @@
}
}
if len(e.cachedBinDir) > 0 {
- writeStringOrDie(e, file, fmt.Sprintf("Binaries are cached in %q", e.cachedBinDir))
+ writeStringOrDie(e, file, fmt.Sprintf("Binaries are cached in %q\n", e.cachedBinDir))
} else {
- writeStringOrDie(e, file, "Caching of binaries was not enabled")
+ writeStringOrDie(e, file, "Caching of binaries was not enabled\n")
}
shellPath := "/bin/sh"
@@ -546,7 +565,7 @@
// binary.
func (e *T) BuildGoPkg(binary_path string) *Binary {
then := time.Now()
- loc := location(1)
+ loc := Caller(1)
cached, built_path, cleanup, err := buildPkg(e.cachedBinDir, binary_path)
if err != nil {
e.Fatalf("%s: buildPkg(%s) failed: %v", loc, binary_path, err)
@@ -574,10 +593,10 @@
return binary
}
-// TempFile creates a temporary file. Temporary files will be deleted
+// NewTempFile creates a temporary file. Temporary files will be deleted
// by Cleanup.
-func (e *T) TempFile() *os.File {
- loc := location(1)
+func (e *T) NewTempFile() *os.File {
+ loc := Caller(1)
f, err := ioutil.TempFile("", "")
if err != nil {
e.Fatalf("%s: TempFile() failed: %v", loc, err)
@@ -587,10 +606,10 @@
return f
}
-// TempDir creates a temporary directory. Temporary directories and
+// NewTempDir creates a temporary directory. Temporary directories and
// their contents will be deleted by Cleanup.
-func (e *T) TempDir() string {
- loc := location(1)
+func (e *T) NewTempDir() string {
+ loc := Caller(1)
f, err := ioutil.TempDir("", "")
if err != nil {
e.Fatalf("%s: TempDir() failed: %v", loc, err)
@@ -708,7 +727,7 @@
return b, inv
}
-// UseShardBinDir ensures that a shared directory is used for binaries
+// UseSharedBinDir ensures that a shared directory is used for binaries
// across multiple instances of the test environment. This is achieved
// by setting the V23_BIN_DIR environment variable if it is not already
// set in the test processes environment (as will typically be the case when
diff --git a/lib/testutil/v23tests/v23tests_test.go b/lib/testutil/v23tests/v23tests_test.go
index 9546c05..1ab0f52 100644
--- a/lib/testutil/v23tests/v23tests_test.go
+++ b/lib/testutil/v23tests/v23tests_test.go
@@ -153,7 +153,7 @@
// Read something from a file.
{
want := "Hello from a file!"
- f := env.TempFile()
+ f := env.NewTempFile()
f.WriteString(want)
f.Seek(0, 0)
if got := cat.WithStdin(f).Start().Output(); want != got {
@@ -165,7 +165,7 @@
{
want := testutil.RandomBytes(1 << 20)
expectedSum := sha1.Sum(want)
- f := env.TempFile()
+ f := env.NewTempFile()
f.Write(want)
f.Seek(0, 0)
got := cat.WithStdin(f).Start().Output()
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index f7c252b..85a6f35 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -611,8 +611,10 @@
if err := fs.serve(); err != nil {
// TODO(caprita): Logging errors here is too spammy. For example, "not
// authorized" errors shouldn't be logged as server errors.
+ // TODO(cnicolaou): revisit this when verror2 transition is
+ // done.
if err != io.EOF {
- vlog.Errorf("Flow serve on %v failed: %v", ep, err)
+ vlog.VI(2).Infof("Flow serve on %v failed: %v", ep, err)
}
}
}(flow)
diff --git a/security/agent/agent_v23_test.go b/security/agent/agent_v23_test.go
index f074006..0125236 100644
--- a/security/agent/agent_v23_test.go
+++ b/security/agent/agent_v23_test.go
@@ -18,7 +18,7 @@
// Test passphrase handling.
bin := i.BuildGoPkg("v.io/core/veyron/security/agent/agentd")
- credentials := "VEYRON_CREDENTIALS=" + i.TempDir()
+ credentials := "VEYRON_CREDENTIALS=" + i.NewTempDir()
// Create the passphrase
agent := bin.WithEnv(credentials).Start("echo", "Hello")
@@ -54,7 +54,7 @@
agentBin := i.BuildGoPkg("v.io/core/veyron/security/agent/agentd")
principalBin := i.BuildGoPkg("v.io/core/veyron/security/agent/test_principal")
- credentials := "VEYRON_CREDENTIALS=" + i.TempDir()
+ credentials := "VEYRON_CREDENTIALS=" + i.NewTempDir()
agent := agentBin.WithEnv(credentials).Start(principalBin.Path())
agent.WaitOrDie(nil, os.Stderr)
}
@@ -79,7 +79,7 @@
agentBin := i.BuildGoPkg("v.io/core/veyron/security/agent/agentd")
testChildBin := i.BuildGoPkg("v.io/core/veyron/security/agent/test_child")
- credentials := "VEYRON_CREDENTIALS=" + i.TempDir()
+ credentials := "VEYRON_CREDENTIALS=" + i.NewTempDir()
// Test running a single app.
pingpongBin := buildAndRunPingpongServer(i, rootMTArg)
@@ -129,11 +129,11 @@
vrun := i.BuildGoPkg("v.io/core/veyron/tools/vrun")
pingpongBin := buildAndRunPingpongServer(i, rootMTArg)
- credentials := "VEYRON_CREDENTIALS=" + i.TempDir()
+ credentials := "VEYRON_CREDENTIALS=" + i.NewTempDir()
// This script increments a counter in $COUNTER_FILE and exits with exit code 0
// while the counter is < 5, and 1 otherwise.
- counterFile := i.TempFile()
+ counterFile := i.NewTempFile()
script := fmt.Sprintf("%q %q|| exit 101\n", pingpongBin.Path(), rootMTArg)
script += fmt.Sprintf("%q %q %q|| exit 102\n", vrun.Path(), pingpongBin.Path(), rootMTArg)
@@ -147,7 +147,7 @@
i.Logf(exit)
counterFile.Seek(0, 0)
fmt.Fprintln(counterFile, "0")
- agent := agentBin.WithEnv(credentials).Start("--additional_principals", i.TempDir(), exit, "bash", "-c", script)
+ agent := agentBin.WithEnv(credentials).Start("--additional_principals", i.NewTempDir(), exit, "bash", "-c", script)
if err := agent.Wait(nil, nil); err == nil {
if len(status) > 0 {
i.Fatalf("%s: expected an error %q that didn't occur", loc, status)
diff --git a/services/mgmt/application/applicationd/applicationd_v23_test.go b/services/mgmt/application/applicationd/applicationd_v23_test.go
index a3c0c16..7fa3406 100644
--- a/services/mgmt/application/applicationd/applicationd_v23_test.go
+++ b/services/mgmt/application/applicationd/applicationd_v23_test.go
@@ -53,7 +53,7 @@
// Start the application repository.
appRepoName := "test-app-repo"
- appRepoStore := i.TempDir()
+ appRepoStore := i.NewTempDir()
args := []string{
"-name=" + appRepoName,
"-store=" + appRepoStore,
@@ -90,7 +90,7 @@
// Create an application envelope.
appRepoSuffix := "test-application/v1"
- appEnvelopeFile := i.TempFile()
+ appEnvelopeFile := i.NewTempFile()
wantEnvelope := `{
"Title": "title",
"Args": null,
diff --git a/services/mgmt/binary/binaryd/binaryd_v23_test.go b/services/mgmt/binary/binaryd/binaryd_v23_test.go
index 9646991..2ecdbf4 100644
--- a/services/mgmt/binary/binaryd/binaryd_v23_test.go
+++ b/services/mgmt/binary/binaryd/binaryd_v23_test.go
@@ -123,7 +123,7 @@
binaryRepoBin.Start(args...)
// Upload a random binary file.
- binFile := i.TempFile()
+ binFile := i.NewTempFile()
if _, err := binFile.Write(testutil.RandomBytes(16 * 1000 * 1000)); err != nil {
i.Fatalf("Write() failed: %v", err)
}
diff --git a/services/mgmt/build/buildd/buildd_v23_test.go b/services/mgmt/build/buildd/buildd_v23_test.go
index 99b28d0..54de166 100644
--- a/services/mgmt/build/buildd/buildd_v23_test.go
+++ b/services/mgmt/build/buildd/buildd_v23_test.go
@@ -47,7 +47,7 @@
buildServerBin.Start(args...)
// Create and build a test source file.
- testGoPath := i.TempDir()
+ testGoPath := i.NewTempDir()
testBinDir := filepath.Join(testGoPath, "bin")
if err := os.MkdirAll(testBinDir, os.FileMode(0700)); err != nil {
i.Fatalf("MkdirAll(%v) failed: %v", testBinDir, err)
diff --git a/services/mgmt/profile/profiled/profiled_v23_test.go b/services/mgmt/profile/profiled/profiled_v23_test.go
index 4180ebe..f0d62c4 100644
--- a/services/mgmt/profile/profiled/profiled_v23_test.go
+++ b/services/mgmt/profile/profiled/profiled_v23_test.go
@@ -45,7 +45,7 @@
// Start the profile repository.
profileRepoName := "test-profile-repo"
- profileRepoStore := i.TempDir()
+ profileRepoStore := i.NewTempDir()
args := []string{
"-name=" + profileRepoName, "-store=" + profileRepoStore,
"-veyron.tcp.address=127.0.0.1:0",
diff --git a/tools/debug/debug_v23_test.go b/tools/debug/debug_v23_test.go
index 4cb0ccd..dee8b6a 100644
--- a/tools/debug/debug_v23_test.go
+++ b/tools/debug/debug_v23_test.go
@@ -34,7 +34,7 @@
v23tests.RunRootMT(i, "--veyron.tcp.address=127.0.0.1:0")
// Create a temp file before we list the logs.
- fileName := filepath.Base(i.TempFile().Name())
+ fileName := filepath.Base(i.NewTempFile().Name())
binary := i.BuildGoPkg("v.io/core/veyron/tools/debug")
output := binary.Start("glob", "__debug/logs/*").Output()
@@ -61,7 +61,7 @@
}
func createTestLogFile(i *v23tests.T, content string) *os.File {
- file := i.TempFile()
+ file := i.NewTempFile()
_, err := file.Write([]byte(content))
if err != nil {
i.Fatalf("Write failed: %v", err)
diff --git a/tools/mgmt/dummy.go b/tools/mgmt/dummy.go
new file mode 100644
index 0000000..2d4fedb
--- /dev/null
+++ b/tools/mgmt/dummy.go
@@ -0,0 +1 @@
+package mgmt
diff --git a/tools/mgmt/mgmt_v23_test.go b/tools/mgmt/mgmt_v23_test.go
new file mode 100644
index 0000000..1fa0fef
--- /dev/null
+++ b/tools/mgmt/mgmt_v23_test.go
@@ -0,0 +1,462 @@
+// Test the device manager and related services and tools.
+//
+// By default, this script tests the device manager in a fashion amenable
+// to automatic testing: the --single_user is passed to the device
+// manager so that all device manager components run as the same user and
+// no user input (such as an agent pass phrase) is needed.
+//
+// When this script is invoked with the --with_suid <user> flag, it
+// installs the device manager in its more secure multi-account
+// configuration where the device manager runs under the account of the
+// invoker and test apps will be executed as <user>. This mode will
+// require root permisisons to install and may require configuring an
+// agent passphrase.
+//
+// For exanple:
+//
+// v23 go test -v . --v23.tests --with_suid vanaguest
+//
+// to test a device manager with multi-account support enabled for app
+// account vanaguest.
+//
+package mgmt_test
+
+//go:generate v23 test generate .
+
+import (
+ "bytes"
+ "errors"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "math/rand"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "v.io/core/veyron2/vlog"
+
+ "v.io/core/veyron/lib/testutil/v23tests"
+ _ "v.io/core/veyron/profiles"
+)
+
+var (
+ suidUserFlag string
+ hostname string
+ errTimeout = errors.New("timeout")
+)
+
+func init() {
+ flag.StringVar(&suidUserFlag, "with_suid", "", "run the device manager as the specified user")
+ name, err := os.Hostname()
+ if err != nil {
+ panic(fmt.Sprintf("Hostname() failed: %v", err))
+ }
+ hostname = name
+}
+
+// waitFor waits for the specified timeout for the supplied function parameter
+// function to return a result or an error. If error is nil, the function
+// will be called again to see if a result can be obtained until the timeout
+// expires.
+func waitFor(fn func() (string, error), timeout time.Duration) (string, error) {
+ errCh := make(chan error)
+ resultCh := make(chan string)
+ cancelCh := make(chan struct{})
+
+ eval := func() {
+ for {
+ result, err := fn()
+ switch {
+ case err != nil:
+ errCh <- err
+ close(errCh)
+ close(resultCh)
+ return
+ case len(result) > 0:
+ resultCh <- result
+ close(resultCh)
+ close(errCh)
+ return
+ }
+ time.Sleep(100 * time.Millisecond)
+ select {
+ case <-cancelCh:
+ return
+ default:
+ }
+ }
+ }
+
+ go eval()
+
+ select {
+ case <-time.After(timeout):
+ close(cancelCh)
+ return "", errTimeout
+ case result := <-resultCh:
+ return strings.TrimRight(result, "\n"), nil
+ case err := <-errCh:
+ return "", err
+ }
+}
+
+func waitForOrDie(i *v23tests.T, fn func() (string, error), timeout time.Duration) string {
+ result, err := waitFor(fn, timeout)
+ if err != nil {
+ i.Fatal(fmt.Sprintf("%s: %s", v23tests.Caller(1), err))
+ }
+ return result
+}
+
+func V23TestNodeManager(i *v23tests.T) {
+ defer fmt.Fprintf(os.Stderr, "--------------- SHUTDOWN ---------------\n")
+ userFlag := "--single_user"
+ withSuid := false
+ if len(suidUserFlag) > 0 {
+ userFlag = "--with_suid=" + suidUserFlag
+ withSuid = true
+ }
+ i.Logf("user flag: %q", userFlag)
+
+ v23tests.RunRootMT(i, "--veyron.tcp.address=127.0.0.1:0")
+ workDir := i.NewTempDir()
+
+ mkSubdir := func(sub string) string {
+ n := filepath.Join(workDir, sub)
+ if err := os.Mkdir(n, 0755); err != nil {
+ i.Fatalf("failed to create %q: %v", n, err)
+ }
+ return n
+ }
+
+ binStagingDir := mkSubdir("bin")
+ agentServerBin := i.BuildGoPkg("v.io/core/veyron/security/agent/agentd")
+ suidHelperBin := i.BuildGoPkg("v.io/core/veyron/services/mgmt/suidhelper")
+ initHelperBin := i.BuildGoPkg("v.io/core/veyron/services/mgmt/inithelper")
+
+ // Device manager and principal use their own set of credentials.
+ // The credentials directory will be populated with Start an application
+ // server under the blessing "alice/myworkstation/applicationd" so that
+ // the device ("alice/myworkstation") can talk to it. ALl of the binaries
+ // that communicate with each other must share this credentials directory.
+ credentials := "VEYRON_CREDENTIALS=" + i.NewTempDir()
+ namespaceBin := i.BuildGoPkg("v.io/core/veyron/tools/namespace").WithEnv(credentials)
+ debugBin := i.BuildGoPkg("v.io/core/veyron/tools/debug").WithEnv(credentials)
+ deviceBin := i.BuildGoPkg("v.io/core/veyron/tools/mgmt/device").WithEnv(credentials)
+ devicedBin := i.BuildGoPkg("v.io/core/veyron/services/mgmt/device/deviced").WithEnv(credentials)
+ deviceScript := i.BinaryFromPath("device/devicex").WithEnv(credentials)
+ principalBin := i.BuildGoPkg("v.io/core/veyron/tools/principal").WithEnv(credentials)
+ binarydBin := i.BuildGoPkg("v.io/core/veyron/services/mgmt/binary/binaryd").WithEnv(credentials)
+ binaryBin := i.BuildGoPkg("v.io/core/veyron/tools/binary").WithEnv(credentials)
+ applicationdBin := i.BuildGoPkg("v.io/core/veyron/services/mgmt/application/applicationd").WithEnv(credentials)
+ applicationBin := i.BuildGoPkg("v.io/core/veyron/tools/application").WithEnv(credentials)
+
+ appDName := "applicationd"
+ devicedAppName := filepath.Join(appDName, "deviced", "test")
+
+ i.BinaryFromPath("/bin/cp").Start(agentServerBin.Path(), suidHelperBin.Path(), initHelperBin.Path(), devicedBin.Path(), binStagingDir).WaitOrDie(os.Stdout, os.Stderr)
+
+ dmInstallDir := filepath.Join(workDir, "dm")
+ i.SetVar("VANADIUM_DEVICE_DIR", dmInstallDir)
+
+ neighborhoodName := fmt.Sprintf("%s-%d-%d", hostname, os.Getpid(), rand.Int())
+
+ deviceScript.Start(
+ "install",
+ binStagingDir,
+ userFlag,
+ "--origin="+devicedAppName,
+ "--",
+ "--veyron.tcp.address=127.0.0.1:0",
+ "--neighborhood_name="+neighborhoodName).
+ WaitOrDie(os.Stdout, os.Stderr)
+
+ deviceScript.Start("start").WaitOrDie(os.Stdout, os.Stderr)
+
+ mtName := "devices/" + hostname
+
+ resolve := func(name string) (string, error) {
+ inv := namespaceBin.Start("resolve", name)
+ // Avoid leaving a ton of invocations lying around to obscure
+ // logging output. Ignore the error code from Wait since it'll
+ // deadlock if we call Fatalf etc from a goroutine.
+ defer inv.Wait(nil, os.Stderr)
+ return strings.TrimRight(inv.Output(), "\n"), nil
+ }
+ resolveMtName := func() (string, error) {
+ return resolve(mtName)
+ }
+
+ mtEP := waitForOrDie(i, resolveMtName, time.Minute)
+
+ run := func(bin *v23tests.Binary, args ...string) string {
+ var stdout, stderr bytes.Buffer
+ inv := bin.Start(args...)
+ if err := inv.Wait(&stdout, &stderr); err != nil {
+ loc := v23tests.Caller(1)
+ i.Logf("%s: %v failed: %s", loc, filepath.Base(bin.Path()), err)
+ i.Fatalf("%s: %v", loc, stderr.String())
+ }
+ return strings.TrimRight(stdout.String(), "\n")
+ }
+
+ // Verify that device manager's mounttable is published under the expected
+ // name (hostname).
+ if got := run(namespaceBin, "glob", mtName); len(got) == 0 {
+ i.Fatalf("glob failed for %q", mtName)
+ }
+
+ // Create a self-signed blessing with name "alice" and set it as default
+ // and shareable with all peers on the principal that the device manager
+ // and principal are sharing (via the .WithEnv method) above. This
+ // blessing will be used by all commands run by the device manager that
+ // specify the same credentials.
+ // TODO - update these commands
+ // that except those
+ // run with a different which gets a principal forked from the
+ // process principal.
+ blessingFilename := filepath.Join(workDir, "alice.bless")
+ blessing := run(principalBin, "blessself", "alice")
+ if err := ioutil.WriteFile(blessingFilename, []byte(blessing), 0755); err != nil {
+ i.Fatal(err)
+ }
+ run(principalBin, "store", "setdefault", blessingFilename)
+ run(principalBin, "store", "set", blessingFilename, "...")
+ defer os.Remove(blessingFilename)
+
+ // Claim the device as "alice/myworkstation".
+ deviceBin.Start("claim", mtName+"/devmgr/device", "myworkstation")
+
+ resolveChanged := func(name, prev string) (string, error) {
+ ep, err := resolve(name)
+ if err == nil && ep != prev {
+ return ep, nil
+ }
+ return "", nil
+ }
+
+ waitForChange := func(name, prevEP string) string {
+ newEP := waitForOrDie(i, func() (string, error) { return resolveChanged(name, prevEP) }, time.Minute)
+ loc := v23tests.Caller(1)
+ if newEP == prevEP {
+ i.Fatalf("%s: failed to obtain new endpoint for %s: same as before %v", loc, name, newEP)
+ }
+ vlog.Infof("%s: new endpoint: %s -> %s", loc, name, newEP)
+ return newEP
+ }
+
+ // Wait for the device manager to update its mount table entry.
+ mtEP = waitForChange(mtName, mtEP)
+
+ if withSuid {
+ /*
+ "${DEVICE_BIN}" associate add "${MT_NAME}/devmgr/device" "${SUID_USER}" "alice"
+ shell_test::assert_eq "$("${DEVICE_BIN}" associate list "${MT_NAME}/devmgr/device")" \
+ "alice ${SUID_USER}" "${LINENO}"
+ */
+ }
+
+ // Verify the device's default blessing is as expected.
+ inv := debugBin.Start("stats", "read", mtName+"/devmgr/__debug/stats/security/principal/*/blessingstore")
+ inv.ExpectRE(".*Default blessings: alice/myworkstation$", -1)
+
+ // Get the device's profile, which should be set to non-empty string
+ inv = deviceBin.Start("describe", mtName+"/devmgr/device")
+
+ parts := inv.ExpectRE(`{Profiles:map\[(.*):{}\]}`, 1)
+ expectOneMatch := func(parts [][]string) string {
+ if len(parts) != 1 || len(parts[0]) != 2 {
+ loc := v23tests.Caller(1)
+ i.Fatalf("%s: failed to match profile: %#v", loc, parts)
+ }
+ return parts[0][1]
+ }
+ deviceProfile := expectOneMatch(parts)
+ if len(deviceProfile) == 0 {
+ i.Fatalf("failed to get profile")
+ }
+
+ binarydName := "binaryd"
+ // Start an application server under the blessing
+ // "alice/myworkstation/applicationd" so that
+ // the device ("alice/myworkstation") can talk to it.
+ binarydBin.Start(
+ "--name="+binarydName,
+ "--root_dir="+filepath.Join(workDir, "binstore"),
+ "--veyron.tcp.address=127.0.0.1:0",
+ "--http=127.0.0.1:0")
+
+ sampleAppBinName := binarydName + "/testapp"
+ run(binaryBin, "upload", sampleAppBinName, binarydBin.Path())
+
+ // Verify that the binary we uploaded is shown by glob, we need to run
+ // with the same blessed credentials as binaryd in order to be able to
+ // glob its names pace.
+ if got := run(namespaceBin.WithEnv(credentials), "glob", sampleAppBinName); len(got) == 0 {
+ i.Fatalf("glob failed for %q", sampleAppBinName)
+ }
+
+ appstoreDir := mkSubdir("apptstore")
+
+ applicationdBin.Start(
+ "--name="+appDName,
+ "--store="+appstoreDir,
+ "--veyron.tcp.address=127.0.0.1:0",
+ )
+
+ sampleAppName := appDName + "/testapp/v0"
+ appPubName := "testbinaryd"
+ appEnvelopeFilename := filepath.Join(workDir, "app.envelope")
+ appEnvelope := fmt.Sprintf("{\"Title\":\"BINARYD\", \"Args\":[\"--name=%s\", \"--root_dir=./binstore\", \"--veyron.tcp.address=127.0.0.1:0\", \"--http=127.0.0.1:0\"], \"Binary\":{\"File\":%q}, \"Env\":[]}", appPubName, sampleAppBinName)
+ ioutil.WriteFile(appEnvelopeFilename, []byte(appEnvelope), 0666)
+ defer os.Remove(appEnvelopeFilename)
+
+ output := run(applicationBin, "put", sampleAppName, deviceProfile, appEnvelopeFilename)
+ if got, want := output, "Application envelope added successfully."; got != want {
+ i.Fatalf("got %q, want %q", got, want)
+ }
+
+ // Verify that the envelope we uploaded shows up with glob.
+ inv = applicationBin.Start("match", sampleAppName, deviceProfile)
+ parts = inv.ExpectSetEventuallyRE(`"Title": "(.*)",`, `"File": "(.*)",`)
+ if got, want := len(parts), 2; got != want {
+ i.Fatalf("got %d, want %d", got, want)
+ }
+ for line, want := range []string{"BINARYD", sampleAppBinName} {
+ if got := parts[line][1]; got != want {
+ i.Fatalf("got %q, want %q", got, want)
+ }
+ }
+
+ // Install the app on the device.
+ inv = deviceBin.Start("install", mtName+"/devmgr/apps", sampleAppName)
+ parts = inv.ExpectRE(`Successfully installed: "(.*)"`, 1)
+ installationName := expectOneMatch(parts)
+
+ // Verify that the installation shows up when globbing the device manager.
+ output = run(namespaceBin, "glob", mtName+"/devmgr/apps/BINARYD/*")
+ if got, want := output, installationName; got != want {
+ i.Fatalf("got %q, want %q", got, want)
+ }
+
+ // Start an instance of the app, granting it blessing extension myapp.
+ inv = deviceBin.Start("start", installationName, "myapp")
+ parts = inv.ExpectRE(`Successfully started: "(.*)"`, 1)
+ instanceName := expectOneMatch(parts)
+
+ resolveInstanceName := func() (string, error) {
+ return resolve(mtName + "/" + appPubName)
+ }
+ waitForOrDie(i, resolveInstanceName, time.Minute)
+
+ // Verify that the instance shows up when globbing the device manager.
+ output = run(namespaceBin, "glob", mtName+"/devmgr/apps/BINARYD/*/*")
+ if got, want := output, instanceName; got != want {
+ i.Fatalf("got %q, want %q", got, want)
+ }
+
+ // TODO(rjkroege): Verify that the app is actually running as ${SUID_USER}
+
+ // Verify the app's default blessing.
+ inv = debugBin.Start("stats", "read", instanceName+"/stats/security/principal/*/blessingstore")
+ // Why is this alice/myworkstation/myapp/BINARYD and not
+ // alice/myapp/BINARYD as seen by the test.sh?
+ inv.ExpectRE(".*Default blessings: alice/myworkstation/myapp/BINARYD$", -1)
+
+ // Stop the instance
+ run(deviceBin, "stop", instanceName)
+
+ // Verify that logs, but not stats, show up when globbing the
+ // stopped instance.
+ output = run(namespaceBin, "glob", instanceName+"/stats/...")
+ if len(output) > 0 {
+ i.Fatalf("no output expected for glob %s/stats/..., got %q", output, instanceName)
+ }
+ output = run(namespaceBin, "glob", instanceName+"/logs/...")
+ if len(output) == 0 {
+ i.Fatalf("output expected for glob %s/logs/..., but got none", instanceName)
+ }
+
+ // Upload a deviced binary
+ devicedAppBinName := binarydName + "/deviced"
+ run(binaryBin, "upload", devicedAppBinName, devicedBin.Path())
+
+ // Upload a device manager envelope, make sure that we set
+ // VEYRON_CREDENTIALS in the enevelope, otherwise the updated device
+ // manager will use new credentials.
+ devicedEnvelopeFilename := filepath.Join(workDir, "deviced.envelope")
+ devicedEnvelope := fmt.Sprintf("{\"Title\":\"device manager\", \"Binary\":{\"File\":%q}, \"Env\":[%q]}", devicedAppBinName, credentials)
+ ioutil.WriteFile(devicedEnvelopeFilename, []byte(devicedEnvelope), 0666)
+ defer os.Remove(devicedEnvelopeFilename)
+ run(applicationBin, "put", devicedAppName, deviceProfile, devicedEnvelopeFilename)
+
+ // Update the device manager.
+ run(deviceBin, "update", mtName+"/devmgr/device")
+ mtEP = waitForChange(mtName, mtEP)
+
+ // Verify that device manager's mounttable is still published under the
+ // expected name (hostname).
+ if run(namespaceBin, "glob", mtName) == "" {
+ i.Fatalf("failed to glob %s", mtName)
+ }
+
+ // Revert the device manager
+ run(deviceBin, "revert", mtName+"/devmgr/device")
+ mtEP = waitForChange(mtName, mtEP)
+
+ // Verify that device manager's mounttable is still published under the
+ // expected name (hostname).
+ if run(namespaceBin, "glob", mtName) == "" {
+ i.Fatalf("failed to glob %s", mtName)
+ }
+
+ // Verify that the local mounttable exists, and that the device manager,
+ // the global namespace, and the neighborhood are mounted on it.
+ n := mtEP + "/devmgr"
+ if run(namespaceBin, "resolve", n) == "" {
+ i.Fatalf("failed to resolve %s", n)
+ }
+ n = mtEP + "/nh"
+ if run(namespaceBin, "resolve", n) == "" {
+ i.Fatalf("failed to resolve %s", n)
+ }
+ namespaceRoot, _ := i.GetVar("NAMESPACE_ROOT")
+ n = mtEP + "/global"
+ if got, want := run(namespaceBin, "resolve", n), namespaceRoot; got != want {
+ i.Fatalf("got %q, want %q", got, want)
+ }
+
+ // Suspend the device manager.
+ run(deviceBin, "suspend", mtName+"/devmgr/device")
+ mtEP = waitForChange(mtName, mtEP)
+
+ // Stop the device manager.
+ run(deviceScript, "stop")
+
+ // Wait for the mounttable entry to go away.
+ noEntry := func() (string, error) {
+ ep, err := resolve(mtName)
+ if err == nil && len(ep) == 0 {
+ return "done", nil
+ }
+ return "", nil
+ }
+ waitForOrDie(i, noEntry, time.Minute)
+
+ fi, err := ioutil.ReadDir(dmInstallDir)
+ if err != nil {
+ i.Fatalf("failed to readdir for %q: %v", dmInstallDir, err)
+ }
+
+ run(deviceScript, "uninstall")
+
+ fi, err = ioutil.ReadDir(dmInstallDir)
+ if err == nil || len(fi) > 0 {
+ i.Fatalf("managed to read %d entries from %q", len(fi), dmInstallDir)
+ }
+ if err != nil && !strings.Contains(err.Error(), "no such file or directory") {
+ i.Fatalf("wrong error: %v", err)
+ }
+}
diff --git a/tools/mgmt/v23_test.go b/tools/mgmt/v23_test.go
new file mode 100644
index 0000000..b72930b
--- /dev/null
+++ b/tools/mgmt/v23_test.go
@@ -0,0 +1,21 @@
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+package mgmt_test
+
+import "testing"
+import "os"
+
+import "v.io/core/veyron/lib/testutil"
+import "v.io/core/veyron/lib/testutil/v23tests"
+
+func TestMain(m *testing.M) {
+ testutil.Init()
+ cleanup := v23tests.UseSharedBinDir()
+ r := m.Run()
+ cleanup()
+ os.Exit(r)
+}
+
+func TestV23NodeManager(t *testing.T) {
+ v23tests.RunTest(t, V23TestNodeManager)
+}
diff --git a/tools/principal/principal_v23_test.go b/tools/principal/principal_v23_test.go
index 0ea874e..d4b03ab 100644
--- a/tools/principal/principal_v23_test.go
+++ b/tools/principal/principal_v23_test.go
@@ -41,7 +41,7 @@
func V23TestBlessSelf(t *v23tests.T) {
var (
- outputDir = t.TempDir()
+ outputDir = t.NewTempDir()
aliceDir = filepath.Join(outputDir, "alice")
aliceBlessingFile = filepath.Join(outputDir, "aliceself")
)
@@ -65,7 +65,7 @@
func V23TestStore(t *v23tests.T) {
var (
- outputDir = t.TempDir()
+ outputDir = t.NewTempDir()
bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
aliceDir = filepath.Join(outputDir, "alice")
aliceFriend = filepath.Join(outputDir, "alice.bless")
@@ -103,7 +103,7 @@
func V23TestDump(t *v23tests.T) {
var (
- outputDir = t.TempDir()
+ outputDir = t.NewTempDir()
bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
aliceDir = filepath.Join(outputDir, "alice")
)
@@ -128,7 +128,7 @@
func V23TestRecvBlessings(t *v23tests.T) {
var (
- outputDir = t.TempDir()
+ outputDir = t.NewTempDir()
bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
aliceDir = filepath.Join(outputDir, "alice")
carolDir = filepath.Join(outputDir, "carol")
@@ -214,7 +214,7 @@
func V23TestFork(t *v23tests.T) {
var (
- outputDir = t.TempDir()
+ outputDir = t.NewTempDir()
bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
aliceDir = filepath.Join(outputDir, "alice")
alicePhoneDir = filepath.Join(outputDir, "alice-phone")
@@ -267,7 +267,7 @@
func V23TestCreate(t *v23tests.T) {
var (
- outputDir = t.TempDir()
+ outputDir = t.NewTempDir()
bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
aliceDir = filepath.Join(outputDir, "alice")
)
@@ -286,7 +286,7 @@
func V23TestCaveats(t *v23tests.T) {
var (
- outputDir = t.TempDir()
+ outputDir = t.NewTempDir()
aliceDir = filepath.Join(outputDir, "alice")
aliceBlessingFile = filepath.Join(outputDir, "aliceself")
)
@@ -318,13 +318,13 @@
func V23TestForkWithoutVDLPATH(t *v23tests.T) {
var (
- parent = t.TempDir()
+ parent = t.NewTempDir()
bin = t.BuildGoPkg("v.io/core/veyron/tools/principal").WithEnv("VANADIUM_ROOT=''", "VDLPATH=''")
)
if err := bin.Start("create", parent, "parent").Wait(os.Stdout, os.Stderr); err != nil {
t.Fatalf("create %q failed: %v", parent, err)
}
- if err := bin.Start("--veyron.credentials="+parent, "fork", t.TempDir(), "child").Wait(os.Stdout, os.Stderr); err != nil {
+ if err := bin.Start("--veyron.credentials="+parent, "fork", t.NewTempDir(), "child").Wait(os.Stdout, os.Stderr); err != nil {
t.Errorf("fork failed: %v", err)
}
}
diff --git a/tools/vrun/internal/vrun_v23_test.go b/tools/vrun/internal/vrun_v23_test.go
index 083bc20..fbb13cf 100644
--- a/tools/vrun/internal/vrun_v23_test.go
+++ b/tools/vrun/internal/vrun_v23_test.go
@@ -18,7 +18,7 @@
v23tests.RunRootMT(t, "--veyron.tcp.address=127.0.0.1:0")
- creds := t.TempDir()
+ creds := t.NewTempDir()
agentdBin.WithEnv("VEYRON_CREDENTIALS="+creds).Start("--no_passphrase",
"--additional_principals="+creds,
helperBin.Path(),