v23proxy: Add test for 0-in and out args

Change-Id: I86cc5c8c514df48e84c61fed2ff401e2e91c423c
diff --git a/go/src/v.io/x/mojo/proxy/clientproxy/clientproxy.go b/go/src/v.io/x/mojo/proxy/clientproxy/clientproxy.go
index 2cfd823..eb19c84 100644
--- a/go/src/v.io/x/mojo/proxy/clientproxy/clientproxy.go
+++ b/go/src/v.io/x/mojo/proxy/clientproxy/clientproxy.go
@@ -88,6 +88,16 @@
 
 	messageBytes := message.Payload
 
+	if methodSig.ResponseParams == nil {
+		// This may be complicated to support because of a race on the server side.
+		// When we send the no-response message through mojo we don't know when it has been received
+		// and we can close the pipe (one is opened per incoming message).
+
+		// Note that because the client expects no response, it will not receive the following
+		// error.
+		return fmt.Errorf("this error not received")
+	}
+
 	response, err := s.call(s.header.v23Name, methodName, messageBytes, methodSig.Parameters, methodSig.ResponseParams)
 	if err != nil {
 		return err
@@ -143,13 +153,6 @@
 	if err != nil {
 		return nil, err
 	}
-	var outVType *vdl.Type
-	if outParamsType != nil {
-		outVType, err = transcoder.MojomStructToVDLType(*outParamsType, s.header.desc)
-		if err != nil {
-			return nil, err
-		}
-	}
 
 	// Decode the vdl.Value from the mojom bytes and mojom type.
 	var inVdlValue *vdl.Value
@@ -167,7 +170,11 @@
 	// We know that the v23serverproxy will give us back a bunch of
 	// data in []interface{}. so we'll want to decode them into *vdl.Value.
 	s.ctx.Infof("%s %v", method, outParamsType)
-	outargs := make([]*vdl.Value, len(outParamsType.Fields))
+	var numParams int
+	if outParamsType != nil {
+		numParams = len(outParamsType.Fields)
+	}
+	outargs := make([]*vdl.Value, numParams)
 	outptrs := make([]interface{}, len(outargs))
 	for i := range outargs {
 		outptrs[i] = &outargs[i]
@@ -178,6 +185,15 @@
 		return nil, err
 	}
 
+	if outParamsType == nil {
+		return nil, nil
+	}
+
+	outVType, err := transcoder.MojomStructToVDLType(*outParamsType, s.header.desc)
+	if err != nil {
+		return nil, err
+	}
+
 	// Now convert the []interface{} into a *vdl.Value (struct).
 	outVdlValue := util.CombineVdlValueByMojomType(outargs, outVType)
 
diff --git a/go/src/v.io/x/mojo/proxy/serverproxy/serverproxy.go b/go/src/v.io/x/mojo/proxy/serverproxy/serverproxy.go
index f83b3f0..13ac37d 100644
--- a/go/src/v.io/x/mojo/proxy/serverproxy/serverproxy.go
+++ b/go/src/v.io/x/mojo/proxy/serverproxy/serverproxy.go
@@ -162,7 +162,7 @@
 }
 
 // A helper function that sends a remote message that expects a response.
-func (fs fakeService) callRemoteGeneric(ctx *context.T, message *bindings.Message) (outMessage *bindings.Message, err error) {
+func (fs fakeService) callRemoteWithResponse(ctx *context.T, message *bindings.Message) (outMessage *bindings.Message, err error) {
 	ctx.Infof("callRemoteGeneric: Send message along the router")
 
 	readResult := <-fs.router.AcceptWithResponse(message)
@@ -227,19 +227,10 @@
 
 	// A void function must have request id of 0, whereas one with response params
 	// should  have a unique request id.
-	var rqId uint64
-	var flag uint32
-	if mm.ResponseParams != nil {
-		rqId = fs.ids.Count()
-		flag = bindings.MessageExpectsResponseFlag
-	} else {
-		flag = bindings.MessageNoFlag
-	}
-
 	header := bindings.MessageHeader{
 		Type:      ordinal,
-		Flags:     flag,
-		RequestId: rqId,
+		Flags:     bindings.MessageExpectsResponseFlag,
+		RequestId: fs.ids.Count(),
 	}
 
 	// Now produce the *bindings.Message that we will send to the other side.
@@ -252,16 +243,8 @@
 		return nil, err
 	}
 
-	// Handle the 0 out-arg case first.
-	if mm.ResponseParams == nil {
-		if err = fs.router.Accept(message); err != nil {
-			return nil, err
-		}
-		return make([]*vdl.Value, 0), nil
-	}
-
 	// Otherwise, make a generic call with the message.
-	outMessage, err := fs.callRemoteGeneric(ctx, message)
+	outMessage, err := fs.callRemoteWithResponse(ctx, message)
 	if err != nil {
 		return nil, err
 	}
@@ -304,7 +287,7 @@
 }
 
 func (v23pd *dispatcher) Lookup(ctx *context.T, suffix string) (interface{}, security.Authorizer, error) {
-	ctx.Infof("Dispatcher: %s", suffix)
+	ctx.Infof("dispatcher.Lookup for suffix: %s", suffix)
 	return fakeService{
 		appctx: v23pd.appctx,
 		suffix: suffix,
diff --git a/go/src/v.io/x/mojo/tests/client/test_client.go b/go/src/v.io/x/mojo/tests/client/test_client.go
index 8b1e816..1909ad5 100644
--- a/go/src/v.io/x/mojo/tests/client/test_client.go
+++ b/go/src/v.io/x/mojo/tests/client/test_client.go
@@ -63,7 +63,6 @@
 }
 
 func TestReuseProxy(t *testing.T, ctx application.Context) {
-	fmt.Printf("in test reuse\n")
 	proxy := createProxy(ctx)
 	defer proxy.Close_Proxy()
 
@@ -74,12 +73,10 @@
 	if value != expected.SimpleResponseValue {
 		t.Errorf("expected %v, but got %v", expected.SimpleResponseValue, value)
 	}
-	fmt.Printf("about to call second f\n")
 	x, y, err := proxy.MultiArgs(expected.MultiArgsRequestA, expected.MultiArgsRequestB, expected.MultiArgsRequestC, expected.MultiArgsRequestD)
 	if err != nil {
 		t.Fatal(err)
 	}
-	fmt.Printf("called second f\n")
 	if !reflect.DeepEqual(x, expected.MultiArgsResponseX) {
 		t.Errorf("expected %v, but got %v", expected.MultiArgsResponseX, x)
 	}
@@ -88,6 +85,29 @@
 	}
 }
 
