veyron/tools/principal: finish porting old-style integration test
Change-Id: Ib6b2b5e3b6301149baeba5d34e0c8de42b1a1b57
diff --git a/tools/principal/principal_v23_test.go b/tools/principal/principal_v23_test.go
index 47b92b9..5d288dd 100644
--- a/tools/principal/principal_v23_test.go
+++ b/tools/principal/principal_v23_test.go
@@ -1,12 +1,17 @@
package main_test
import (
+ "bytes"
"io/ioutil"
"os"
"path/filepath"
"regexp"
+ "strings"
+ "syscall"
"testing"
+ "time"
+ "v.io/core/veyron/lib/expect"
"v.io/core/veyron/lib/modules"
"v.io/core/veyron/lib/testutil/v23tests"
)
@@ -24,6 +29,17 @@
}
}
+// removePublicKeys replaces public keys (16 hex bytes, :-separated) with
+// XX:.... This substitution enables comparison with golden output even when
+// keys are freshly minted by the "principal create" command.
+func removePublicKeys(input string) string {
+ return regexp.MustCompile("([0-9a-f]{2}:){15}[0-9a-f]{2}").ReplaceAllString(input, "XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX")
+}
+
+func removeCaveats(input string) string {
+ return regexp.MustCompile("0x54a676398137187ecdb26d2d69ba0004\\(int64=.*\\)").ReplaceAllString(input, "ExpiryCaveat")
+}
+
func V23TestBlessSelf(t *v23tests.T) {
var (
outputDir = t.TempDir()
@@ -36,13 +52,238 @@
bin = bin.WithEnv("VEYRON_CREDENTIALS=" + aliceDir)
redirect(t, bin.Start("blessself", "alicereborn"), aliceBlessingFile)
- got := bin.Start("dumpblessings", aliceBlessingFile).Output()
+ got := removePublicKeys(bin.Start("dumpblessings", aliceBlessingFile).Output())
want := `Blessings : alicereborn
-PublicKey : ([0-9a-f]{2}:){15}[0-9a-f]{2}
+PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
Certificate chains : 1
-Chain #0 \(1 certificates\). Root certificate public key: ([0-9a-f]{2}:){15}[0-9a-f]{2}
- Certificate #0: alicereborn with 0 caveats`
- if regexp.MustCompile(want).FindString(got) == "" {
- t.Fatalf("wanted something matching \n%s, got \n%s\n", want, got)
+Chain #0 (1 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+ Certificate #0: alicereborn with 0 caveats
+`
+ if want != got {
+ t.Fatalf("unexpected output, wanted \n%s, got\n%s", want, got)
}
}
+
+func V23TestStore(t *v23tests.T) {
+ var (
+ outputDir = t.TempDir()
+ bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
+ aliceDir = filepath.Join(outputDir, "alice")
+ aliceFriend = filepath.Join(outputDir, "alice.bless")
+ bobDir = filepath.Join(outputDir, "bob")
+ bobForPeer = filepath.Join(outputDir, "bob.store.forpeer")
+ )
+
+ // Create two principals: alice and bob.
+ bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr)
+ bin.Start("create", bobDir, "bob").WaitOrDie(os.Stdout, os.Stderr)
+
+ // Bless Alice with Bob's principal.
+ blessEnv := []string{"VEYRON_CREDENTIALS=" + aliceDir}
+ redirect(t, bin.WithEnv(blessEnv...).Start("bless", bobDir, "friend"), aliceFriend)
+
+ // Run store forpeer on bob.
+ bin.Start("--veyron.credentials="+bobDir, "store", "set", aliceFriend, "alice").WaitOrDie(os.Stdout, os.Stderr)
+ redirect(t, bin.WithEnv(blessEnv...).Start("--veyron.credentials="+bobDir, "store", "forpeer", "alice/server"), bobForPeer)
+
+ got := removeCaveats(removePublicKeys(bin.Start("dumpblessings", bobForPeer).Output()))
+ want := `Blessings : bob#alice/friend
+PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+Certificate chains : 2
+Chain #0 (1 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+ Certificate #0: bob with 0 caveats
+Chain #1 (2 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+ Certificate #0: alice with 0 caveats
+ Certificate #1: friend with 1 caveat
+ (0) ExpiryCaveat
+`
+ if want != got {
+ t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
+ }
+}
+
+func V23TestDump(t *v23tests.T) {
+ var (
+ outputDir = t.TempDir()
+ bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
+ aliceDir = filepath.Join(outputDir, "alice")
+ )
+
+ bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr)
+
+ blessEnv := []string{"VEYRON_CREDENTIALS=" + aliceDir}
+ got := removePublicKeys(bin.WithEnv(blessEnv...).Start("dump").Output())
+ want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+---------------- BlessingStore ----------------
+Default blessings: alice
+Peer pattern : Blessings
+... : alice
+---------------- BlessingRoots ----------------
+Public key : Pattern
+XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX : [alice]
+`
+ if want != got {
+ t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
+ }
+}
+
+func V23TestRecvBlessings(t *v23tests.T) {
+ var (
+ outputDir = t.TempDir()
+ bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
+ aliceDir = filepath.Join(outputDir, "alice")
+ carolDir = filepath.Join(outputDir, "carol")
+ )
+
+ // Generate principals for alice and carol.
+ bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr)
+ bin.Start("create", carolDir, "carol").WaitOrDie(os.Stdout, os.Stderr)
+
+ // Run recvblessings on carol, and have alice send blessings over
+ // (blessings received must be set as default and shareable with all peers).
+ var args []string
+ {
+ inv := bin.Start("--veyron.credentials="+carolDir, "--veyron.tcp.address=127.0.0.1:0", "recvblessings")
+ defer inv.Kill(syscall.SIGTERM)
+ // recvblessings suggests a random extension, find the extension and replace it with friend/carol.
+ e := expect.NewSession(t, inv.Stdout(), 3*time.Second)
+ cmd := e.ExpectSetEventuallyRE("(^principal bless .*$)")[0][0]
+ args = strings.Split(regexp.MustCompile("extension[0-9]*").ReplaceAllString(cmd, "friend/carol"), " ")
+ }
+
+ bin.WithEnv("VEYRON_CREDENTIALS="+aliceDir).Start(args[1:]...).WaitOrDie(os.Stdout, os.Stderr)
+
+ // Run recvblessings on carol, and have alice send blessings over
+ // (blessings received must be set as shareable with peers matching 'alice/...'.)
+ {
+ inv := bin.Start("--veyron.credentials="+carolDir, "--veyron.tcp.address=127.0.0.1:0", "recvblessings", "--for_peer=alice", "--set_default=false")
+ defer inv.Kill(syscall.SIGTERM)
+ // recvblessings suggests a random extension, find the extension and replace it with friend/carol/foralice.
+ e := expect.NewSession(t, inv.Stdout(), 3*time.Second)
+ cmd := e.ExpectSetEventuallyRE("(^principal bless .*$)")[0][0]
+ args = strings.Split(regexp.MustCompile("extension[0-9]*").ReplaceAllString(cmd, "friend/carol/foralice"), " ")
+ }
+ bin.WithEnv("VEYRON_CREDENTIALS="+aliceDir).Start(args[1:]...).WaitOrDie(os.Stdout, os.Stderr)
+
+ listenerInv := bin.Start("--veyron.credentials="+carolDir, "--veyron.tcp.address=127.0.0.1:0", "recvblessings", "--for_peer=alice/...", "--set_default=false", "--vmodule=*=2", "--logtostderr")
+ defer listenerInv.Kill(syscall.SIGTERM)
+
+ e := expect.NewSession(t, listenerInv.Stdout(), 3*time.Second)
+ sendCmd := e.ExpectSetEventuallyRE("(^principal bless .*$)")[0][0]
+ // Mucking around with the key should fail.
+ args = strings.Split(regexp.MustCompile("remote_key=").ReplaceAllString(sendCmd, "remote_key=BAD"), " ")
+
+ {
+ var buf bytes.Buffer
+ if bin.WithEnv("VEYRON_CREDENTIALS="+aliceDir).Start(args[1:]...).Wait(os.Stdout, &buf) == nil {
+ t.Fatalf("sender should have failed but did not")
+ }
+
+ if want, got := "key mismatch", buf.String(); !strings.Contains(got, want) {
+ t.Fatalf("expected %q to be contained within\n%s\n, but was not", want, got)
+ }
+ }
+
+ {
+ var buf bytes.Buffer
+ // Mucking around with the token should fail.
+ args = strings.Split(regexp.MustCompile("remote_token=").ReplaceAllString(sendCmd, "remote_token=BAD"), " ")
+ if bin.WithEnv("VEYRON_CREDENTIALS="+aliceDir).Start(args[1:]...).Wait(os.Stdout, &buf) == nil {
+ t.Fatalf("sender should have failed but did not")
+ }
+
+ if want, got := "blessings received from unexpected sender", buf.String(); !strings.Contains(got, want) {
+ t.Fatalf("expected %q to be contained within\n%s\n, but was not", want, got)
+ }
+ }
+
+ // Dump carol out, the only blessing that survives should be from the
+ // first "bless" command. (alice/friend/carol).
+ got := removePublicKeys(bin.Start("--veyron.credentials="+carolDir, "dump").Output())
+ want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+---------------- BlessingStore ----------------
+Default blessings: alice/friend/carol
+Peer pattern : Blessings
+... : alice/friend/carol
+alice : alice/friend/carol/foralice
+---------------- BlessingRoots ----------------
+Public key : Pattern
+XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX : [alice]
+XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX : [carol]
+`
+ if want != got {
+ t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
+ }
+}
+
+func V23TestFork(t *v23tests.T) {
+ var (
+ outputDir = t.TempDir()
+ bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
+ aliceDir = filepath.Join(outputDir, "alice")
+ alicePhoneDir = filepath.Join(outputDir, "alice-phone")
+ alicePhoneCalendarDir = filepath.Join(outputDir, "alice-phone-calendar")
+ )
+
+ // Generate principals for alice.
+ bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr)
+
+ // Run fork to setup up credentials for alice/phone that are
+ // blessed by alice under the extension "phone".
+ bin.Start("--veyron.credentials="+aliceDir, "fork", alicePhoneDir, "phone").WaitOrDie(os.Stdout, os.Stderr)
+
+ // Dump alice-phone out, the only blessings it has must be from alice (alice/phone).
+ {
+ got := removePublicKeys(bin.Start("--veyron.credentials="+alicePhoneDir, "dump").Output())
+ want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+---------------- BlessingStore ----------------
+Default blessings: alice/phone
+Peer pattern : Blessings
+... : alice/phone
+---------------- BlessingRoots ----------------
+Public key : Pattern
+XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX : [alice]
+`
+ if want != got {
+ t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
+ }
+ }
+
+ // Run fork to setup up credentials for alice/phone/calendar that are
+ // blessed by alice/phone under the extension "calendar".
+ bin.Start("--veyron.credentials="+alicePhoneDir, "fork", alicePhoneCalendarDir, "calendar").WaitOrDie(os.Stdout, os.Stderr)
+ {
+ got := removePublicKeys(bin.Start("--veyron.credentials="+alicePhoneCalendarDir, "dump").Output())
+ want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+---------------- BlessingStore ----------------
+Default blessings: alice/phone/calendar
+Peer pattern : Blessings
+... : alice/phone/calendar
+---------------- BlessingRoots ----------------
+Public key : Pattern
+XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX : [alice]
+`
+ if want != got {
+ t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want)
+ }
+ }
+}
+
+func V23TestCreate(t *v23tests.T) {
+ var (
+ outputDir = t.TempDir()
+ bin = t.BuildGoPkg("v.io/core/veyron/tools/principal")
+ aliceDir = filepath.Join(outputDir, "alice")
+ )
+
+ // Creating a principal should succeed the first time.
+ bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr)
+
+ // The second time should fail (the create command won't override an existing principal).
+ if bin.Start("create", aliceDir, "alice").Wait(os.Stdout, os.Stderr) == nil {
+ t.Fatalf("principal creation should have failed, but did not")
+ }
+
+ // If we specify -overwrite, it will.
+ bin.Start("create", "--overwrite", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr)
+}