blob: c3d3c010b151565ad31cc081ec994571c202c65c [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package servicetest
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/options"
"v.io/x/lib/gosh"
"v.io/x/ref"
"v.io/x/ref/internal/logger"
"v.io/x/ref/lib/signals"
"v.io/x/ref/services/internal/dirprinter"
"v.io/x/ref/services/mounttable/mounttablelib"
"v.io/x/ref/test"
"v.io/x/ref/test/testutil"
"v.io/x/ref/test/v23test"
)
const (
// Setting this environment variable to any non-empty value avoids
// removing the generated workspace for successful test runs (for
// failed test runs, this is already the case). This is useful when
// developing test cases.
preserveWorkspaceEnv = "V23_TEST_PRESERVE_WORKSPACE"
)
var rootMT = gosh.RegisterFunc("rootMT", func() error {
ctx, shutdown := test.V23Init()
defer shutdown()
mt, err := mounttablelib.NewMountTableDispatcher(ctx, "", "", "mounttable")
if err != nil {
return fmt.Errorf("mounttablelib.NewMountTableDispatcher failed: %s", err)
}
ctx, server, err := v23.WithNewDispatchingServer(ctx, "", mt, options.ServesMountTable(true))
if err != nil {
return fmt.Errorf("rootMT failed: %v", err)
}
gosh.SendVars(map[string]string{"NAME": server.Status().Endpoints[0].Name()})
<-signals.ShutdownOnSignals(ctx)
return nil
})
// startRootMT sets up a root mount table for tests.
func startRootMT(t *testing.T, sh *v23test.Shell) string {
c := sh.FuncCmd(rootMT)
c.Args = append(c.Args, "--v23.tcp.address=127.0.0.1:0")
c.PropagateOutput = false
c.Start()
return c.AwaitVars("NAME")["NAME"]
}
// setNSRoots sets the roots for the local runtime's namespace.
func setNSRoots(t *testing.T, ctx *context.T, roots ...string) {
ns := v23.GetNamespace(ctx)
if err := ns.SetRoots(roots...); err != nil {
t.Fatal(testutil.FormatLogLine(3, "SetRoots(%v) failed: %v", roots, err))
}
}
// CreateShellAndMountTable builds a new shell and starts a root mount table.
// Returns the shell and a cleanup function.
// TODO(sadovsky): Use v23test.StartRootMountTable.
func CreateShellAndMountTable(t *testing.T, ctx *context.T) (*v23test.Shell, func()) {
sh := v23test.NewShell(t, ctx)
sh.PropagateChildOutput = true
ok := false
defer func() {
if !ok {
sh.Cleanup()
}
}()
mtName := startRootMT(t, sh)
ctx.VI(1).Infof("Started root mount table with name %s", mtName)
oldNamespaceRoots := v23.GetNamespace(ctx).Roots()
fn := func() {
ctx.VI(1).Info("------------ CLEANUP ------------")
ctx.VI(1).Info("---------------------------------")
ctx.VI(1).Info("--(cleaning up shell)------------")
sh.Cleanup()
ctx.VI(1).Info("--(done cleaning up shell)-------")
setNSRoots(t, ctx, oldNamespaceRoots...)
}
setNSRoots(t, ctx, mtName)
sh.Vars[ref.EnvNamespacePrefix] = mtName
ok = true
return sh, fn
}
// CreateShell builds a new shell.
// Returns the shell and a cleanup function.
func CreateShell(t *testing.T, ctx *context.T) (*v23test.Shell, func()) {
sh := v23test.NewShell(t, ctx)
sh.PropagateChildOutput = true
ok := false
defer func() {
if !ok {
sh.Cleanup()
}
}()
fn := func() {
ctx.VI(1).Info("------------ CLEANUP ------------")
ctx.VI(1).Info("---------------------------------")
ctx.VI(1).Info("--(cleaning up shell)------------")
sh.Cleanup()
ctx.VI(1).Info("--(done cleaning up shell)-------")
}
nsRoots := v23.GetNamespace(ctx).Roots()
if len(nsRoots) == 0 {
t.Fatalf("no namespace roots")
}
sh.Vars[ref.EnvNamespacePrefix] = nsRoots[0]
ok = true
return sh, fn
}
// SetupRootDir sets up and returns a directory for the root and returns
// a cleanup function.
func SetupRootDir(t *testing.T, prefix string) (string, func()) {
rootDir, err := ioutil.TempDir("", prefix)
if err != nil {
t.Fatalf("Failed to set up temporary dir for test: %v", err)
}
// On some operating systems (e.g. darwin) os.TempDir() can return a
// symlink. To avoid having to account for this eventuality later,
// evaluate the symlink.
rootDir, err = filepath.EvalSymlinks(rootDir)
if err != nil {
logger.Global().Fatalf("EvalSymlinks(%v) failed: %v", rootDir, err)
}
return rootDir, func() {
if t.Failed() || os.Getenv(preserveWorkspaceEnv) != "" {
t.Logf("A dump of the %s workspace at %v:", prefix, rootDir)
var dump bytes.Buffer
if err := dirprinter.DumpDir(&dump, rootDir); err != nil {
t.Logf("Failed to dump %v: %v", rootDir, err)
} else {
t.Log("\n" + dump.String())
}
} else {
os.RemoveAll(rootDir)
}
}
}