services/device/internal/impl: shard device unit tests (4)

This is CL 4 of n to shard device manager unit tests into multiple
files and packages to permit concurrent test execution. This CL moves
permissions tests into a separate package so that it can execute in
parallel.

Change-Id: Ibb7773b7769fffb1cb0159035fe2debefb3f03bf
diff --git a/services/device/internal/impl/impl_test.go b/services/device/internal/impl/impl_test.go
index babe024..0a3bccd 100644
--- a/services/device/internal/impl/impl_test.go
+++ b/services/device/internal/impl/impl_test.go
@@ -9,10 +9,8 @@
 package impl_test
 
 import (
-	"bytes"
 	"crypto/md5"
 	"encoding/base64"
-	"encoding/hex"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -83,16 +81,6 @@
 	return path
 }
 
-func initForTest() (*context.T, v23.Shutdown) {
-	roots, _ := envvar.NamespaceRoots()
-	for key, _ := range roots {
-		os.Unsetenv(key)
-	}
-	ctx, shutdown := test.InitForTest()
-	v23.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
-	return ctx, shutdown
-}
-
 // TestDeviceManagerUpdateAndRevert makes the device manager go through the
 // motions of updating itself to newer versions (twice), and reverting itself
 // back (twice). It also checks that update and revert fail when they're
@@ -100,7 +88,7 @@
 // command. Further versions are running through the soft link that the device
 // manager itself updates.
 func TestDeviceManagerUpdateAndRevert(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, v23.GetPrincipal(ctx))
@@ -324,7 +312,7 @@
 // TestLifeOfAnApp installs an app, instantiates, runs, kills, and deletes
 // several instances, and performs updates.
 func TestLifeOfAnApp(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -624,173 +612,6 @@
 	}
 }
 
