blob: 567ec85a6d6edd4332ddf6e388678a37767bd5ca [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Jiri Simsa78b646f2014-10-08 10:23:05 -07005package app
6
7import (
Matt Rosencrantz786f7272015-02-11 15:18:07 -08008 "bytes"
Shyam Jayaraman251f9d32015-05-29 09:27:48 -07009 "encoding/base64"
Matt Rosencrantz786f7272015-02-11 15:18:07 -080010 "encoding/hex"
Jiri Simsa78b646f2014-10-08 10:23:05 -070011 "fmt"
12 "reflect"
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -080013 "sync"
Jiri Simsa78b646f2014-10-08 10:23:05 -070014 "testing"
15
Jiri Simsa1f1302c2015-02-23 16:18:34 -080016 "v.io/v23"
17 "v.io/v23/context"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080018 "v.io/v23/options"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070019 "v.io/v23/rpc"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080020 "v.io/v23/security"
21 "v.io/v23/vdl"
Todd Wangac9e1902015-02-25 01:58:01 -080022 "v.io/v23/vdlroot/signature"
Shyam Jayaraman7efedbe2015-03-05 12:57:18 -080023 vdltime "v.io/v23/vdlroot/time"
Jiri Simsa1f1302c2015-02-23 16:18:34 -080024 "v.io/v23/verror"
25 "v.io/v23/vom"
26 "v.io/v23/vtrace"
Todd Wangb3511492015-04-07 23:32:34 -070027 vsecurity "v.io/x/ref/lib/security"
Suharsh Sivakumardcc11d72015-05-11 12:19:20 -070028 "v.io/x/ref/runtime/factories/generic"
Todd Wang5987a942015-04-06 11:06:17 -070029 "v.io/x/ref/services/mounttable/mounttablelib"
Todd Wang5b77a342015-04-06 18:31:37 -070030 "v.io/x/ref/services/wspr/internal/lib"
31 "v.io/x/ref/services/wspr/internal/lib/testwriter"
32 "v.io/x/ref/services/wspr/internal/rpc/server"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070033 "v.io/x/ref/test"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070034 "v.io/x/ref/test/testutil"
Jiri Simsa78b646f2014-10-08 10:23:05 -070035)
36
Cosmos Nicolaou8c3faba2015-03-25 22:23:32 -070037//go:generate v23 test generate
38
Asim Shankar4a698282015-03-21 21:59:18 -070039var testPrincipal = testutil.NewPrincipal("test")
Ankure7889242014-10-20 18:37:29 -070040
41// newBlessedPrincipal returns a new principal that has a blessing from the
42// provided runtime's principal which is set on its BlessingStore such
43// that it is revealed to all clients and servers.
Matt Rosencrantz306d9902015-01-10 17:46:07 -080044func newBlessedPrincipal(ctx *context.T) security.Principal {
Jiri Simsa1f1302c2015-02-23 16:18:34 -080045 principal := v23.GetPrincipal(ctx)
Asim Shankar4a698282015-03-21 21:59:18 -070046 p := testutil.NewPrincipal()
Matt Rosencrantz306d9902015-01-10 17:46:07 -080047 b, err := principal.Bless(p.PublicKey(), principal.BlessingStore().Default(), "delegate", security.UnconstrainedUse())
Ankure7889242014-10-20 18:37:29 -070048 if err != nil {
49 panic(err)
50 }
Asim Shankar4a698282015-03-21 21:59:18 -070051 if err := vsecurity.SetDefaultBlessings(p, b); err != nil {
Ankure7889242014-10-20 18:37:29 -070052 panic(err)
53 }
Ankure7889242014-10-20 18:37:29 -070054 return p
55}
Jiri Simsa78b646f2014-10-08 10:23:05 -070056
57type simpleAdder struct{}
58
Todd Wang54feabe2015-04-15 23:38:26 -070059func (s simpleAdder) Add(_ *context.T, _ rpc.ServerCall, a, b int32) (int32, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -070060 return a + b, nil
61}
62
Todd Wang54feabe2015-04-15 23:38:26 -070063func (s simpleAdder) Divide(_ *context.T, _ rpc.ServerCall, a, b int32) (int32, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -070064 if b == 0 {
Jiri Simsa94f68d02015-02-17 10:22:08 -080065 return 0, verror.New(verror.ErrBadArg, nil, "div 0")
Jiri Simsa78b646f2014-10-08 10:23:05 -070066 }
67 return a / b, nil
68}
69
Todd Wang54feabe2015-04-15 23:38:26 -070070func (s simpleAdder) StreamingAdd(_ *context.T, call rpc.StreamServerCall) (int32, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -070071 total := int32(0)
72 var value int32
73 for err := call.Recv(&value); err == nil; err = call.Recv(&value) {
74 total += value
75 call.Send(total)
76 }
77 return total, nil
78}
79
Todd Wang72ef57b2015-01-08 10:23:21 -080080var simpleAddrSig = signature.Interface{
81 Doc: "The empty interface contains methods not attached to any interface.",
82 Methods: []signature.Method{
83 {
84 Name: "Add",
85 InArgs: []signature.Arg{{Type: vdl.Int32Type}, {Type: vdl.Int32Type}},
Benjamin Prosnitz518af1e2015-01-20 14:20:10 -080086 OutArgs: []signature.Arg{{Type: vdl.Int32Type}},
Todd Wang72ef57b2015-01-08 10:23:21 -080087 },
88 {
89 Name: "Divide",
90 InArgs: []signature.Arg{{Type: vdl.Int32Type}, {Type: vdl.Int32Type}},
Benjamin Prosnitz518af1e2015-01-20 14:20:10 -080091 OutArgs: []signature.Arg{{Type: vdl.Int32Type}},
Todd Wang72ef57b2015-01-08 10:23:21 -080092 },
93 {
94 Name: "StreamingAdd",
Benjamin Prosnitz518af1e2015-01-20 14:20:10 -080095 OutArgs: []signature.Arg{{Type: vdl.Int32Type}},
Todd Wang72ef57b2015-01-08 10:23:21 -080096 InStream: &signature.Arg{Type: vdl.AnyType},
97 OutStream: &signature.Arg{Type: vdl.AnyType},
Jiri Simsa78b646f2014-10-08 10:23:05 -070098 },
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -080099 },
Jiri Simsa78b646f2014-10-08 10:23:05 -0700100}
101
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700102func createWriterCreator(w lib.ClientWriter) func(id int32) lib.ClientWriter {
103 return func(int32) lib.ClientWriter {
104 return w
105 }
106}
Jiri Simsa78b646f2014-10-08 10:23:05 -0700107func TestGetGoServerSignature(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700108 ctx, shutdown := test.V23Init()
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800109 defer shutdown()
110
Matt Rosencrantz53ac5852015-09-04 15:14:54 -0700111 ctx, s, err := v23.WithNewServer(ctx, "", simpleAdder{}, nil)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700112 if err != nil {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700113 t.Fatalf("unable to start server: %v", err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700114 }
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700115 name := s.Status().Endpoints[0].Name()
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800116
Jiri Simsa1f1302c2015-02-23 16:18:34 -0800117 spec := v23.GetListenSpec(ctx)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700118 spec.Proxy = "mockVeyronProxyEP"
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700119 writer := &testwriter.Writer{}
120 controller, err := NewController(ctx, createWriterCreator(writer), &spec, nil, newBlessedPrincipal(ctx))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700121
122 if err != nil {
Ankure7889242014-10-20 18:37:29 -0700123 t.Fatalf("Failed to create controller: %v", err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700124 }
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700125 sig, err := controller.getSignature(ctx, name)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700126 if err != nil {
Ankure7889242014-10-20 18:37:29 -0700127 t.Fatalf("Failed to get signature: %v", err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700128 }
Todd Wang72ef57b2015-01-08 10:23:21 -0800129 if got, want := len(sig), 2; got != want {
130 t.Fatalf("got signature %#v len %d, want %d", sig, got, want)
131 }
132 if got, want := sig[0], simpleAddrSig; !reflect.DeepEqual(got, want) {
133 t.Errorf("got sig[0] %#v, want: %#v", got, want)
134 }
135 if got, want := sig[1].Name, "__Reserved"; got != want {
136 t.Errorf("got sig[1].Name %#v, want: %#v", got, want)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700137 }
138}
139
140type goServerTestCase struct {
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700141 expectedTypeStream []lib.Response
142 method string
143 inArgs []interface{}
144 numOutArgs int32
145 streamingInputs []interface{}
146 expectedStream []lib.Response
147 expectedError error
Jiri Simsa78b646f2014-10-08 10:23:05 -0700148}
149
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700150func runGoServerTestCase(t *testing.T, testCase goServerTestCase) {
Todd Wang60052d82015-05-22 15:00:10 -0700151 ctx, shutdown := test.V23Init()
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800152 defer shutdown()
153
Matt Rosencrantz53ac5852015-09-04 15:14:54 -0700154 ctx, s, err := v23.WithNewServer(ctx, "", simpleAdder{}, nil)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700155 if err != nil {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700156 t.Fatalf("unable to start server: %v", err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700157 }
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700158 name := s.Status().Endpoints[0].Name()
Cosmos Nicolaou408de0f2014-10-24 13:32:29 -0700159
Jiri Simsa1f1302c2015-02-23 16:18:34 -0800160 spec := v23.GetListenSpec(ctx)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700161 spec.Proxy = "mockVeyronProxyEP"
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700162 writer := testwriter.Writer{}
163 controller, err := NewController(ctx, createWriterCreator(&writer), &spec, nil, newBlessedPrincipal(ctx))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700164
165 if err != nil {
166 t.Errorf("unable to create controller: %v", err)
167 t.Fail()
168 return
169 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700170 var stream *outstandingStream
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700171 if len(testCase.streamingInputs) > 0 {
Benjamin Prosnitzae300202015-06-04 19:36:49 -0700172 stream = newStream(nil)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700173 controller.outstandingRequests[0] = &outstandingRequest{
174 stream: stream,
175 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700176 go func() {
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700177 for _, value := range testCase.streamingInputs {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700178 controller.SendOnStream(ctx, 0, lib.HexVomEncodeOrDie(value, nil), &writer)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700179 }
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700180 controller.CloseStream(ctx, 0)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700181 }()
182 }
183
Todd Wangbaf16842015-03-16 14:12:29 -0700184 request := RpcRequest{
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700185 Name: name,
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700186 Method: testCase.method,
187 NumInArgs: int32(len(testCase.inArgs)),
188 NumOutArgs: testCase.numOutArgs,
Jiri Simsa78b646f2014-10-08 10:23:05 -0700189 IsStreaming: stream != nil,
190 }
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700191 controller.sendVeyronRequest(ctx, 0, &request, testCase.inArgs, &writer, stream, vtrace.GetSpan(ctx))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700192
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700193 if err := testwriter.CheckResponses(&writer, testCase.expectedStream, testCase.expectedTypeStream, testCase.expectedError); err != nil {
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700194 t.Error(err)
195 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700196}
197
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700198type typeWriter struct {
199 resps []lib.Response
200}
201
202func (t *typeWriter) Write(p []byte) (int, error) {
203 t.resps = append(t.resps, lib.Response{
204 Type: lib.ResponseTypeMessage,
205 Message: base64.StdEncoding.EncodeToString(p),
206 })
207 return len(p), nil
208}
209
210func makeRPCResponse(outArgs ...*vdl.Value) (string, []lib.Response) {
211 writer := typeWriter{}
212 typeEncoder := vom.NewTypeEncoder(&writer)
213 var buf bytes.Buffer
214 encoder := vom.NewEncoderWithTypeEncoder(&buf, typeEncoder)
215 var output = RpcResponse{
Matt Rosencrantz8fa0ea12015-02-24 14:17:50 -0800216 OutArgs: outArgs,
217 TraceResponse: vtrace.Response{},
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700218 }
219 if err := encoder.Encode(output); err != nil {
220 panic(err)
221 }
222 return hex.EncodeToString(buf.Bytes()), writer.resps
Matt Rosencrantzac1e3a82015-02-12 16:04:28 -0800223}
224
Jiri Simsa78b646f2014-10-08 10:23:05 -0700225func TestCallingGoServer(t *testing.T) {
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700226 resp, typeMessages := makeRPCResponse(vdl.Int32Value(5))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700227 runGoServerTestCase(t, goServerTestCase{
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700228 expectedTypeStream: typeMessages,
229 method: "Add",
230 inArgs: []interface{}{2, 3},
231 numOutArgs: 1,
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800232 expectedStream: []lib.Response{
233 lib.Response{
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700234 Message: resp,
Jiri Simsa78b646f2014-10-08 10:23:05 -0700235 Type: lib.ResponseFinal,
236 },
237 },
238 })
239}
240
241func TestCallingGoServerWithError(t *testing.T) {
242 runGoServerTestCase(t, goServerTestCase{
243 method: "Divide",
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800244 inArgs: []interface{}{1, 0},
Benjamin Prosnitz518af1e2015-01-20 14:20:10 -0800245 numOutArgs: 1,
Jiri Simsa94f68d02015-02-17 10:22:08 -0800246 expectedError: verror.New(verror.ErrBadArg, nil, "div 0"),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700247 })
248}
249
250func TestCallingGoWithStreaming(t *testing.T) {
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700251 resp, typeMessages := makeRPCResponse(vdl.Int32Value(10))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700252 runGoServerTestCase(t, goServerTestCase{
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700253 expectedTypeStream: typeMessages,
254 method: "StreamingAdd",
255 streamingInputs: []interface{}{1, 2, 3, 4},
256 numOutArgs: 1,
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800257 expectedStream: []lib.Response{
258 lib.Response{
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700259 Message: lib.HexVomEncodeOrDie(int32(1), nil),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700260 Type: lib.ResponseStream,
261 },
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800262 lib.Response{
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700263 Message: lib.HexVomEncodeOrDie(int32(3), nil),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700264 Type: lib.ResponseStream,
265 },
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800266 lib.Response{
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700267 Message: lib.HexVomEncodeOrDie(int32(6), nil),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700268 Type: lib.ResponseStream,
269 },
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800270 lib.Response{
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700271 Message: lib.HexVomEncodeOrDie(int32(10), nil),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700272 Type: lib.ResponseStream,
273 },
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800274 lib.Response{
Jiri Simsa78b646f2014-10-08 10:23:05 -0700275 Message: nil,
276 Type: lib.ResponseStreamClose,
277 },
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800278 lib.Response{
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700279 Message: resp,
Jiri Simsa78b646f2014-10-08 10:23:05 -0700280 Type: lib.ResponseFinal,
281 },
282 },
283 })
284}
285
286type runningTest struct {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700287 controller *Controller
288 writer *testwriter.Writer
289 proxyShutdown func()
290 typeEncoder *vom.TypeEncoder
Jiri Simsa78b646f2014-10-08 10:23:05 -0700291}
292
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700293func makeRequest(typeEncoder *vom.TypeEncoder, rpc RpcRequest, args ...interface{}) (string, error) {
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800294 var buf bytes.Buffer
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700295 encoder := vom.NewEncoderWithTypeEncoder(&buf, typeEncoder)
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800296 if err := encoder.Encode(rpc); err != nil {
297 return "", err
298 }
299 for _, arg := range args {
300 if err := encoder.Encode(arg); err != nil {
301 return "", err
302 }
303 }
304 return hex.EncodeToString(buf.Bytes()), nil
305}
306
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700307type typeEncoderWriter struct {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700308 c *Controller
309 ctx *context.T
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700310}
311
312func (t *typeEncoderWriter) Write(p []byte) (int, error) {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700313 t.c.HandleTypeMessage(t.ctx, hex.EncodeToString(p))
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700314 return len(p), nil
315}
316
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800317func serveServer(ctx *context.T, writer lib.ClientWriter, setController func(*Controller)) (*runningTest, error) {
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700318 mt, err := mounttablelib.NewMountTableDispatcher(ctx, "", "", "mounttable")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700319 if err != nil {
320 return nil, fmt.Errorf("unable to start mounttable: %v", err)
321 }
Matt Rosencrantz53ac5852015-09-04 15:14:54 -0700322 ctx, s, err := v23.WithNewDispatchingServer(ctx, "", mt, options.ServesMountTable(true))
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700323 if err != nil {
324 return nil, fmt.Errorf("unable to start mounttable: %v", err)
325 }
326 mtName := s.Status().Endpoints[0].Name()
327
Nicolas Lacasseec7a6082015-05-13 18:17:17 -0700328 proxySpec := rpc.ListenSpec{
Suharsh Sivakumar6d1aad82015-09-04 11:09:05 -0700329 Addrs: rpc.ListenAddrs{{Protocol: "tcp", Address: "127.0.0.1:0"}},
Nicolas Lacasseec7a6082015-05-13 18:17:17 -0700330 }
Suharsh Sivakumar40e52e92015-05-11 15:37:00 -0700331 proxyShutdown, proxyEndpoint, err := generic.NewProxy(ctx, proxySpec, security.AllowEveryone())
Jiri Simsa78b646f2014-10-08 10:23:05 -0700332 if err != nil {
333 return nil, fmt.Errorf("unable to start proxy: %v", err)
334 }
335
Benjamin Prosnitz86d52282014-12-19 15:48:38 -0800336 writerCreator := func(int32) lib.ClientWriter {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800337 return writer
Jiri Simsa78b646f2014-10-08 10:23:05 -0700338 }
Jiri Simsa1f1302c2015-02-23 16:18:34 -0800339 spec := v23.GetListenSpec(ctx)
Matt Rosencrantz2b675f92015-03-05 12:52:50 -0800340 spec.Proxy = proxyEndpoint.Name()
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800341 controller, err := NewController(ctx, writerCreator, &spec, nil, testPrincipal)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700342 if err != nil {
343 return nil, err
344 }
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800345
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800346 if setController != nil {
347 setController(controller)
348 }
349
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700350 v23.GetNamespace(controller.Context()).SetRoots(mtName)
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700351 typeStream := &typeEncoderWriter{c: controller, ctx: controller.Context()}
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700352 typeEncoder := vom.NewTypeEncoder(typeStream)
353 req, err := makeRequest(typeEncoder, RpcRequest{
Matt Rosencrantz9d2170b2015-02-21 16:19:53 -0800354 Name: "__controller",
Ali Ghassemiddccf362015-09-14 10:53:58 -0700355 Method: "NewServer",
Ali Ghassemibac34032015-04-30 18:27:57 -0700356 NumInArgs: 3,
Matt Rosencrantz786f7272015-02-11 15:18:07 -0800357 NumOutArgs: 1,
Shyam Jayaraman7efedbe2015-03-05 12:57:18 -0800358 Deadline: vdltime.Deadline{},
Ali Ghassemibac34032015-04-30 18:27:57 -0700359 }, "adder", 0, []RpcServerOption{})
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700360
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800361 controller.HandleVeyronRequest(ctx, 0, req, writer)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700362
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800363 testWriter, _ := writer.(*testwriter.Writer)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700364 return &runningTest{
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700365 controller, testWriter, proxyShutdown,
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700366 typeEncoder,
Jiri Simsa78b646f2014-10-08 10:23:05 -0700367 }, nil
368}
369
Jiri Simsa78b646f2014-10-08 10:23:05 -0700370// A test case to simulate a Javascript server talking to the App. All the
371// responses from Javascript are mocked and sent back through the method calls.
372// All messages from the client are sent using a go client.
373type jsServerTestCase struct {
374 method string
375 inArgs []interface{}
376 // The set of streaming inputs from the client to the server.
377 // This is passed to the client, which then passes it to the app.
378 clientStream []interface{}
379 // The set of JSON streaming messages sent from Javascript to the
380 // app.
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800381 serverStream []interface{}
Jiri Simsa78b646f2014-10-08 10:23:05 -0700382 // The final response sent by the Javascript server to the
383 // app.
Todd Wang5ab03662015-02-19 21:03:01 -0800384 finalResponse *vdl.Value
Jiri Simsa78b646f2014-10-08 10:23:05 -0700385 // The final error sent by the Javascript server to the app.
Mike Burrowsa727df72015-02-04 17:26:46 -0800386 err error
Jiri Simsa78b646f2014-10-08 10:23:05 -0700387
388 // Whether or not the Javascript server has an authorizer or not.
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800389 // If it does have an authorizer, then err is sent back from the server
Jiri Simsa78b646f2014-10-08 10:23:05 -0700390 // to the app.
391 hasAuthorizer bool
Jiri Simsa78b646f2014-10-08 10:23:05 -0700392}
393
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700394func runJsServerTestCase(t *testing.T, testCase jsServerTestCase) {
Todd Wang60052d82015-05-22 15:00:10 -0700395 ctx, shutdown := test.V23Init()
Suharsh Sivakumar94d00662015-01-21 14:31:30 -0800396 defer shutdown()
397
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800398 vomClientStream := []string{}
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700399 for _, m := range testCase.clientStream {
Shyam Jayaraman3facd242015-05-29 11:20:59 -0700400 vomClientStream = append(vomClientStream, lib.HexVomEncodeOrDie(m, nil))
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800401 }
402 mock := &mockJSServer{
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800403 t: t,
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700404 method: testCase.method,
Todd Wang72ef57b2015-01-08 10:23:21 -0800405 serviceSignature: []signature.Interface{simpleAddrSig},
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800406 expectedClientStream: vomClientStream,
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700407 serverStream: testCase.serverStream,
408 hasAuthorizer: testCase.hasAuthorizer,
409 inArgs: testCase.inArgs,
410 finalResponse: testCase.finalResponse,
411 finalError: testCase.err,
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800412 controllerReady: sync.RWMutex{},
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700413 flowCount: 2,
414 typeReader: lib.NewTypeReader(),
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700415 ctx: ctx,
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800416 }
Shyam Jayaraman251f9d32015-05-29 09:27:48 -0700417 mock.typeDecoder = vom.NewTypeDecoder(mock.typeReader)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800418 rt, err := serveServer(ctx, mock, func(controller *Controller) {
419 mock.controller = controller
420 })
Shyam Jayaraman0062e272015-06-04 11:25:13 -0700421
422 mock.typeEncoder = rt.typeEncoder
Matt Rosencrantz2b675f92015-03-05 12:52:50 -0800423 defer rt.proxyShutdown()
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700424 defer rt.controller.Cleanup(ctx)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800425
426 if err != nil {
427 t.Fatalf("could not serve server %v", err)
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800428 }
429
Matt Rosencrantzc90eb7b2015-01-09 08:32:01 -0800430 // Get the client that is relevant to the controller so it talks
431 // to the right mounttable.
Jiri Simsa1f1302c2015-02-23 16:18:34 -0800432 client := v23.GetClient(rt.controller.Context())
Asim Shankar263c73b2015-03-19 18:31:26 -0700433 // And have the client recognize the server, otherwise it won't
434 // authorize calls to it.
435 v23.GetPrincipal(rt.controller.Context()).AddToRoots(v23.GetPrincipal(ctx).BlessingStore().Default())
Jiri Simsa78b646f2014-10-08 10:23:05 -0700436
437 if err != nil {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800438 t.Fatalf("unable to create client: %v", err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700439 }
440
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700441 call, err := client.StartCall(rt.controller.Context(), "adder/adder", testCase.method, testCase.inArgs)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700442 if err != nil {
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800443 t.Fatalf("failed to start call: %v", err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700444 }
445
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700446 for _, msg := range testCase.clientStream {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700447 if err := call.Send(msg); err != nil {
448 t.Errorf("unexpected error while sending %v: %v", msg, err)
449 }
450 }
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800451 if err := call.CloseSend(); err != nil {
452 t.Errorf("unexpected error on close: %v", err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700453 }
454
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700455 expectedStream := testCase.serverStream
Jiri Simsa78b646f2014-10-08 10:23:05 -0700456 for {
457 var data interface{}
458 if err := call.Recv(&data); err != nil {
459 break
460 }
461 if len(expectedStream) == 0 {
462 t.Errorf("unexpected stream value: %v", data)
463 continue
464 }
465 if !reflect.DeepEqual(data, expectedStream[0]) {
466 t.Errorf("unexpected stream value: got %v, expected %v", data, expectedStream[0])
467 }
468 expectedStream = expectedStream[1:]
469 }
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800470
Todd Wang5ab03662015-02-19 21:03:01 -0800471 var result *vdl.Value
Todd Wangf21e1552015-02-18 13:21:52 -0800472 err = call.Finish(&result)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700473
Todd Wang8fa38762015-03-25 14:04:59 -0700474 if verror.ErrorID(err) != verror.ErrorID(testCase.err) {
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700475 t.Errorf("unexpected err: got %#v, expected %#v", err, testCase.err)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800476 }
477
478 if err != nil {
479 return
Shyam Jayaramane56df9a2014-11-20 17:38:54 -0800480 }
Nicolas LaCassed7ab8a12015-02-03 11:46:29 -0800481
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700482 if got, want := result, testCase.finalResponse; !vdl.EqualValue(got, want) {
Todd Wang5ab03662015-02-19 21:03:01 -0800483 t.Errorf("unexected final response: got %v, want %v", got, want)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700484 }
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800485
486 // ensure there is only one server and then stop the server
487 if len(rt.controller.servers) != 1 {
488 t.Errorf("expected only one server but got: %d", len(rt.controller.servers))
489 return
490 }
491 for serverId := range rt.controller.servers {
Todd Wang54feabe2015-04-15 23:38:26 -0700492 rt.controller.Stop(nil, nil, serverId)
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800493 }
494
495 // ensure there is no more servers now
496 if len(rt.controller.servers) != 0 {
497 t.Errorf("expected no server after stopping the only one but got: %d", len(rt.controller.servers))
498 return
499 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700500}
501
502func TestSimpleJSServer(t *testing.T) {
503 runJsServerTestCase(t, jsServerTestCase{
504 method: "Add",
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800505 inArgs: []interface{}{int32(1), int32(2)},
Todd Wang5ab03662015-02-19 21:03:01 -0800506 finalResponse: vdl.Int32Value(3),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700507 })
508}
509
510func TestJSServerWithAuthorizer(t *testing.T) {
511 runJsServerTestCase(t, jsServerTestCase{
512 method: "Add",
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800513 inArgs: []interface{}{int32(1), int32(2)},
Todd Wang5ab03662015-02-19 21:03:01 -0800514 finalResponse: vdl.Int32Value(3),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700515 hasAuthorizer: true,
516 })
517}
518
519func TestJSServerWithError(t *testing.T) {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800520 err := verror.New(verror.ErrInternal, nil)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700521 runJsServerTestCase(t, jsServerTestCase{
Nicolas LaCassed7ab8a12015-02-03 11:46:29 -0800522 method: "Divide",
523 inArgs: []interface{}{int32(1), int32(0)},
524 err: err,
Jiri Simsa78b646f2014-10-08 10:23:05 -0700525 })
526}
527
528func TestJSServerWithAuthorizerAndAuthError(t *testing.T) {
Jiri Simsa94f68d02015-02-17 10:22:08 -0800529 err := verror.New(verror.ErrNoAccess, nil)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700530 runJsServerTestCase(t, jsServerTestCase{
531 method: "Add",
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800532 inArgs: []interface{}{int32(1), int32(2)},
Jiri Simsa78b646f2014-10-08 10:23:05 -0700533 hasAuthorizer: true,
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800534 finalResponse: vdl.Int32Value(3),
535 err: err,
Jiri Simsa78b646f2014-10-08 10:23:05 -0700536 })
537}
538func TestJSServerWihStreamingInputs(t *testing.T) {
539 runJsServerTestCase(t, jsServerTestCase{
540 method: "StreamingAdd",
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800541 clientStream: []interface{}{int32(3), int32(4)},
Todd Wang5ab03662015-02-19 21:03:01 -0800542 finalResponse: vdl.Int32Value(10),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700543 })
544}
545
546func TestJSServerWihStreamingOutputs(t *testing.T) {
547 runJsServerTestCase(t, jsServerTestCase{
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800548 method: "StreamingAdd",
549 serverStream: []interface{}{int32(3), int32(4)},
Todd Wang5ab03662015-02-19 21:03:01 -0800550 finalResponse: vdl.Int32Value(10),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700551 })
552}
553
554func TestJSServerWihStreamingInputsAndOutputs(t *testing.T) {
555 runJsServerTestCase(t, jsServerTestCase{
Benjamin Prosnitza2ac3b32014-12-12 11:40:31 -0800556 method: "StreamingAdd",
557 clientStream: []interface{}{int32(1), int32(2)},
558 serverStream: []interface{}{int32(3), int32(4)},
Todd Wang5ab03662015-02-19 21:03:01 -0800559 finalResponse: vdl.Int32Value(10),
Jiri Simsa78b646f2014-10-08 10:23:05 -0700560 })
561}
Nicolas LaCassed7ab8a12015-02-03 11:46:29 -0800562
563func TestJSServerWithWrongNumberOfArgs(t *testing.T) {
Todd Wangb63e9eb2015-02-10 19:57:39 -0800564 err := verror.New(server.ErrWrongNumberOfArgs, nil, "Add", 3, 2)
Nicolas LaCassed7ab8a12015-02-03 11:46:29 -0800565 runJsServerTestCase(t, jsServerTestCase{
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800566 method: "Add",
567 inArgs: []interface{}{int32(1), int32(2), int32(3)},
568 err: err,
Nicolas LaCassed7ab8a12015-02-03 11:46:29 -0800569 })
570}
571
572func TestJSServerWithMethodNotFound(t *testing.T) {
573 methodName := "UnknownMethod"
Todd Wangb63e9eb2015-02-10 19:57:39 -0800574 err := verror.New(server.ErrMethodNotFoundInSignature, nil, methodName)
Nicolas LaCassed7ab8a12015-02-03 11:46:29 -0800575 runJsServerTestCase(t, jsServerTestCase{
Benjamin Prosnitze8e2b9b2015-02-24 12:55:25 -0800576 method: methodName,
577 inArgs: []interface{}{int32(1), int32(2)},
578 err: err,
Nicolas LaCassed7ab8a12015-02-03 11:46:29 -0800579 })
580}