runtime/internal/lib/publisher: make this asynchronous for real and fix up all unit tests.
MultiPart: 1/2
Change-Id: Ic03a1241a1114dc2ab15525b2a4ec1eb4c190694
diff --git a/runtime/internal/naming/namespace/all_test.go b/runtime/internal/naming/namespace/all_test.go
index fd269d5..a2c4afe 100644
--- a/runtime/internal/naming/namespace/all_test.go
+++ b/runtime/internal/naming/namespace/all_test.go
@@ -31,6 +31,17 @@
//go:generate v23 test generate
+func resolveWithRetry(ctx *context.T, name string, opts ...naming.NamespaceOpt) *naming.MountEntry {
+ ns := v23.GetNamespace(ctx)
+ for {
+ mp, err := ns.Resolve(ctx, name, opts...)
+ if err == nil {
+ return mp
+ }
+ time.Sleep(100 * time.Millisecond)
+ }
+}
+
func createContexts(t *testing.T) (sc, c *context.T, cleanup func()) {
ctx, shutdown := test.InitForTest()
var (
@@ -222,6 +233,8 @@
boom(t, "Failed to serve mount table at %s: %s", mountPoint, err)
}
t.Logf("server %q -> %s", eps[0].Name(), mountPoint)
+ // Wait until the mount point appears in the mount table.
+ resolveWithRetry(ctx, mountPoint)
return &serverEntry{mountPoint: mountPoint, server: s, endpoint: eps[0], name: eps[0].Name()}
}
@@ -644,17 +657,12 @@
mtCtx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal()) // intermediate mounttable
serverCtx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal()) // end server
clientCtx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal()) // client process (doing Resolves).
- idp = testutil.NewIDProvider("idp") // identity provider
+ clientNs = v23.GetNamespace(clientCtx)
+ serverNs = v23.GetNamespace(serverCtx)
+ idp = testutil.NewIDProvider("idp") // identity provider
serverEndpoint = naming.FormatEndpoint("tcp", "127.0.0.1:14141")
-
- resolve = func(name string, opts ...naming.NamespaceOpt) (*naming.MountEntry, error) {
- return v23.GetNamespace(clientCtx).Resolve(clientCtx, name, opts...)
- }
-
- mount = func(name, server string, ttl time.Duration, opts ...naming.NamespaceOpt) error {
- return v23.GetNamespace(serverCtx).Mount(serverCtx, name, server, ttl, opts...)
- }
)
+
// Setup default blessings for the processes.
idp.Bless(v23.GetPrincipal(rootMtCtx), "rootmt")
idp.Bless(v23.GetPrincipal(serverCtx), "server")
@@ -668,45 +676,46 @@
}
// Disable caching in the client so that any Mount calls by the server
// are noticed immediately.
- v23.GetNamespace(clientCtx).CacheCtl(naming.DisableCache(true))
+ clientNs.CacheCtl(naming.DisableCache(true))
// Intermediate mounttables should be authenticated.
mt := runMT(t, mtCtx, "mt")
defer func() {
mt.server.Stop()
}()
+
// Mount a server on "mt".
- if err := mount("mt/server", serverEndpoint, time.Minute, naming.ReplaceMount(true)); err != nil {
+ if err := serverNs.Mount(serverCtx, "mt/server", serverEndpoint, time.Minute, naming.ReplaceMount(true)); err != nil {
t.Error(err)
}
+
// The namespace root should be authenticated too
- if e, err := resolve("mt/server"); err != nil {
- t.Errorf("Got (%v, %v)", e, err)
- } else {
- // Host:Port and Endpoint versions of the other namespace root
- // (which has different blessings)
- hproot := fmt.Sprintf("(otherroot)@%v", rootmt.endpoint.Addr())
- eproot := naming.FormatEndpoint(rootmt.endpoint.Addr().Network(), rootmt.endpoint.Addr().String(), rootmt.endpoint.RoutingID(), naming.BlessingOpt("otherroot"), naming.ServesMountTable(rootmt.endpoint.ServesMountTable()))
- for _, root := range []string{hproot, eproot} {
- name := naming.JoinAddressName(root, "mt")
- // Rooted name resolutions should fail authorization because of the "otherrot"
- if e, err := resolve(name); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
- t.Errorf("resolve(%q) returned (%v, errorid=%v %v), wanted errorid=%v", name, e, verror.ErrorID(err), err, verror.ErrNotTrusted.ID)
- }
- // But not fail if the skip-authorization option is provided
- if e, err := resolve(name, options.SkipServerEndpointAuthorization{}); err != nil {
- t.Errorf("resolve(%q): Got (%v, %v), expected resolution to succeed", name, e, err)
- }
- // The namespace root from the context should be authorized as well.
- ctx, ns, _ := v23.WithNewNamespace(clientCtx, naming.JoinAddressName(root, ""))
- if e, err := ns.Resolve(ctx, "mt/server"); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
- t.Errorf("resolve with root=%q returned (%v, errorid=%v %v), wanted errorid=%v: %s", root, e, verror.ErrorID(err), err, verror.ErrNotTrusted.ID, verror.DebugString(err))
- }
- if _, err := ns.Resolve(ctx, "mt/server", options.SkipServerEndpointAuthorization{}); err != nil {
- t.Errorf("resolve with root=%q should have succeeded when authorization checks are skipped. Got %v: %s", root, err, verror.DebugString(err))
- }
+ resolveWithRetry(clientCtx, "mt/server")
+ // Host:Port and Endpoint versions of the other namespace root
+ // (which has different blessings)
+ hproot := fmt.Sprintf("(otherroot)@%v", rootmt.endpoint.Addr())
+ eproot := naming.FormatEndpoint(rootmt.endpoint.Addr().Network(), rootmt.endpoint.Addr().String(), rootmt.endpoint.RoutingID(), naming.BlessingOpt("otherroot"), naming.ServesMountTable(rootmt.endpoint.ServesMountTable()))
+ for _, root := range []string{hproot, eproot} {
+ name := naming.JoinAddressName(root, "mt")
+ // Rooted name resolutions should fail authorization because of the "otherrot"
+ if e, err := clientNs.Resolve(clientCtx, name); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
+ t.Errorf("resolve(%q) returned (%v, errorid=%v %v), wanted errorid=%v", name, e, verror.ErrorID(err), err, verror.ErrNotTrusted.ID)
+ }
+ // But not fail if the skip-authorization option is provided
+ if e, err := clientNs.Resolve(clientCtx, name, options.SkipServerEndpointAuthorization{}); err != nil {
+ t.Errorf("resolve(%q): Got (%v, %v), expected resolution to succeed", name, e, err)
+ }
+
+ // The namespace root from the context should be authorized as well.
+ ctx, ns, _ := v23.WithNewNamespace(clientCtx, naming.JoinAddressName(root, ""))
+ if e, err := ns.Resolve(ctx, "mt/server"); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
+ t.Errorf("resolve with root=%q returned (%v, errorid=%v %v), wanted errorid=%v: %s", root, e, verror.ErrorID(err), err, verror.ErrNotTrusted.ID, verror.DebugString(err))
+ }
+ if _, err := ns.Resolve(ctx, "mt/server", options.SkipServerEndpointAuthorization{}); err != nil {
+ t.Errorf("resolve with root=%q should have succeeded when authorization checks are skipped. Got %v: %s", root, err, verror.DebugString(err))
}
}
+
// Imagine that the network address of "mt" has been taken over by an
// attacker. However, this attacker cannot mess with the mount entry
// for "mt". This would result in "mt" and its mount entry (in the
@@ -717,9 +726,9 @@
t.Error(err)
}
- if e, err := resolve("mt/server", options.SkipServerEndpointAuthorization{}); err != nil {
+ if e, err := clientNs.Resolve(serverCtx, "mt/server", options.SkipServerEndpointAuthorization{}); err != nil {
t.Errorf("Resolve should succeed when skipping server authorization. Got (%v, %v) %s", e, err, verror.DebugString(err))
- } else if e, err := resolve("mt/server"); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
+ } else if e, err := clientNs.Resolve(serverCtx, "mt/server"); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
t.Errorf("Resolve should have failed with %q because an attacker has taken over the intermediate mounttable. Got (%+v, errorid=%q:%v)", verror.ErrNotTrusted.ID, e, verror.ErrorID(err), err)
}
}
@@ -784,10 +793,7 @@
}
defer server.Stop()
- mountEntry, err := ns.Resolve(ctx, "leaf")
- if err != nil {
- boom(t, "ns.Resolve failed: %v", err)
- }
+ mountEntry := resolveWithRetry(ctx, "leaf")
if expected := true; mountEntry.IsLeaf != expected {
boom(t, "unexpected mountEntry.IsLeaf value. Got %v, expected %v", mountEntry.IsLeaf, expected)
}