services/mounttable/btmtd: Add more tests

Add more tests for node mutations.

Change-Id: Id851ab384938266205a3ba87cc37ad52e72452c2
diff --git a/services/mounttable/btmtd/internal/node_test.go b/services/mounttable/btmtd/internal/node_test.go
new file mode 100644
index 0000000..7918069
--- /dev/null
+++ b/services/mounttable/btmtd/internal/node_test.go
@@ -0,0 +1,153 @@
+// Copyright 2016 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 internal
+
+import (
+	"math/rand"
+	"testing"
+	"time"
+
+	"v.io/v23/security"
+	"v.io/v23/security/access"
+	"v.io/x/ref/test"
+)
+
+func TestMutations(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	bt, shutdownBT, err := NewTestBigTable("test")
+	if err != nil {
+		t.Fatalf("NewTestBigTable: %s", err)
+	}
+	defer shutdownBT()
+	if err := bt.SetupTable(ctx, ""); err != nil {
+		t.Fatalf("bt.SetupTable: %s", err)
+	}
+
+	root, err := getNode(ctx, bt, "")
+	if err != nil {
+		t.Fatalf("getNode: %v", err)
+	}
+
+	ops := []func(i int, n *mtNode) bool{
+		func(i int, n *mtNode) bool {
+			if err := n.delete(ctx, false); err != nil {
+				t.Logf("[%d] delete: %v", i, err)
+				return false
+			}
+			t.Logf("[%d] delete succeeded", i)
+			m, err := getNode(ctx, bt, "X")
+			if err != nil {
+				t.Errorf("[%d] getNode failed after delete: %v", i, err)
+				return false
+			}
+			if m != nil {
+				t.Errorf("[%d] node still exists after delete", i)
+				return false
+			}
+			return true
+		},
+		func(i int, n *mtNode) bool {
+			if child, err := n.createChild(ctx, "Y", n.permissions); err != nil {
+				t.Logf("[%d] createChild: (%v, %v)", i, child, err)
+				return false
+			}
+			t.Logf("[%d] createChild succeeded", i)
+			m, err := getNode(ctx, bt, "X")
+			if err != nil {
+				t.Errorf("[%d] getNode failed after createChild: %v", i, err)
+				return false
+			}
+			if m == nil {
+				t.Errorf("[%d] node doesn't exist after createChild", i)
+				return false
+			}
+			if len(m.children) != 1 || m.children[0] != "Y" {
+				t.Errorf("[%d] unexpected children after createChild: %v", i, m.children)
+				return false
+			}
+			return true
+		},
+		func(i int, n *mtNode) bool {
+			const serverAddr = "/example.com:1234"
+			if err := n.mount(ctx, serverAddr, clock.Now().Add(time.Minute), 0); err != nil {
+				t.Logf("[%d] mount: %v", i, err)
+				return false
+			}
+			t.Logf("[%d] mount succeeded", i)
+			m, err := getNode(ctx, bt, "X")
+			if err != nil {
+				t.Errorf("[%d] getNode failed after mount: %v", i, err)
+				return false
+			}
+			if m == nil {
+				t.Errorf("[%d] node doesn't exist after mount", i)
+				return false
+			}
+			if len(m.servers) != 1 || m.servers[0].Server != serverAddr {
+				t.Errorf("[%d] unexpected servers after mount: %v", i, m.servers)
+				return false
+			}
+			return true
+		},
+		func(i int, n *mtNode) bool {
+			perm := access.Permissions{"Admin": access.AccessList{In: []security.BlessingPattern{"foo"}}}
+			if err := n.setPermissions(ctx, perm); err != nil {
+				t.Logf("[%d] setPermissions: %v", i, err)
+				return false
+			}
+			t.Logf("[%d] setPermissions succeeded", i)
+			m, err := getNode(ctx, bt, "X")
+			if err != nil {
+				t.Errorf("[%d] getNode failed after setPermissions: %v", i, err)
+				return false
+			}
+			if m == nil {
+				t.Errorf("[%d] node doesn't exist after setPermissions", i)
+				return false
+			}
+			if len(m.permissions["Admin"].In) != 1 || string(m.permissions["Admin"].In[0]) != "foo" {
+				t.Errorf("[%d] unexpected permissions after setPermissions: %v", i, m.permissions)
+			}
+			return true
+		},
+	}
+	for i := 1; i <= 100; i++ {
+		// Create X.
+		root, _ = getNode(ctx, bt, "")
+		n, err := root.createChild(ctx, "X", root.permissions)
+		if err != nil || n == nil {
+			t.Fatalf("createChild(X): (%v, %v)", n, err)
+		}
+
+		// Attempt all the mutations in random order. Only the first one
+		// should ever succeed because the node version changes after
+		// successful mutations.
+		for j, p := range rand.Perm(len(ops)) {
+			success := ops[p](i, n)
+			switch {
+			case j == 0 && !success:
+				t.Errorf("Unexpected failure for first mutation")
+			case j > 0 && success:
+				t.Errorf("Unexpected success for mutation")
+			}
+		}
+
+		// Delete X, if it still exists.
+		if n, err := getNode(ctx, bt, "X"); err == nil && n != nil {
+			n.delete(ctx, true)
+		}
+	}
+
+	count, err := bt.CountRows(ctx)
+	if err != nil {
+		t.Errorf("CountRows failed: %v", err)
+	}
+	if expected := 1; count != expected {
+		t.Errorf("Unexpected number of rows: got %d, expected %d", count, expected)
+		bt.DumpTable(ctx)
+	}
+}