-// TestDeviceManagerClaim claims a devicemanager and tests AccessList permissions on
-// its methods.
-func TestDeviceManagerClaim(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-
-	// root blessing provider so that the principals of all the contexts
-	// recognize each other.
-	idp := testutil.NewIDProvider("root")
-	if err := idp.Bless(v23.GetPrincipal(ctx), "ctx"); err != nil {
-		t.Fatal(err)
-	}
-
-	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
-	defer deferFn()
-
-	// Set up mock application and binary repositories.
-	envelope, cleanup := utiltest.StartMockRepos(t, ctx)
-	defer cleanup()
-
-	root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
-	defer cleanup()
-	if err := impl.SaveCreatorInfo(root); err != nil {
-		t.Fatal(err)
-	}
-
-	// Create a script wrapping the test target that implements suidhelper.
-	helperPath := utiltest.GenerateSuidHelperScript(t, root)
-
-	// Set up the device manager.  Since we won't do device manager updates,
-	// don't worry about its application envelope and current link.
-	pairingToken := "abcxyz"
-	dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link", pairingToken)
-	pid := servicetest.ReadPID(t, dmh)
-	defer syscall.Kill(pid, syscall.SIGINT)
-
-	*envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps", "trapp")
-
-	claimantCtx := utiltest.CtxWithNewPrincipal(t, ctx, idp, "claimant")
-	octx, err := v23.WithPrincipal(ctx, testutil.NewPrincipal("other"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Unclaimed devices cannot do anything but be claimed.
-	// TODO(ashankar,caprita): The line below will currently fail with
-	// ErrUnclaimedDevice != NotTrusted. NotTrusted can be avoided by
-	// passing options.SkipServerEndpointAuthorization{} to the "Install" RPC.
-	// Refactor the helper function to make this possible.
-	//installAppExpectError(t, octx, impl.ErrUnclaimedDevice.ID)
-
-	// Claim the device with an incorrect pairing token should fail.
-	utiltest.ClaimDeviceExpectError(t, claimantCtx, "claimable", "mydevice", "badtoken", impl.ErrInvalidPairingToken.ID)
-	// But succeed with a valid pairing token
-	utiltest.ClaimDevice(t, claimantCtx, "claimable", "dm", "mydevice", pairingToken)
-
-	// Installation should succeed since claimantRT is now the "owner" of
-	// the devicemanager.
-	appID := utiltest.InstallApp(t, claimantCtx)
-
-	// octx will not install the app now since it doesn't recognize the
-	// device's blessings. The error returned will be ErrNoServers as that
-	// is what the IPC stack does when there are no authorized servers.
-	utiltest.InstallAppExpectError(t, octx, verror.ErrNoServers.ID)
-	// Even if it does recognize the device (by virtue of recognizing the
-	// claimant), the device will not allow it to install.
-	if err := v23.GetPrincipal(octx).AddToRoots(v23.GetPrincipal(claimantCtx).BlessingStore().Default()); err != nil {
-		t.Fatal(err)
-	}
-	utiltest.InstallAppExpectError(t, octx, verror.ErrNoAccess.ID)
-
-	// Create the local server that the app uses to let us know it's ready.
-	pingCh, cleanup := utiltest.SetupPingServer(t, claimantCtx)
-	defer cleanup()
-
-	// Start an instance of the app.
-	instanceID := utiltest.LaunchApp(t, claimantCtx, appID)
-
-	// Wait until the app pings us that it's ready.
-	pingCh.WaitForPingArgs(t)
-	utiltest.Resolve(t, ctx, "trapp", 1)
-	utiltest.KillApp(t, claimantCtx, appID, instanceID)
-
-	// TODO(gauthamt): Test that AccessLists persist across devicemanager restarts
-}
-
-func TestDeviceManagerUpdateAccessList(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-
-	// Identity provider to ensure that all processes recognize each
-	// others' blessings.
-	idp := testutil.NewIDProvider("root")
-	ctx = utiltest.CtxWithNewPrincipal(t, ctx, idp, "self")
-
-	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
-	defer deferFn()
-
-	// Set up mock application and binary repositories.
-	envelope, cleanup := utiltest.StartMockRepos(t, ctx)
-	defer cleanup()
-
-	root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
-	defer cleanup()
-	if err := impl.SaveCreatorInfo(root); err != nil {
-		t.Fatal(err)
-	}
-
-	selfCtx := ctx
-	octx := utiltest.CtxWithNewPrincipal(t, selfCtx, idp, "other")
-
-	// Set up the device manager.  Since we won't do device manager updates,
-	// don't worry about its application envelope and current link.
-	dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, "unused_helper", "unused_app_repo_name", "unused_curr_link")
-	pid := servicetest.ReadPID(t, dmh)
-	defer syscall.Kill(pid, syscall.SIGINT)
-	defer utiltest.VerifyNoRunningProcesses(t)
-
-	// Create an envelope for an app.
-	*envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps")
-
-	// On an unclaimed device manager, there will be no AccessLists.
-	if _, _, err := device.DeviceClient("claimable").GetPermissions(selfCtx); err == nil {
-		t.Fatalf("GetPermissions should have failed but didn't.")
-	}
-
-	// Claim the devicemanager as "root/self/mydevice"
-	utiltest.ClaimDevice(t, selfCtx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
-	expectedAccessList := make(access.Permissions)
-	for _, tag := range access.AllTypicalTags() {
-		expectedAccessList[string(tag)] = access.AccessList{In: []security.BlessingPattern{"root/$", "root/self/$", "root/self/mydevice/$"}}
-	}
-	var b bytes.Buffer
-	if err := expectedAccessList.WriteTo(&b); err != nil {
-		t.Fatalf("Failed to save AccessList:%v", err)
-	}
-	// Note, "version" below refers to the Permissions version, not the device
-	// manager version.
-	md5hash := md5.Sum(b.Bytes())
-	expectedVersion := hex.EncodeToString(md5hash[:])
-	deviceStub := device.DeviceClient("dm/device")
-	perms, version, err := deviceStub.GetPermissions(selfCtx)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if version != expectedVersion {
-		t.Fatalf("getAccessList expected:%v(%v), got:%v(%v)", expectedAccessList, expectedVersion, perms, version)
-	}
-	// Install from octx should fail, since it does not match the AccessList.
-	utiltest.InstallAppExpectError(t, octx, verror.ErrNoAccess.ID)
-
-	newAccessList := make(access.Permissions)
-	for _, tag := range access.AllTypicalTags() {
-		newAccessList.Add("root/other", string(tag))
-	}
-	if err := deviceStub.SetPermissions(selfCtx, newAccessList, "invalid"); err == nil {
-		t.Fatalf("SetPermissions should have failed with invalid version")
-	}
-	if err := deviceStub.SetPermissions(selfCtx, newAccessList, version); err != nil {
-		t.Fatal(err)
-	}
-	// Install should now fail with selfCtx, which no longer matches the
-	// AccessLists but succeed with octx, which does.
-	utiltest.InstallAppExpectError(t, selfCtx, verror.ErrNoAccess.ID)
-	utiltest.InstallApp(t, octx)
-}
-
 type simpleRW chan []byte
 
 func (s simpleRW) Write(p []byte) (n int, err error) {
@@ -807,7 +628,7 @@
 // This should bring up a functioning device manager.  In the end it runs
 // Uninstall and verifies that the installation is gone.
 func TestDeviceManagerInstallation(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -867,7 +688,7 @@
 }
 
 func TestDeviceManagerGlobAndDebug(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -966,7 +787,7 @@
 // TODO(caprita): We need better test coverage for how updating/reverting apps
 // affects the package configured for the app.
 func TestDeviceManagerPackages(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -1106,7 +927,7 @@
 // TODO(rjkroege): Verify that associations persist across restarts once
 // permanent storage is added.
 func TestAccountAssociation(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
@@ -1192,7 +1013,7 @@
 }
 
 func TestAppWithSuidHelper(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	// Identity provider used to ensure that all processes recognize each
@@ -1357,7 +1178,7 @@
 }
 
 func TestDownloadSignatureMatch(t *testing.T) {
-	ctx, shutdown := initForTest()
+	ctx, shutdown := utiltest.InitForTest()
 	defer shutdown()
 
 	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
diff --git a/services/device/internal/impl/debug_perms_test.go b/services/device/internal/impl/perms/debug_perms_test.go
similarity index 96%
rename from services/device/internal/impl/debug_perms_test.go
rename to services/device/internal/impl/perms/debug_perms_test.go
index 306cebe..9c6e757 100644
--- a/services/device/internal/impl/debug_perms_test.go
+++ b/services/device/internal/impl/perms/debug_perms_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package impl_test
+package perms_test
 
 import (
 	"io/ioutil"
@@ -226,15 +226,15 @@
 			[]string{
 				// STDERR and STDOUT are not handled through the log package so
 				// are not included here.
-				"impl.test.INFO",
-				"impl.test.<*>.INFO.<timestamp>",
+				"perms.test.INFO",
+				"perms.test.<*>.INFO.<timestamp>",
 			},
 		},
 	}
-	res := utiltest.NewGlobTestRegexHelper(`impl\.test`)
+	res := utiltest.NewGlobTestRegexHelper(`perms\.test`)
 
 	// Bob claimed the DM so can access it.
-	utiltest.VerifyGlob(t, bobCtx, "impl.test", dmGlobtests, res)
+	utiltest.VerifyGlob(t, bobCtx, "perms.test", dmGlobtests, res)
 	utiltest.VerifyStatsValues(t, bobCtx, "dm", "__debug", "stats/system/start-time*")
 
 	// Without permissions, hackerjoe can't access the device manager.
@@ -247,14 +247,14 @@
 
 	// Alice is an adminstrator and so can can access device manager __debug
 	// values.
-	utiltest.VerifyGlob(t, aliceCtx, "impl.test", dmGlobtests, res)
+	utiltest.VerifyGlob(t, aliceCtx, "perms.test", dmGlobtests, res)
 	utiltest.VerifyStatsValues(t, aliceCtx, "dm", "__debug", "stats/system/start-time*")
 
 	// Bob gives debug access to the device manager to hackerjoe
 	updateAccessList(t, bobCtx, "root/hackerjoe/$", string(access.Debug), "dm", "device")
 
 	// hackerjoe can now access the device manager
-	utiltest.VerifyGlob(t, hjCtx, "impl.test", dmGlobtests, res)
+	utiltest.VerifyGlob(t, hjCtx, "perms.test", dmGlobtests, res)
 	utiltest.VerifyStatsValues(t, hjCtx, "dm", "__debug", "stats/system/start-time*")
 
 	// Cleanly shut down the device manager.
diff --git a/services/device/internal/impl/perms/doc.go b/services/device/internal/impl/perms/doc.go
new file mode 100644
index 0000000..afd8566
--- /dev/null
+++ b/services/device/internal/impl/perms/doc.go
@@ -0,0 +1,7 @@
+// 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 perms
+
+// Test code for claiming and permission list code in the device manager.
diff --git a/services/device/internal/impl/perms/impl_test.go b/services/device/internal/impl/perms/impl_test.go
new file mode 100644
index 0000000..37a5102
--- /dev/null
+++ b/services/device/internal/impl/perms/impl_test.go
@@ -0,0 +1,19 @@
+// 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 perms_test
+
+import (
+	"testing"
+
+	"v.io/x/ref/services/device/internal/impl/utiltest"
+)
+
+func TestMain(m *testing.M) {
+	utiltest.TestMainImpl(m)
+}
+
+func TestSuidHelper(t *testing.T) {
+	utiltest.TestSuidHelperImpl(t)
+}
diff --git a/services/device/internal/impl/perms/perms_test.go b/services/device/internal/impl/perms/perms_test.go
new file mode 100644
index 0000000..83bd086
--- /dev/null
+++ b/services/device/internal/impl/perms/perms_test.go
@@ -0,0 +1,191 @@
+// 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 perms_test
+
+import (
+	"bytes"
+	"crypto/md5"
+	"encoding/hex"
+	"syscall"
+	"testing"
+
+	"v.io/v23"
+	"v.io/v23/security"
+	"v.io/v23/security/access"
+	"v.io/v23/services/device"
+	"v.io/v23/verror"
+
+	"v.io/x/ref/services/device/internal/impl"
+	"v.io/x/ref/services/device/internal/impl/utiltest"
+	"v.io/x/ref/services/internal/servicetest"
+	"v.io/x/ref/test/testutil"
+)
+
+// TestDeviceManagerClaim claims a devicemanager and tests AccessList permissions on
+// its methods.
+func TestDeviceManagerClaim(t *testing.T) {
+	ctx, shutdown := utiltest.InitForTest()
+	defer shutdown()
+
+	// root blessing provider so that the principals of all the contexts
+	// recognize each other.
+	idp := testutil.NewIDProvider("root")
+	if err := idp.Bless(v23.GetPrincipal(ctx), "ctx"); err != nil {
+		t.Fatal(err)
+	}
+
+	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
+	defer deferFn()
+
+	// Set up mock application and binary repositories.
+	envelope, cleanup := utiltest.StartMockRepos(t, ctx)
+	defer cleanup()
+
+	root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
+	defer cleanup()
+	if err := impl.SaveCreatorInfo(root); err != nil {
+		t.Fatal(err)
+	}
+
+	// Create a script wrapping the test target that implements suidhelper.
+	helperPath := utiltest.GenerateSuidHelperScript(t, root)
+
+	// Set up the device manager.  Since we won't do device manager updates,
+	// don't worry about its application envelope and current link.
+	pairingToken := "abcxyz"
+	dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link", pairingToken)
+	pid := servicetest.ReadPID(t, dmh)
+	defer syscall.Kill(pid, syscall.SIGINT)
+
+	*envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps", "trapp")
+
+	claimantCtx := utiltest.CtxWithNewPrincipal(t, ctx, idp, "claimant")
+	octx, err := v23.WithPrincipal(ctx, testutil.NewPrincipal("other"))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Unclaimed devices cannot do anything but be claimed.
+	// TODO(ashankar,caprita): The line below will currently fail with
+	// ErrUnclaimedDevice != NotTrusted. NotTrusted can be avoided by
+	// passing options.SkipServerEndpointAuthorization{} to the "Install" RPC.
+	// Refactor the helper function to make this possible.
+	//installAppExpectError(t, octx, impl.ErrUnclaimedDevice.ID)
+
+	// Claim the device with an incorrect pairing token should fail.
+	utiltest.ClaimDeviceExpectError(t, claimantCtx, "claimable", "mydevice", "badtoken", impl.ErrInvalidPairingToken.ID)
+	// But succeed with a valid pairing token
+	utiltest.ClaimDevice(t, claimantCtx, "claimable", "dm", "mydevice", pairingToken)
+
+	// Installation should succeed since claimantRT is now the "owner" of
+	// the devicemanager.
+	appID := utiltest.InstallApp(t, claimantCtx)
+
+	// octx will not install the app now since it doesn't recognize the
+	// device's blessings. The error returned will be ErrNoServers as that
+	// is what the IPC stack does when there are no authorized servers.
+	utiltest.InstallAppExpectError(t, octx, verror.ErrNoServers.ID)
+	// Even if it does recognize the device (by virtue of recognizing the
+	// claimant), the device will not allow it to install.
+	if err := v23.GetPrincipal(octx).AddToRoots(v23.GetPrincipal(claimantCtx).BlessingStore().Default()); err != nil {
+		t.Fatal(err)
+	}
+	utiltest.InstallAppExpectError(t, octx, verror.ErrNoAccess.ID)
+
+	// Create the local server that the app uses to let us know it's ready.
+	pingCh, cleanup := utiltest.SetupPingServer(t, claimantCtx)
+	defer cleanup()
+
+	// Start an instance of the app.
+	instanceID := utiltest.LaunchApp(t, claimantCtx, appID)
+
+	// Wait until the app pings us that it's ready.
+	pingCh.WaitForPingArgs(t)
+	utiltest.Resolve(t, ctx, "trapp", 1)
+	utiltest.KillApp(t, claimantCtx, appID, instanceID)
+
+	// TODO(gauthamt): Test that AccessLists persist across devicemanager restarts
+}
+
+func TestDeviceManagerUpdateAccessList(t *testing.T) {
+	ctx, shutdown := utiltest.InitForTest()
+	defer shutdown()
+
+	// Identity provider to ensure that all processes recognize each
+	// others' blessings.
+	idp := testutil.NewIDProvider("root")
+	ctx = utiltest.CtxWithNewPrincipal(t, ctx, idp, "self")
+
+	sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
+	defer deferFn()
+
+	// Set up mock application and binary repositories.
+	envelope, cleanup := utiltest.StartMockRepos(t, ctx)
+	defer cleanup()
+
+	root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
+	defer cleanup()
+	if err := impl.SaveCreatorInfo(root); err != nil {
+		t.Fatal(err)
+	}
+
+	selfCtx := ctx
+	octx := utiltest.CtxWithNewPrincipal(t, selfCtx, idp, "other")
+
+	// Set up the device manager.  Since we won't do device manager updates,
+	// don't worry about its application envelope and current link.
+	dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, "unused_helper", "unused_app_repo_name", "unused_curr_link")
+	pid := servicetest.ReadPID(t, dmh)
+	defer syscall.Kill(pid, syscall.SIGINT)
+	defer utiltest.VerifyNoRunningProcesses(t)
+
+	// Create an envelope for an app.
+	*envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps")
+
+	// On an unclaimed device manager, there will be no AccessLists.
+	if _, _, err := device.DeviceClient("claimable").GetPermissions(selfCtx); err == nil {
+		t.Fatalf("GetPermissions should have failed but didn't.")
+	}
+
+	// Claim the devicemanager as "root/self/mydevice"
+	utiltest.ClaimDevice(t, selfCtx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
+	expectedAccessList := make(access.Permissions)
+	for _, tag := range access.AllTypicalTags() {
+		expectedAccessList[string(tag)] = access.AccessList{In: []security.BlessingPattern{"root/$", "root/self/$", "root/self/mydevice/$"}}
+	}
+	var b bytes.Buffer
+	if err := expectedAccessList.WriteTo(&b); err != nil {
+		t.Fatalf("Failed to save AccessList:%v", err)
+	}
+	// Note, "version" below refers to the Permissions version, not the device
+	// manager version.
+	md5hash := md5.Sum(b.Bytes())
+	expectedVersion := hex.EncodeToString(md5hash[:])
+	deviceStub := device.DeviceClient("dm/device")
+	perms, version, err := deviceStub.GetPermissions(selfCtx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if version != expectedVersion {
+		t.Fatalf("getAccessList expected:%v(%v), got:%v(%v)", expectedAccessList, expectedVersion, perms, version)
+	}
+	// Install from octx should fail, since it does not match the AccessList.
+	utiltest.InstallAppExpectError(t, octx, verror.ErrNoAccess.ID)
+
+	newAccessList := make(access.Permissions)
+	for _, tag := range access.AllTypicalTags() {
+		newAccessList.Add("root/other", string(tag))
+	}
+	if err := deviceStub.SetPermissions(selfCtx, newAccessList, "invalid"); err == nil {
+		t.Fatalf("SetPermissions should have failed with invalid version")
+	}
+	if err := deviceStub.SetPermissions(selfCtx, newAccessList, version); err != nil {
+		t.Fatal(err)
+	}
+	// Install should now fail with selfCtx, which no longer matches the
+	// AccessLists but succeed with octx, which does.
+	utiltest.InstallAppExpectError(t, selfCtx, verror.ErrNoAccess.ID)
+	utiltest.InstallApp(t, octx)
+}
diff --git a/services/device/internal/impl/reaping/impl_test.go b/services/device/internal/impl/reaping/impl_test.go
index abc7f7a..66d1c4e 100644
--- a/services/device/internal/impl/reaping/impl_test.go
+++ b/services/device/internal/impl/reaping/impl_test.go
@@ -14,8 +14,6 @@
 	utiltest.TestMainImpl(m)
 }
 
-// TestSuidHelper is testing boilerplate for suidhelper that does not
-// create a runtime because the suidhelper is not a Vanadium application.
 func TestSuidHelper(t *testing.T) {
 	utiltest.TestSuidHelperImpl(t)
 }
diff --git a/services/device/internal/impl/utiltest/helpers.go b/services/device/internal/impl/utiltest/helpers.go
index 5b753c0..4e82508 100644
--- a/services/device/internal/impl/utiltest/helpers.go
+++ b/services/device/internal/impl/utiltest/helpers.go
@@ -33,6 +33,7 @@
 	"v.io/v23/services/stats"
 	"v.io/v23/verror"
 
+	"v.io/x/ref/envvar"
 	_ "v.io/x/ref/profiles/roaming"
 	"v.io/x/ref/services/device/internal/impl"
 	"v.io/x/ref/services/internal/servicetest"
@@ -665,3 +666,13 @@
 	}
 	return u.Username
 }
+
+func InitForTest() (*context.T, v23.Shutdown) {
+	roots, _ := envvar.NamespaceRoots()
+	for key, _ := range roots {
+		os.Unsetenv(key)
+	}
+	ctx, shutdown := test.InitForTest()
+	v23.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
+	return ctx, shutdown
+}