runtimes/google/ipc: cleanup error handling.
MultiPart: 1/2

Change-Id: I366b9cecc1b53d4a2ffc207e5ed52f7e7bf9c3e4
diff --git a/runtimes/google/ipc/cancel_test.go b/runtimes/google/ipc/cancel_test.go
index d5e2e01..2022ad7 100644
--- a/runtimes/google/ipc/cancel_test.go
+++ b/runtimes/google/ipc/cancel_test.go
@@ -21,13 +21,13 @@
 }
 
 type canceld struct {
-	sm        stream.Manager
-	ns        naming.Namespace
-	name      string
-	child     string
-	started   chan struct{}
-	cancelled chan struct{}
-	stop      func() error
+	sm       stream.Manager
+	ns       naming.Namespace
+	name     string
+	child    string
+	started  chan struct{}
+	canceled chan struct{}
+	stop     func() error
 }
 
 func (c *canceld) Run(ctx ipc.ServerCall) error {
@@ -48,8 +48,8 @@
 
 	vlog.Info(c.name, " waiting for cancellation")
 	<-ctx.Context().Done()
-	vlog.Info(c.name, " cancelled")
-	close(c.cancelled)
+	vlog.Info(c.name, " canceled")
+	close(c.canceled)
 	return nil
 }
 
@@ -65,13 +65,13 @@
 	}
 
 	c := &canceld{
-		sm:        sm,
-		ns:        ns,
-		name:      name,
-		child:     child,
-		started:   make(chan struct{}, 0),
-		cancelled: make(chan struct{}, 0),
-		stop:      s.Stop,
+		sm:       sm,
+		ns:       ns,
+		name:     name,
+		child:    child,
+		started:  make(chan struct{}, 0),
+		canceled: make(chan struct{}, 0),
+		stop:     s.Stop,
 	}
 
 	if err := s.Serve(name, c, fakeAuthorizer(0)); err != nil {
@@ -116,7 +116,7 @@
 	vlog.Info("cancelling initial call")
 	cancel()
 
-	vlog.Info("waiting for children to be cancelled")
-	<-c1.cancelled
-	<-c2.cancelled
+	vlog.Info("waiting for children to be canceled")
+	<-c1.canceled
+	<-c2.canceled
 }
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 5f53bc8..a534864 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -53,7 +53,6 @@
 	errAuthError = verror.Register(pkgPath+".authError", verror.RetryRefetch, "authentication error from server {3}{:4}")
 
 	errSystemRetry = verror.Register(pkgPath+".sysErrorRetryConnection", verror.RetryConnection, "{:3:}")
-	errClosingFlow = verror.Register(pkgPath+".errClosingFlow", verror.NoRetry, "{:3:}")
 
 	errVomEncoder = verror.Register(pkgPath+".vomEncoder", verror.NoRetry, "failed to create vom encoder {:3}")
 	errVomDecoder = verror.Register(pkgPath+".vomDecoder", verror.NoRetry, "failed to create vom decoder {:3}")
@@ -315,7 +314,7 @@
 }
 
 // startCall ensures StartCall always returns verror.E.
