blob: b28c95f2d109f45c11be66f33725703ac33a19ff [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package tests
import (
"fmt"
"sync"
"testing"
"mojo/public/go/application"
"mojo/public/go/bindings"
"examples/echo/echo"
mojoApp "mojo/public/interfaces/application/application"
sp "mojo/public/interfaces/application/service_provider"
"mojo/public/interfaces/application/shell"
)
var urls = [2]string{"first.example.com", "second.example.com"}
func pairedURL(url string) string {
switch url {
case urls[0]:
return urls[1]
case urls[1]:
return urls[0]
default:
panic(fmt.Sprintf("unexpected URL %v", url))
}
}
func checkEcho(echoPointer echo.Echo_Pointer) {
echo := echo.NewEchoProxy(echoPointer, bindings.GetAsyncWaiter())
str := fmt.Sprintf("Hello, world")
response, err := echo.EchoString(&str)
if err != nil {
panic(err)
}
if *response != str {
panic(fmt.Sprintf("invalid response: want %v, got %v", str, *response))
}
echo.Close_Proxy()
}
type EchoImpl struct{}
func (echo *EchoImpl) EchoString(inValue *string) (outValue *string, err error) {
return inValue, nil
}
// EchoDelegate implements mojo application. In this test configuration we
// have two instances of this implementation that talk to each other.
type EchoDelegate struct {
Wg *sync.WaitGroup
localURL string
}
func (delegate *EchoDelegate) Create(request echo.Echo_Request) {
stub := echo.NewEchoStub(request, &EchoImpl{}, bindings.GetAsyncWaiter())
go func() {
if err := stub.ServeRequest(); err != nil {
panic(err)
}
stub.Close()
delegate.Wg.Done()
}()
}
// Initialize connects to other instance, providing and asking for echo service.
func (delegate *EchoDelegate) Initialize(ctx application.Context) {
if ctx.URL() != delegate.localURL {
panic(fmt.Sprintf("invalid URL: want %v, got %v", delegate.localURL, ctx.URL()))
}
if len(ctx.Args()) != 1 || ctx.Args()[0] != delegate.localURL {
panic(fmt.Sprintf("invalid args: want %v, got %v", []string{delegate.localURL}, ctx.Args()))
}
go func() {
echoRequest, echoPointer := echo.CreateMessagePipeForEcho()
conn := ctx.ConnectToApplication(pairedURL(delegate.localURL), &echo.Echo_ServiceFactory{delegate})
if conn.RequestorURL() != delegate.localURL {
panic(fmt.Sprintf("invalid requestor URL: want %v, got %v", delegate.localURL, conn.RequestorURL()))
}
if conn.ConnectionURL() != pairedURL(delegate.localURL) {
panic(fmt.Sprintf("invalid connection URL: want %v, got %v", pairedURL(delegate.localURL), conn.ConnectionURL()))
}
conn.ConnectToService(&echoRequest)
checkEcho(echoPointer)
}()
}
// AcceptConnection accepts incoming connection, providing and asking for echo
// service.
func (delegate *EchoDelegate) AcceptConnection(conn *application.Connection) {
if conn.RequestorURL() != pairedURL(delegate.localURL) {
panic(fmt.Sprintf("invalid requestor URL: want %v, got %v", pairedURL(delegate.localURL), conn.RequestorURL()))
}
if conn.ConnectionURL() != delegate.localURL {
panic(fmt.Sprintf("invalid connection URL: want %v, got %v", delegate.localURL, conn.ConnectionURL()))
}
echoRequest, echoPointer := echo.CreateMessagePipeForEcho()
conn.ProvideServices(&echo.Echo_ServiceFactory{delegate}).ConnectToService(&echoRequest)
checkEcho(echoPointer)
}
func (delegate *EchoDelegate) Quit() {}
// shellImpl forward connection from local EchoDelegate instance to remote.
type shellImpl struct {
remoteApp *mojoApp.Application_Proxy
localURL string
}
func (s *shellImpl) ConnectToApplication(URL string, services *sp.ServiceProvider_Request, exposedServices *sp.ServiceProvider_Pointer) error {
if URL != pairedURL(s.localURL) {
return fmt.Errorf("invalid URL: want %v, got %v", pairedURL(s.localURL), URL)
}
s.remoteApp.AcceptConnection(s.localURL, services, exposedServices, pairedURL(s.localURL))
return nil
}
func TestApplication(t *testing.T) {
var apps []*mojoApp.Application_Proxy
var responsesSent, appsTerminated sync.WaitGroup
// Create and run applications.
for i := 0; i < 2; i++ {
request, pointer := mojoApp.CreateMessagePipeForApplication()
apps = append(apps, mojoApp.NewApplicationProxy(pointer, bindings.GetAsyncWaiter()))
// Each app instance provides echo service once when it creates
// a connection and once other instance creates a connection.
responsesSent.Add(2)
appsTerminated.Add(1)
delegate := &EchoDelegate{&responsesSent, urls[i]}
go func() {
application.Run(delegate, request.PassMessagePipe().ReleaseNativeHandle())
appsTerminated.Done()
}()
}
// Provide a shell for each application.
for i := 0; i < 2; i++ {
shellRequest, shellPointer := shell.CreateMessagePipeForShell()
shellStub := shell.NewShellStub(shellRequest, &shellImpl{apps[i^1], urls[i]}, bindings.GetAsyncWaiter())
go func() {
if err := shellStub.ServeRequest(); err != nil {
panic(err)
}
shellStub.Close()
}()
apps[i].Initialize(shellPointer, &[]string{urls[i]}, urls[i])
}
// Wait and then close pipes.
responsesSent.Wait()
for i := 0; i < 2; i++ {
apps[i].RequestQuit()
}
appsTerminated.Wait()
for i := 0; i < 2; i++ {
apps[i].Close_Proxy()
}
}