blob: 2b4887d3f48c2568c5669b1ad0394225db459798 [file] [log] [blame]
package browspr
import (
"bytes"
"encoding/hex"
"encoding/json"
"strings"
"testing"
"veyron.io/veyron/veyron/profiles"
"veyron.io/veyron/veyron/runtimes/google/ipc/stream/proxy"
mounttable "veyron.io/veyron/veyron/services/mounttable/lib"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/options"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/vdl/vdlutil"
"veyron.io/veyron/veyron2/vom2"
"veyron.io/veyron/veyron2/wiretype"
"veyron.io/wspr/veyron/services/wsprd/app"
"veyron.io/wspr/veyron/services/wsprd/lib"
)
var (
r = rt.Init()
)
func startProxy() (*proxy.Proxy, error) {
rid, err := naming.NewRoutingID()
if err != nil {
return nil, err
}
return proxy.New(rid, nil, "tcp", "127.0.0.1:0", "")
}
func startMounttable() (ipc.Server, naming.Endpoint, error) {
mt, err := mounttable.NewMountTable("")
if err != nil {
return nil, nil, err
}
s, err := r.NewServer(options.ServesMountTable(true))
if err != nil {
return nil, nil, err
}
endpoint, err := s.Listen(profiles.LocalListenSpec)
if err != nil {
return nil, nil, err
}
if err := s.ServeDispatcher("", mt); err != nil {
return nil, nil, err
}
return s, endpoint, nil
}
type mockServer struct{}
func (s mockServer) BasicCall(_ ipc.ServerCall, txt string) (string, error) {
return "[" + txt + "]", nil
}
func (s mockServer) Signature(call ipc.ServerCall) (ipc.ServiceSignature, error) {
result := ipc.ServiceSignature{Methods: make(map[string]ipc.MethodSignature)}
result.Methods["BasicCall"] = ipc.MethodSignature{
InArgs: []ipc.MethodArgument{
{Name: "Txt", Type: 3},
},
OutArgs: []ipc.MethodArgument{
{Name: "Value", Type: 3},
{Name: "Err", Type: 65},
},
}
result.TypeDefs = []vdlutil.Any{
wiretype.NamedPrimitiveType{Type: 0x1, Name: "error", Tags: []string(nil)}}
return result, nil
}
func startMockServer(desiredName string) (ipc.Server, naming.Endpoint, error) {
// Create a new server instance.
s, err := r.NewServer()
if err != nil {
return nil, nil, err
}
endpoint, err := s.Listen(profiles.LocalListenSpec)
if err != nil {
return nil, nil, err
}
if err := s.ServeDispatcher(desiredName, ipc.LeafDispatcher(mockServer{}, nil)); err != nil {
return nil, nil, err
}
return s, endpoint, nil
}
type veyronTempRPC struct {
Name string
Method string
InArgs []json.RawMessage
NumOutArgs int32
IsStreaming bool
Timeout int64
}
func TestBrowspr(t *testing.T) {
proxy, err := startProxy()
if err != nil {
t.Fatalf("Failed to start proxy: %v", err)
}
defer proxy.Shutdown()
mtServer, mtEndpoint, err := startMounttable()
if err != nil {
t.Fatalf("Failed to start mounttable server: %v", err)
}
defer mtServer.Stop()
tcpNamespaceRoot := "/" + mtEndpoint.String()
if err := r.Namespace().SetRoots(tcpNamespaceRoot); err != nil {
t.Fatalf("Failed to set namespace roots: %v", err)
}
mockServerName := "mock/server"
mockServer, mockServerEndpoint, err := startMockServer(mockServerName)
if err != nil {
t.Fatalf("Failed to start mock server: %v", err)
}
defer mockServer.Stop()
names, err := mockServer.Published()
if err != nil {
t.Fatalf("Error fetching published names: %v", err)
}
if len(names) != 1 || names[0] != tcpNamespaceRoot+"/"+mockServerName {
t.Fatalf("Incorrectly mounted server. Names: %v", names)
}
mountEntry, err := r.Namespace().ResolveX(nil, mockServerName)
if err != nil {
t.Fatalf("Error fetching published names from mounttable: %v", err)
}
servers := []string{}
for _, s := range mountEntry.Servers {
if strings.Index(s.Server, "@tcp") != -1 {
servers = append(servers, s.Server)
}
}
if len(servers) != 1 || servers[0] != "/"+mockServerEndpoint.String() {
t.Fatalf("Incorrect names retrieved from mounttable: %v", mountEntry)
}
spec := profiles.LocalListenSpec
spec.Proxy = proxy.Endpoint().String()
receivedResponse := make(chan bool, 1)
var receivedInstanceId int32
var receivedType string
var receivedMsg string
var postMessageHandler = func(instanceId int32, ty, msg string) {
receivedInstanceId = instanceId
receivedType = ty
receivedMsg = msg
receivedResponse <- true
}
browspr := NewBrowspr(postMessageHandler, nil, spec, "/mock/identd", []string{tcpNamespaceRoot}, options.RuntimePrincipal{r.Principal()})
// browspr sets its namespace root to use the "ws" protocol, but we want to force "tcp" here.
browspr.namespaceRoots = []string{tcpNamespaceRoot}
principal := browspr.rt.Principal()
browspr.accountManager.SetMockBlesser(newMockBlesserService(principal))
msgInstanceId := int32(11)
rpcMessage := veyronTempRPC{
Name: mockServerName,
Method: "BasicCall",
InArgs: []json.RawMessage{
json.RawMessage([]byte("\"InputValue\"")),
},
NumOutArgs: 2,
IsStreaming: false,
Timeout: (1 << 31) - 1,
}
jsonRpcMessage, err := json.Marshal(rpcMessage)
if err != nil {
t.Fatalf("Failed to marshall rpc message to json: %v", err)
}
msg, err := json.Marshal(app.Message{
Id: 1,
Data: string(jsonRpcMessage),
Type: app.VeyronRequestMessage,
})
if err != nil {
t.Fatalf("Failed to marshall app message to json: %v", err)
}
err = browspr.HandleMessage(msgInstanceId, string(msg))
if err != nil {
t.Fatalf("Error while handling message: %v", err)
}
<-receivedResponse
if receivedInstanceId != msgInstanceId {
t.Errorf("Received unexpected instance id: %d. Expected: %d", receivedInstanceId, msgInstanceId)
}
if receivedType != "browsprMsg" {
t.Errorf("Received unexpected response type. Expected: %q, but got %q", "browsprMsg", receivedType)
}
var outMsg app.Message
if err := json.Unmarshal([]byte(receivedMsg), &outMsg); err != nil {
t.Fatalf("Failed to unmarshall outgoing message: %v", err)
}
if outMsg.Id != int64(1) {
t.Errorf("Id was %v, expected %v", outMsg.Id, int64(1))
}
if outMsg.Type != app.VeyronRequestMessage {
t.Errorf("Message type was %v, expected %v", outMsg.Type, app.MessageType(0))
}
var responseMsg app.Response
if err := json.Unmarshal([]byte(outMsg.Data), &responseMsg); err != nil {
t.Fatalf("Failed to unmarshall outgoing response: %v", err)
}
if responseMsg.Type != lib.ResponseFinal {
t.Errorf("Data was %q, expected %q", outMsg.Data, `["[InputValue]"]`)
}
var outArg string
var ok bool
if outArg, ok = responseMsg.Message.(string); !ok {
t.Errorf("Got unexpected response message body of type %T, expected type string", responseMsg.Message)
}
var result []string
arg, err := hex.DecodeString(outArg)
if err != nil {
t.Errorf("failed to hex decode string: %v", err)
}
decoder, err := vom2.NewDecoder(bytes.NewBuffer(arg))
if err != nil {
t.Fatalf("failed to construct new decoder: %v", err)
}
if err := decoder.Decode(&result); err != nil || result[0] != "[InputValue]" {
t.Errorf("got %s with err: %v, expected %s", result[0], err, "[InputValue]")
}
}
func TestWsNames(t *testing.T) {
testdata := map[string]string{
"/@2@tcp@127.0.0.1:46504@d7b41510a6e78033ed86e38efb61ef52@4@6@@": "/@2@ws@127.0.0.1:46504@d7b41510a6e78033ed86e38efb61ef52@4@6@@",
"/@2@tcp4@example.com:46504@d7b41510a6e78033ed86e38efb61ef52@4@6@@/more/stuff": "/@2@ws@example.com:46504@d7b41510a6e78033ed86e38efb61ef52@4@6@@/more/stuff",
"/@2@ws@example.com:46504@d7b41510a6e78033ed86e38efb61ef52@4@6@@/more/stuff": "/@2@ws@example.com:46504@d7b41510a6e78033ed86e38efb61ef52@4@6@@/more/stuff",
"/@2@tcp@[::]:60624@21ba0c2508adfe8507eb953e526bd5a2@4@6@@": "/@2@ws@[::]:60624@21ba0c2508adfe8507eb953e526bd5a2@4@6@@",
"/example.com:12345": "/@2@ws@example.com:12345@00000000000000000000000000000000@@@@",
"/example.com:12345/more/stuff/in/suffix": "/@2@ws@example.com:12345@00000000000000000000000000000000@@@@/more/stuff/in/suffix",
}
for name, expectedWsName := range testdata {
inputNames := []string{name}
actualWsNames, err := wsNames(inputNames)
if err != nil {
t.Fatal(err)
}
expectedWsNames := []string{expectedWsName}
if len(actualWsNames) != 1 || actualWsNames[0] != expectedWsNames[0] {
t.Errorf("expected wsNames(%v) to be %v but got %v", inputNames, expectedWsNames, actualWsNames)
}
}
}