veyron/runtimes/google/ipc: Call CloseSend on Finish.
When the client calls Finish on a call, inform the server that no more inputs
will be sent. (tested by TestCloseSendOnFinish)
The client may still call CloseSend before calling Finish. (tested by TestRPC)
Change-Id: I993ec814343117a3738ee057c933ab49a6cf79cc
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index c2e0aa3..7f2b09c 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -289,6 +289,11 @@
}
func (fc *flowClient) CloseSend() error {
+ return fc.closeSend()
+}
+
+// closeSend ensures CloseSend always returns verror.E.
+func (fc *flowClient) closeSend() verror.E {
if fc.sendClosed {
return errFlowClosed
}
@@ -305,6 +310,14 @@
// finish ensures Finish always returns verror.E.
func (fc *flowClient) finish(resultptrs ...interface{}) verror.E {
+ // Inform the server that no more items will be sent, unless
+ // a) CloseSend has already done so.
+ // b) The flow was previously closed (e.g. due to an encoding error).
+ if !fc.sendClosed && !fc.flow.IsClosed() {
+ if err := fc.closeSend(); err != nil {
+ return err
+ }
+ }
// Decode the response header, if it hasn't already been decoded by Recv.
if fc.response.Error == nil && !fc.response.EndStreamResults {
if err := fc.dec.Decode(&fc.response); err != nil {
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index 4260de9..941f6bd 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -352,6 +352,16 @@
}
func TestRPC(t *testing.T) {
+ testRPC(t, true)
+}
+
+// TestCloseSendOnFinish tests that Finish informs the server that no more
+// inputs will be sent by the client if CloseSend has not already done so.
+func TestRPCCloseSendOnFinish(t *testing.T) {
+ testRPC(t, false)
+}
+
+func testRPC(t *testing.T, shouldCloseSend bool) {
type v []interface{}
type testcase struct {
name string
@@ -402,9 +412,11 @@
t.Errorf("%s call.Recv got value %v, want %v", name(test), u, sarg)
}
}
- vlog.VI(1).Infof("%s call.CloseSend", name(test))
- if err := call.CloseSend(); err != nil {
- t.Errorf(`%s call.CloseSend got unexpected error "%v"`, name(test), err)
+ if shouldCloseSend {
+ vlog.VI(1).Infof("%s call.CloseSend", name(test))
+ if err := call.CloseSend(); err != nil {
+ t.Errorf(`%s call.CloseSend got unexpected error "%v"`, name(test), err)
+ }
}
vlog.VI(1).Infof("%s client.Finish", name(test))
results := makeResultPtrs(test.results)