// Invoke calls the mojom service based on the suffix and converts the mojom // results (a struct) to Vanadium results (a slice of *vom.RawBytes). // Note: The argptrs from Prepare are reused here. The vom bytes should have // been decoded into these argptrs, so there are actual values inside now. func (fs fakeService) Invoke(ctx *context.T, call rpc.StreamServerCall, method string, argptrs []interface{}) (results []interface{}, _ error) { // fs.suffix consists of the mojo url and the application/interface name. // The last part should be the name; everything else is the url. parts := strings.Split(fs.suffix, "/") mojourl := strings.Join(parts[:len(parts)-1], "/") // e.g., mojo:go_remote_echo_server. May be defined in a BUILD.gn file. mojoname := parts[len(parts)-1] // e.g., mojo::examples::RemoteEcho. Defined from the interface + module. // Create the generic message pipe. r is a bindings.InterfaceRequest, and // p is a bindings.InterfacePointer. r, p := bindings.CreateMessagePipeForMojoInterface() v := v23ServiceRequest{ request: r, name: mojoname, } // v is an application.ServiceRequest with mojoname // Connect to the mojourl. fs.appctx.ConnectToApplication(mojourl).ConnectToService(&v) // Then assign a new router the FakeService. // This will never conflict because each FakeService is only invoked once. fs.router = bindings.NewRouter(p.PassMessagePipe(), bindings.GetAsyncWaiter()) defer fs.Close_Proxy() ctx.Infof("Fake Service Invoke (Remote Signature: %q -- %q)", mojourl, mojoname) // Vanadium relies on type information, so we will retrieve that first. mojomInterface, desc, err := fs.callRemoteSignature(mojourl, mojoname) if err != nil { return nil, err } ctx.Infof("Fake Service Invoke Signature %v", mojomInterface) ctx.Infof("Fake Service Invoke (Remote Method: %v)", method) // With the type information, we can make the method call to the remote interface. methodResults, err := fs.callRemoteMethod(ctx, method, mojomInterface, desc, argptrs) if err != nil { ctx.Errorf("Method called failed: %v", err) return nil, err } ctx.Infof("Fake Service Invoke Results %v", methodResults) // Convert methodResult to results. results = make([]interface{}, len(methodResults)) for i := range methodResults { results[i] = &methodResults[i] } return results, nil }
func TestAccept(t *testing.T) { r, h0, h1 := core.CreateMessagePipe(nil) defer h1.Close() if r != system.MOJO_RESULT_OK { t.Fatalf("can't create a message pipe: %v", r) } router := bindings.NewRouter(h0, bindings.GetAsyncWaiter()) header := bindings.MessageHeader{0, 0, 0} if err := router.Accept(encodeMessage(header, &header)); err != nil { t.Fatal(err) } header = bindings.MessageHeader{0, bindings.MessageExpectsResponseFlag, 1} err := router.Accept(encodeMessage(header, &header)) expectError(t, "message header should have a zero request ID", err) router.Close() }
func TestAcceptWithResponseMultiple(t *testing.T) { r, h0, h1 := core.CreateMessagePipe(nil) defer h1.Close() if r != system.MOJO_RESULT_OK { t.Fatalf("can't create a message pipe: %v", r) } router := bindings.NewRouter(h0, bindings.GetAsyncWaiter()) var wg sync.WaitGroup wg.Add(numberOfRequests + 1) // Serve requests. go func() { for i := 0; i < numberOfRequests; i++ { c := make(chan bindings.WaitResponse, 1) bindings.GetAsyncWaiter().AsyncWait(h1, system.MOJO_HANDLE_SIGNAL_READABLE, c) r, bytes, handles := h1.ReadMessage(system.MOJO_READ_MESSAGE_FLAG_NONE) if r != system.MOJO_RESULT_OK { t.Fatalf("can't read from a message pipe: %v", r) } r = h1.WriteMessage(bytes, handles, system.MOJO_WRITE_MESSAGE_FLAG_NONE) if r != system.MOJO_RESULT_OK { t.Fatalf("can't write to a message pipe: %v", r) } } wg.Done() }() // Send concurrent requests. for i := 0; i < numberOfRequests; i++ { go func(i int) { header := bindings.MessageHeader{0, bindings.MessageExpectsResponseFlag, uint64(i + 1)} err := (<-router.AcceptWithResponse(encodeMessage(header, &header))).Error if err != nil { panic(err) } wg.Done() }(i) } wg.Wait() router.Close() }
func TestClose(t *testing.T) { r, h0, h1 := core.CreateMessagePipe(nil) defer h1.Close() if r != system.MOJO_RESULT_OK { t.Fatalf("can't create a message pipe: %v", r) } router := bindings.NewRouter(h0, bindings.GetAsyncWaiter()) var wg sync.WaitGroup wg.Add(numberOfRequests*2 + 1) // Send requests from the same go routine. for i := 0; i < numberOfRequests; i++ { header := bindings.MessageHeader{0, bindings.MessageExpectsResponseFlag, uint64(i + 1)} c := router.AcceptWithResponse(encodeMessage(header, &header)) go func() { if err := (<-c).Error; err == nil { panic("unexpected nil error") } wg.Done() }() } // Send requests from different go routines. for i := 0; i < numberOfRequests; i++ { go func(i int) { header := bindings.MessageHeader{0, bindings.MessageExpectsResponseFlag, uint64(i + 1)} err := (<-router.AcceptWithResponse(encodeMessage(header, &header))).Error if err == nil { panic("unexpected nil error") } wg.Done() }(i + numberOfRequests) } go func() { router.Close() wg.Done() }() wg.Wait() }