blob: a4e473d09da912b5847b1f5335a2fb714ccfec48 [file] [log] [blame]
package rt_test
import (
"fmt"
"io"
"io/ioutil"
"os"
"regexp"
"testing"
"time"
"v.io/core/veyron2"
"v.io/core/veyron2/security"
"v.io/core/veyron2/vlog"
"v.io/core/veyron/lib/expect"
"v.io/core/veyron/lib/flags/consts"
"v.io/core/veyron/lib/modules"
"v.io/core/veyron/lib/testutil"
vsecurity "v.io/core/veyron/security"
)
func init() {
testutil.Init()
modules.RegisterChild("child", "", child)
modules.RegisterChild("principal", "", principal)
modules.RegisterChild("runner", "", runner)
}
func TestHelperProcess(t *testing.T) {
modules.DispatchInTest()
}
func TestInit(t *testing.T) {
testutil.UnsetPrincipalEnvVars()
ctx, shutdown := veyron2.Init()
defer shutdown()
l := vlog.Log
fmt.Println(l)
args := fmt.Sprintf("%s", l)
expected := regexp.MustCompile("name=veyron logdirs=\\[/tmp\\] logtostderr=true|false alsologtostderr=false|true max_stack_buf_size=4292608 v=[0-9] stderrthreshold=2 vmodule= log_backtrace_at=:0")
if !expected.MatchString(args) {
t.Errorf("unexpected default args: %s", args)
}
p := veyron2.GetPrincipal(ctx)
if p == nil {
t.Fatalf("A new principal should have been created")
}
if p.BlessingStore() == nil {
t.Fatalf("The principal must have a BlessingStore")
}
if p.BlessingStore().Default() == nil {
t.Errorf("Principal().BlessingStore().Default() should not be nil")
}
if p.BlessingStore().ForPeer() == nil {
t.Errorf("Principal().BlessingStore().ForPeer() should not be nil")
}
}
func child(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
_, shutdown := veyron2.Init()
defer shutdown()
logger := vlog.Log
vlog.Infof("%s\n", logger)
fmt.Fprintf(stdout, "%s\n", logger)
modules.WaitForEOF(stdin)
fmt.Fprintf(stdout, "done\n")
return nil
}
func TestInitArgs(t *testing.T) {
sh, err := modules.NewShell(nil, nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
defer sh.Cleanup(os.Stderr, os.Stderr)
h, err := sh.Start("child", nil, "--logtostderr=true", "--vmodule=*=3", "--", "foobar")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
s := expect.NewSession(t, h.Stdout(), time.Minute)
s.Expect(fmt.Sprintf("name=veyron "+
"logdirs=[%s] "+
"logtostderr=true "+
"alsologtostderr=true "+
"max_stack_buf_size=4292608 "+
"v=0 "+
"stderrthreshold=2 "+
"vmodule=*=3 "+
"log_backtrace_at=:0",
os.TempDir()))
h.CloseStdin()
s.Expect("done")
s.ExpectEOF()
h.Shutdown(os.Stderr, os.Stderr)
}
func validatePrincipal(p security.Principal) error {
if p == nil {
return fmt.Errorf("nil principal")
}
blessings := p.BlessingStore().Default()
if blessings == nil {
return fmt.Errorf("rt.Principal().BlessingStore().Default() returned nil")
}
ctx := security.NewContext(&security.ContextParams{LocalPrincipal: p})
if n := len(blessings.ForContext(ctx)); n != 1 {
fmt.Errorf("rt.Principal().BlessingStore().Default() returned Blessing %v with %d recognized blessings, want exactly one recognized blessing", blessings, n)
}
return nil
}
func defaultBlessing(p security.Principal) string {
return p.BlessingStore().Default().ForContext(security.NewContext(&security.ContextParams{LocalPrincipal: p}))[0]
}
func tmpDir(t *testing.T) string {
dir, err := ioutil.TempDir("", "rt_test_dir")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
return dir
}
func principal(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
ctx, shutdown := veyron2.Init()
defer shutdown()
p := veyron2.GetPrincipal(ctx)
if err := validatePrincipal(p); err != nil {
return err
}
fmt.Fprintf(stdout, "DEFAULT_BLESSING=%s\n", defaultBlessing(p))
return nil
}
// Runner runs a principal as a subprocess and reports back with its
// own security info and it's childs.
func runner(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
ctx, shutdown := veyron2.Init()
defer shutdown()
p := veyron2.GetPrincipal(ctx)
if err := validatePrincipal(p); err != nil {
return err
}
fmt.Fprintf(stdout, "RUNNER_DEFAULT_BLESSING=%v\n", defaultBlessing(p))
sh, err := modules.NewShell(ctx, p)
if err != nil {
return err
}
if _, err := sh.Start("principal", nil, args[1:]...); err != nil {
return err
}
// Cleanup copies the output of sh to these Writers.
sh.Cleanup(stdout, stderr)
return nil
}
func createCredentialsInDir(t *testing.T, dir string, blessing string) {
principal, err := vsecurity.CreatePersistentPrincipal(dir, nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if err := vsecurity.InitDefaultBlessings(principal, blessing); err != nil {
t.Fatalf("unexpected error: %s", err)
}
}
func TestPrincipalInheritance(t *testing.T) {
sh, err := modules.NewShell(nil, nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
defer func() {
sh.Cleanup(os.Stdout, os.Stderr)
}()
// Test that the child inherits from the parent's credentials correctly.
// The running test process may or may not have a credentials directory set
// up so we have to use a 'runner' process to ensure the correct setup.
cdir := tmpDir(t)
defer os.RemoveAll(cdir)
createCredentialsInDir(t, cdir, "test")
// directory supplied by the environment.
credEnv := []string{consts.VeyronCredentials + "=" + cdir}
h, err := sh.Start("runner", credEnv)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
s := expect.NewSession(t, h.Stdout(), time.Minute)
runnerBlessing := s.ExpectVar("RUNNER_DEFAULT_BLESSING")
principalBlessing := s.ExpectVar("DEFAULT_BLESSING")
if err := s.Error(); err != nil {
t.Fatalf("failed to read input from children: %s", err)
}
h.Shutdown(os.Stdout, os.Stderr)
wantRunnerBlessing := "test"
wantPrincipalBlessing := "test/child"
if runnerBlessing != wantRunnerBlessing || principalBlessing != wantPrincipalBlessing {
t.Fatalf("unexpected default blessing: got runner %s, principal %s, want runner %s, principal %s", runnerBlessing, principalBlessing, wantRunnerBlessing, wantPrincipalBlessing)
}
}
func TestPrincipalInit(t *testing.T) {
// Collect the process' public key and error status
collect := func(sh *modules.Shell, env []string, args ...string) string {
h, err := sh.Start("principal", env, args...)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
s := expect.NewSession(t, h.Stdout(), time.Minute)
s.SetVerbosity(testing.Verbose())
return s.ExpectVar("DEFAULT_BLESSING")
}
// A credentials directory may, or may, not have been already specified.
// Either way, we want to use our own, so we set it aside and use our own.
origCredentialsDir := os.Getenv(consts.VeyronCredentials)
defer os.Setenv(consts.VeyronCredentials, origCredentialsDir)
// Test that with VEYRON_CREDENTIALS unset the runtime's Principal
// is correctly initialized.
if err := os.Setenv(consts.VeyronCredentials, ""); err != nil {
t.Fatal(err)
}
sh, err := modules.NewShell(nil, nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
defer sh.Cleanup(os.Stderr, os.Stderr)
blessing := collect(sh, nil)
if len(blessing) == 0 {
t.Fatalf("child returned an empty default blessings set")
}
// Test specifying credentials via VEYRON_CREDENTIALS environment.
cdir1 := tmpDir(t)
defer os.RemoveAll(cdir1)
createCredentialsInDir(t, cdir1, "test_env")
credEnv := []string{consts.VeyronCredentials + "=" + cdir1}
blessing = collect(sh, credEnv)
if got, want := blessing, "test_env"; got != want {
t.Errorf("got default blessings: %q, want %q", got, want)
}
// Test specifying credentials via the command line and that the
// comand line overrides the environment
cdir2 := tmpDir(t)
defer os.RemoveAll(cdir2)
createCredentialsInDir(t, cdir2, "test_cmd")
blessing = collect(sh, credEnv, "--veyron.credentials="+cdir2)
if got, want := blessing, "test_cmd"; got != want {
t.Errorf("got %q, want %q", got, want)
}
}