-func (c *client) startCall(ctx *context.T, name, method string, args []interface{}, opts []ipc.CallOpt) (ipc.Call, verror.E) {
+func (c *client) startCall(ctx *context.T, name, method string, args []interface{}, opts []ipc.CallOpt) (ipc.Call, error) {
 	if !ctx.Initialized() {
 		return nil, verror.ExplicitMake(verror.BadArg, i18n.NoLangID, "ipc.Client", "StartCall")
 	}
@@ -334,7 +333,7 @@
 		deadline = time.Now().Add(time.Duration(r))
 	}
 
-	var lastErr verror.E
+	var lastErr error
 	for retries := 0; ; retries++ {
 		if retries != 0 {
 			if !backoff(retries, deadline) {
@@ -412,16 +411,19 @@
 // (all that serve "name"), but will invoke the method on at most one of them
 // (the server running on the most preferred protcol and network amongst all
 // the servers that were successfully connected to and authorized).
-func (c *client) tryCall(ctx *context.T, name, method string, args []interface{}, opts []ipc.CallOpt) (ipc.Call, verror.ActionCode, verror.E) {
+func (c *client) tryCall(ctx *context.T, name, method string, args []interface{}, opts []ipc.CallOpt) (ipc.Call, verror.ActionCode, error) {
 	var resolved *naming.MountEntry
 	var pattern security.BlessingPattern
 	var err error
 	if resolved, err = c.ns.Resolve(ctx, name, getResolveOpts(opts)...); err != nil {
 		vlog.Errorf("Resolve: %v", err)
+		// We always return NoServers as the error so that the caller knows
+		// that's ok to retry the operation since the name may be registered
+		// in the near future.
 		if verror.Is(err, naming.ErrNoSuchName.ID) {
 			return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
 		}
-		return nil, verror.NoRetry, verror.Make(verror.NoExist, ctx, name, err)
+		return nil, verror.NoRetry, verror.Make(verror.NoServers, ctx, name, err)
 	} else {
 		pattern = security.BlessingPattern(resolved.Pattern)
 		if len(resolved.Servers) == 0 {
@@ -731,14 +733,33 @@
 	return fc, nil
 }
 
-func (fc *flowClient) close(verr verror.E) verror.E {
-	if err := fc.flow.Close(); err != nil && verr == nil {
-		verr = verror.Make(errClosingFlow, fc.ctx, err)
+func (fc *flowClient) close(err error) error {
+	if cerr := fc.flow.Close(); cerr != nil && err == nil {
+		return verror.Make(verror.Internal, fc.ctx, err)
 	}
-	return verr
+	switch {
+	case verror.Is(err, verror.BadProtocol.ID):
+		switch fc.ctx.Err() {
+		case context.DeadlineExceeded:
+			// TODO(cnicolaou,m3b): reintroduce 'append' when the new verror API is done.
+			//return verror.Append(verror.Make(verror.Timeout, fc.ctx), verr)
+			return verror.Make(verror.Timeout, fc.ctx, err.Error())
+		case context.Canceled:
+			// TODO(cnicolaou,m3b): reintroduce 'append' when the new verror API is done.
+			//return verror.Append(verror.Make(verror.Canceled, fc.ctx), verr)
+			return verror.Make(verror.Canceled, fc.ctx, err.Error())
+		}
+	case verror.Is(err, verror.Timeout.ID):
+		// Canceled trumps timeout.
+		if fc.ctx.Err() == context.Canceled {
+			// TODO(cnicolaou,m3b): reintroduce 'append' when the new verror API is done.
+			return verror.Make(verror.Canceled, fc.ctx, err.Error())
+		}
+	}
+	return err
 }
 
-func (fc *flowClient) start(suffix, method string, args []interface{}, timeout time.Duration, blessings security.Blessings) verror.E {
+func (fc *flowClient) start(suffix, method string, args []interface{}, timeout time.Duration, blessings security.Blessings) error {
 	// Fetch any discharges for third-party caveats on the client's blessings
 	// if this client owns a discharge-client.
 	if self := fc.flow.LocalBlessings(); self != nil && fc.dc != nil {
@@ -800,10 +821,10 @@
 func decodeNetError(ctx *context.T, err error) verror.IDAction {
 	if neterr, ok := err.(net.Error); ok {
 		if neterr.Timeout() || neterr.Temporary() {
-			// If a read is cancelled in the lower levels we see
+			// If a read is canceled in the lower levels we see
 			// a timeout error - see readLocked in vc/reader.go
 			if ctx.Err() == context.Canceled {
-				return verror.Cancelled
+				return verror.Canceled
 			}
 			return verror.Timeout
 		}
@@ -888,7 +909,7 @@
 }
 
 // finish ensures Finish always returns verror.E.
-func (fc *flowClient) finish(resultptrs ...interface{}) verror.E {
+func (fc *flowClient) finish(resultptrs ...interface{}) error {
 	if fc.finished {
 		err := verror.Make(errClientFinishAlreadyCalled, fc.ctx)
 		return fc.close(verror.Make(verror.BadState, fc.ctx, err))
diff --git a/runtimes/google/ipc/client_test.go b/runtimes/google/ipc/client_test.go
index ad6eca7..b91f8c0 100644
--- a/runtimes/google/ipc/client_test.go
+++ b/runtimes/google/ipc/client_test.go
@@ -205,17 +205,10 @@
 	return eps[0].Name(), deferFn
 }
 
-func testForVerror(t *testing.T, err error, verr ...verror.IDAction) {
+func testForVerror(t *testing.T, err error, verr verror.IDAction) {
 	_, file, line, _ := runtime.Caller(1)
 	loc := fmt.Sprintf("%s:%d", filepath.Base(file), line)
-	found := false
-	for _, v := range verr {
-		if verror.Is(err, v.ID) {
-			found = true
-			break
-		}
-	}
-	if !found {
+	if !verror.Is(err, verr.ID) {
 		if _, ok := err.(verror.E); !ok {
 			t.Fatalf("%s: err %v not a verror", loc, err)
 		}
@@ -235,12 +228,11 @@
 	ctx, _ = context.WithTimeout(ctx, 100*time.Millisecond)
 	call, err := veyron2.GetClient(ctx).StartCall(ctx, name, "Sleep", nil)
 	if err != nil {
-		testForVerror(t, err, verror.Timeout, verror.BadProtocol)
+		testForVerror(t, err, verror.Timeout)
 		return
 	}
 	verr := call.Finish(&err)
-	// TODO(cnicolaou): this should be Timeout only.
-	testForVerror(t, verr, verror.Timeout, verror.BadProtocol)
+	testForVerror(t, verr, verror.Timeout)
 }
 
 func TestArgsAndResponses(t *testing.T) {
@@ -291,7 +283,7 @@
 	testForVerror(t, verr, verror.NoAccess)
 }
 
-func TestCancelledBeforeFinish(t *testing.T) {
+func TestCanceledBeforeFinish(t *testing.T) {
 	ctx, shutdown := newCtx()
 	defer shutdown()
 	name, fn := initServer(t, ctx)
@@ -305,11 +297,11 @@
 	// Cancel before we call finish.
 	cancel()
 	verr := call.Finish(&err)
-	// TOO(cnicolaou): this should be Cancelled only.
-	testForVerror(t, verr, verror.Cancelled, verror.BadProtocol)
+	// TOO(cnicolaou): this should be Canceled only.
+	testForVerror(t, verr, verror.Canceled)
 }
 
-func TestCancelledDuringFinish(t *testing.T) {
+func TestCanceledDuringFinish(t *testing.T) {
 	ctx, shutdown := newCtx()
 	defer shutdown()
 	name, fn := initServer(t, ctx)
@@ -326,8 +318,7 @@
 		cancel()
 	}()
 	verr := call.Finish(&err)
-	// TOO(cnicolaou): this should be Cancelled only.
-	testForVerror(t, verr, verror.Cancelled, verror.BadProtocol)
+	testForVerror(t, verr, verror.Canceled)
 }
 
 func TestRendezvous(t *testing.T) {
@@ -358,7 +349,7 @@
 	response := ""
 	verr := call.Finish(&response, &err)
 	if verr != nil {
-		testForVerror(t, verr, verror.Cancelled)
+		testForVerror(t, verr, verror.Canceled)
 		return
 	}
 	if got, want := response, "message: hello\n"; got != want {
@@ -395,8 +386,8 @@
 	ctx, _ = context.WithTimeout(ctx, 300*time.Millisecond)
 	call, err := veyron2.GetClient(ctx).StartCall(ctx, name, "Source", []interface{}{want})
 	if err != nil {
-		if !verror.Is(err, verror.Timeout.ID) && !verror.Is(err, verror.BadProtocol.ID) {
-			t.Fatalf("verror should be a timeout or badprotocol, not %s: stack %s",
+		if !verror.Is(err, verror.Timeout.ID) {
+			t.Fatalf("verror should be a timeout not %s: stack %s",
 				err, err.(verror.E).Stack())
 		}
 		return
@@ -413,11 +404,11 @@
 			continue
 		}
 		// TOO(cnicolaou): this should be Timeout only.
-		testForVerror(t, err, verror.Timeout, verror.BadProtocol)
+		testForVerror(t, err, verror.Timeout)
 		break
 	}
 	verr := call.Finish(&err)
-	testForVerror(t, verr, verror.Timeout, verror.BadProtocol)
+	testForVerror(t, verr, verror.Timeout)
 }
 
 func TestStreamAbort(t *testing.T) {
@@ -465,14 +456,14 @@
 	_, fn := runMountTable(t, ctx)
 	defer fn()
 	name := "noservers"
-	ctx, _ = context.WithTimeout(ctx, 300*time.Millisecond)
+	ctx, _ = context.WithTimeout(ctx, 1000*time.Millisecond)
 	call, verr := veyron2.GetClient(ctx).StartCall(ctx, name, "Sleep", nil)
 	if verr != nil {
-		testForVerror(t, verr, verror.Timeout, verror.BadProtocol, verror.NoExist)
+		testForVerror(t, verr, verror.NoServers)
 		return
 	}
 	err := call.Finish(&verr)
-	testForVerror(t, err, verror.Timeout, verror.BadProtocol, verror.NoExist)
+	testForVerror(t, err, verror.NoServers)
 }
 
 func TestNoMountTable(t *testing.T) {
diff --git a/services/mgmt/logreader/impl/reader.go b/services/mgmt/logreader/impl/reader.go
index e2cefb9..2d1908a 100644
--- a/services/mgmt/logreader/impl/reader.go
+++ b/services/mgmt/logreader/impl/reader.go
@@ -47,7 +47,7 @@
 		if f.ctx != nil {
 			select {
 			case <-f.ctx.Context().Done():
-				return 0, verror.Make(verror.Cancelled, nil)
+				return 0, verror.Make(verror.Canceled, nil)
 			default:
 			}
 		}