+// This test stores a value on the server (through a no-out args RPC)
+// and calls a no-in args RPC to retrieve the value and confirm
+// it matches the value originally sent.
+func TestNoOutArgs(t *testing.T, ctx application.Context) {
+	const msg = "message-for-no-return"
+
+	proxy := createProxy(ctx)
+	defer proxy.Close_Proxy()
+
+	err := proxy.NoOutArgsPut(msg)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	outMsg, err := proxy.FetchMsgFromNoOutArgsPut()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if outMsg != msg {
+		t.Errorf("expected %v, but got %v", msg, outMsg)
+	}
+}
+
 func createProxy(ctx application.Context) *end_to_end_test.V23ProxyTest_Proxy {
 	// Parse arguments. Note: May panic if not enough args are given.
 	remoteName := ctx.Args()[1]
@@ -119,7 +139,7 @@
 	log.Printf("TestClientDelegate.Initialize...")
 
 	tests := []func(*testing.T, application.Context){
-		TestSimple, TestMultiArgs, TestReuseProxy,
+		TestSimple, TestMultiArgs, TestReuseProxy, TestNoOutArgs,
 	}
 
 	matchAllTests := func(pat, str string) (bool, error) { return true, nil }
diff --git a/go/src/v.io/x/mojo/tests/server/test_server.go b/go/src/v.io/x/mojo/tests/server/test_server.go
index e8a7f1c..8fe8607 100644
--- a/go/src/v.io/x/mojo/tests/server/test_server.go
+++ b/go/src/v.io/x/mojo/tests/server/test_server.go
@@ -8,6 +8,7 @@
 	"fmt"
 	"log"
 	"reflect"
+	"time"
 
 	"mojo/public/go/application"
 	"mojo/public/go/bindings"
@@ -21,7 +22,15 @@
 //#include "mojo/public/c/system/types.h"
 import "C"
 
-type V23ProxyTestImpl struct{}
+const noReturnReceiveTimeout = 1 * time.Second
+
+type V23ProxyTestImpl struct {
+	noReturnMsgChan chan string
+}
+
+func NewV23ProxyTestImpl() *V23ProxyTestImpl {
+	return &V23ProxyTestImpl{noReturnMsgChan: make(chan string, 1)}
+}
 
 func (i *V23ProxyTestImpl) Simple(a int32) (value string, err error) {
 	if a != expected.SimpleRequestA {
@@ -46,21 +55,37 @@
 	return expected.MultiArgsResponseX, expected.MultiArgsResponseY, nil
 }
 
+func (i *V23ProxyTestImpl) NoOutArgsPut(storedMsg string) error {
+	i.noReturnMsgChan <- storedMsg
+	return nil
+}
+
+func (i *V23ProxyTestImpl) FetchMsgFromNoOutArgsPut() (string, error) {
+	select {
+	case msg := <-i.noReturnMsgChan:
+		return msg, nil
+	case <-time.After(noReturnReceiveTimeout):
+		return "", fmt.Errorf("timed out waiting for no return message")
+	}
+}
+
 type V23ProxyTestServerDelegate struct {
 	factory V23ProxyTestFactory
 }
 
 type V23ProxyTestFactory struct {
-	stubs []*bindings.Stub
+	stubs    []*bindings.Stub
+	testImpl *V23ProxyTestImpl
 }
 
 func (delegate *V23ProxyTestServerDelegate) Initialize(context application.Context) {
 	log.Printf("V23ProxyTestServerDelegate.Initialize...")
+	delegate.factory.testImpl = NewV23ProxyTestImpl()
 }
 
 func (factory *V23ProxyTestFactory) Create(request end_to_end_test.V23ProxyTest_Request) {
 	log.Printf("V23ProxyTestServer's V23ProxyTestFactory.Create...")
-	stub := end_to_end_test.NewV23ProxyTestStub(request, &V23ProxyTestImpl{}, bindings.GetAsyncWaiter())
+	stub := end_to_end_test.NewV23ProxyTestStub(request, factory.testImpl, bindings.GetAsyncWaiter())
 	factory.stubs = append(factory.stubs, stub)
 	go func() {
 		for {
diff --git a/mojom/mojom/tests/end_to_end_test.mojom b/mojom/mojom/tests/end_to_end_test.mojom
index 025c65b..c98db9f 100644
--- a/mojom/mojom/tests/end_to_end_test.mojom
+++ b/mojom/mojom/tests/end_to_end_test.mojom
@@ -19,4 +19,6 @@
 interface V23ProxyTest {
   Simple(int32 a) => (string value);
   MultiArgs(bool a, array<float> b, map<string, uint8> c, AStruct d) => (AUnion x, string y);
+  NoOutArgsPut(string storedMsg) => ();
+  FetchMsgFromNoOutArgsPut() => (string storedMsg);
 };