blob: 0c2600f65768f84f683daa2e0b65fd4b6fe37491 [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
Matt Rosencrantzbca49812015-03-01 21:32:54 -08005package main_test
6
Suharsh Sivakumar8646ba62015-03-18 15:22:28 -07007// This test assumes the vdl packages under v.io/x/ref/lib/vdl/testdata have been
Matt Rosencrantz94502cf2015-03-18 09:43:44 -07008// compiled using the vdl binary, and runs end-to-end rpc tests against the
Matt Rosencrantzbca49812015-03-01 21:32:54 -08009// generated output. It's meant as a final sanity check of the vdl compiler; by
10// using the compiled results we're behaving as an end-user would behave.
11
12import (
13 "errors"
14 "math"
15 "reflect"
16 "testing"
17
18 "v.io/v23"
19 "v.io/v23/context"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070020 "v.io/v23/rpc"
Matt Rosencrantzbca49812015-03-01 21:32:54 -080021 "v.io/v23/vdl"
22 "v.io/x/ref/lib/vdl/testdata/arith"
23 "v.io/x/ref/lib/vdl/testdata/base"
24
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070025 "v.io/x/ref/test"
Matt Rosencrantzbca49812015-03-01 21:32:54 -080026)
27
28var generatedError = errors.New("generated error")
29
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070030func newServer(ctx *context.T) rpc.Server {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080031 s, err := v23.NewServer(ctx)
32 if err != nil {
33 panic(err)
34 }
35 return s
36}
37
38// serverArith implements the arith.Arith interface.
39type serverArith struct{}
40
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070041func (*serverArith) Add(_ rpc.ServerCall, A, B int32) (int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080042 return A + B, nil
43}
44
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070045func (*serverArith) DivMod(_ rpc.ServerCall, A, B int32) (int32, int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080046 return A / B, A % B, nil
47}
48
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070049func (*serverArith) Sub(_ rpc.ServerCall, args base.Args) (int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080050 return args.A - args.B, nil
51}
52
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070053func (*serverArith) Mul(_ rpc.ServerCall, nestedArgs base.NestedArgs) (int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080054 return nestedArgs.Args.A * nestedArgs.Args.B, nil
55}
56
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080057func (*serverArith) Count(call arith.ArithCountServerCall, start int32) error {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080058 const kNum = 1000
59 for i := int32(0); i < kNum; i++ {
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080060 if err := call.SendStream().Send(start + i); err != nil {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080061 return err
62 }
63 }
64 return nil
65}
66
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080067func (*serverArith) StreamingAdd(call arith.ArithStreamingAddServerCall) (int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080068 var total int32
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080069 for call.RecvStream().Advance() {
70 value := call.RecvStream().Value()
Matt Rosencrantzbca49812015-03-01 21:32:54 -080071 total += value
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080072 call.SendStream().Send(total)
Matt Rosencrantzbca49812015-03-01 21:32:54 -080073 }
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080074 return total, call.RecvStream().Err()
Matt Rosencrantzbca49812015-03-01 21:32:54 -080075}
76
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070077func (*serverArith) GenError(_ rpc.ServerCall) error {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080078 return generatedError
79}
80
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070081func (*serverArith) QuoteAny(_ rpc.ServerCall, any *vdl.Value) (*vdl.Value, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080082 return vdl.StringValue(any.String()), nil
83}
84
85type serverCalculator struct {
86 serverArith
87}
88
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070089func (*serverCalculator) Sine(_ rpc.ServerCall, angle float64) (float64, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080090 return math.Sin(angle), nil
91}
92
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070093func (*serverCalculator) Cosine(_ rpc.ServerCall, angle float64) (float64, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080094 return math.Cos(angle), nil
95}
96
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070097func (*serverCalculator) Exp(_ rpc.ServerCall, x float64) (float64, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080098 return math.Exp(x), nil
99}
100
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700101func (*serverCalculator) On(_ rpc.ServerCall) error {
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800102 return nil
103}
104
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700105func (*serverCalculator) Off(_ rpc.ServerCall) error {
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800106 return nil
107}
108
109func TestCalculator(t *testing.T) {
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -0700110 ctx, shutdown := test.InitForTest()
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800111 defer shutdown()
112
113 server := newServer(ctx)
114 eps, err := server.Listen(v23.GetListenSpec(ctx))
115 if err := server.Serve("", arith.CalculatorServer(&serverCalculator{}), nil); err != nil {
116 t.Fatal(err)
117 }
118 root := eps[0].Name()
119 // Synchronous calls
120 calculator := arith.CalculatorClient(root)
121 sine, err := calculator.Sine(ctx, 0)
122 if err != nil {
123 t.Errorf("Sine: got %q but expected no error", err)
124 }
125 if sine != 0 {
126 t.Errorf("Sine: expected 0 got %f", sine)
127 }
128 cosine, err := calculator.Cosine(ctx, 0)
129 if err != nil {
130 t.Errorf("Cosine: got %q but expected no error", err)
131 }
132 if cosine != 1 {
133 t.Errorf("Cosine: expected 1 got %f", cosine)
134 }
135
136 ar := arith.ArithClient(root)
137 sum, err := ar.Add(ctx, 7, 8)
138 if err != nil {
139 t.Errorf("Add: got %q but expected no error", err)
140 }
141 if sum != 15 {
142 t.Errorf("Add: expected 15 got %d", sum)
143 }
144 ar = calculator
145 sum, err = ar.Add(ctx, 7, 8)
146 if err != nil {
147 t.Errorf("Add: got %q but expected no error", err)
148 }
149 if sum != 15 {
150 t.Errorf("Add: expected 15 got %d", sum)
151 }
152
153 trig := arith.TrigonometryClient(root)
154 cosine, err = trig.Cosine(ctx, 0)
155 if err != nil {
156 t.Errorf("Cosine: got %q but expected no error", err)
157 }
158 if cosine != 1 {
159 t.Errorf("Cosine: expected 1 got %f", cosine)
160 }
161
162 // Test auto-generated methods.
163 serverStub := arith.CalculatorServer(&serverCalculator{})
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700164 expectDesc(t, serverStub.Describe__(), []rpc.InterfaceDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800165 {
166 Name: "Calculator",
167 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700168 Embeds: []rpc.EmbedDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800169 {
170 Name: "Arith",
171 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
172 },
173 {
174 Name: "AdvancedMath",
175 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
176 },
177 },
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700178 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800179 {Name: "On"},
180 {Name: "Off", Tags: []*vdl.Value{vdl.StringValue("offtag")}},
181 },
182 },
183 {
184 Name: "Arith",
185 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700186 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800187 {
188 Name: "Add",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700189 InArgs: []rpc.ArgDesc{{Name: "a"}, {Name: "b"}},
190 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800191 },
192 {
193 Name: "DivMod",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700194 InArgs: []rpc.ArgDesc{{Name: "a"}, {Name: "b"}},
195 OutArgs: []rpc.ArgDesc{{Name: "quot"}, {Name: "rem"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800196 },
197 {
198 Name: "Sub",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700199 InArgs: []rpc.ArgDesc{{Name: "args"}},
200 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800201 },
202 {
203 Name: "Mul",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700204 InArgs: []rpc.ArgDesc{{Name: "nested"}},
205 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800206 },
207 {
208 Name: "GenError",
209 Tags: []*vdl.Value{vdl.StringValue("foo"), vdl.StringValue("barz"), vdl.StringValue("hello"), vdl.Int32Value(129), vdl.Uint64Value(0x24)},
210 },
211 {
212 Name: "Count",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700213 InArgs: []rpc.ArgDesc{{Name: "start"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800214 },
215 {
216 Name: "StreamingAdd",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700217 OutArgs: []rpc.ArgDesc{{Name: "total"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800218 },
219 {
220 Name: "QuoteAny",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700221 InArgs: []rpc.ArgDesc{{Name: "a"}},
222 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800223 },
224 },
225 },
226 {
227 Name: "AdvancedMath",
228 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700229 Embeds: []rpc.EmbedDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800230 {
231 Name: "Trigonometry",
232 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
233 },
234 {
235 Name: "Exp",
236 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith/exp",
237 }},
238 },
239 {
240 Name: "Trigonometry",
241 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
242 Doc: "// Trigonometry is an interface that specifies a couple trigonometric functions.",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700243 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800244 {
245 Name: "Sine",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700246 InArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800247 {"angle", ``}, // float64
248 },
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700249 OutArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800250 {"", ``}, // float64
251 },
252 },
253 {
254 Name: "Cosine",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700255 InArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800256 {"angle", ``}, // float64
257 },
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700258 OutArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800259 {"", ``}, // float64
260 },
261 },
262 },
263 },
264 {
265 Name: "Exp",
266 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith/exp",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700267 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800268 {
269 Name: "Exp",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700270 InArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800271 {"x", ``}, // float64
272 },
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700273 OutArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800274 {"", ``}, // float64
275 },
276 },
277 },
278 },
279 })
280}
281
282func TestArith(t *testing.T) {
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -0700283 ctx, shutdown := test.InitForTest()
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800284 defer shutdown()
285
286 // TODO(bprosnitz) Split this test up -- it is quite long and hard to debug.
287
288 // We try a few types of dispatchers on the server side, to verify that
289 // anything dispatching to Arith or an interface embedding Arith (like
290 // Calculator) works for a client looking to talk to an Arith service.
291 objects := []interface{}{
292 arith.ArithServer(&serverArith{}),
293 arith.ArithServer(&serverCalculator{}),
294 arith.CalculatorServer(&serverCalculator{}),
295 }
296
297 for i, obj := range objects {
298 server := newServer(ctx)
299 defer server.Stop()
300 eps, err := server.Listen(v23.GetListenSpec(ctx))
301 if err != nil {
302 t.Fatal(err)
303 }
304 root := eps[0].Name()
305 if err := server.Serve("", obj, nil); err != nil {
306 t.Fatalf("%d: %v", i, err)
307 }
308 // Synchronous calls
309 ar := arith.ArithClient(root)
310 sum, err := ar.Add(ctx, 7, 8)
311 if err != nil {
312 t.Errorf("Add: got %q but expected no error", err)
313 }
314 if sum != 15 {
315 t.Errorf("Add: expected 15 got %d", sum)
316 }
317 q, r, err := ar.DivMod(ctx, 7, 3)
318 if err != nil {
319 t.Errorf("DivMod: got %q but expected no error", err)
320 }
321 if q != 2 || r != 1 {
322 t.Errorf("DivMod: expected (2,1) got (%d,%d)", q, r)
323 }
324 diff, err := ar.Sub(ctx, base.Args{7, 8})
325 if err != nil {
326 t.Errorf("Sub: got %q but expected no error", err)
327 }
328 if diff != -1 {
329 t.Errorf("Sub: got %d, expected -1", diff)
330 }
331 prod, err := ar.Mul(ctx, base.NestedArgs{base.Args{7, 8}})
332 if err != nil {
333 t.Errorf("Mul: got %q, but expected no error", err)
334 }
335 if prod != 56 {
336 t.Errorf("Sub: got %d, expected 56", prod)
337 }
338 stream, err := ar.Count(ctx, 35)
339 if err != nil {
340 t.Fatalf("error while executing Count %v", err)
341 }
342
343 countIterator := stream.RecvStream()
344 for i := int32(0); i < 1000; i++ {
345 if !countIterator.Advance() {
346 t.Errorf("Error getting value %v", countIterator.Err())
347 }
348 val := countIterator.Value()
349 if val != 35+i {
350 t.Errorf("Expected value %d, got %d", 35+i, val)
351 }
352 }
353 if countIterator.Advance() || countIterator.Err() != nil {
354 t.Errorf("Reply stream should have been closed %v", countIterator.Err())
355 }
356
357 if err := stream.Finish(); err != nil {
358 t.Errorf("Count failed with %v", err)
359 }
360
361 addStream, err := ar.StreamingAdd(ctx)
362
363 go func() {
364 sender := addStream.SendStream()
365 for i := int32(0); i < 100; i++ {
366 if err := sender.Send(i); err != nil {
367 t.Errorf("Send error %v", err)
368 }
369 }
370 if err := sender.Close(); err != nil {
371 t.Errorf("Close error %v", err)
372 }
373 }()
374
375 var expectedSum int32
376 rStream := addStream.RecvStream()
377 for i := int32(0); i < 100; i++ {
378 expectedSum += i
379 if !rStream.Advance() {
380 t.Errorf("Error getting value %v", rStream.Err())
381 }
382 value := rStream.Value()
383 if value != expectedSum {
384 t.Errorf("Got %d but expected %d", value, expectedSum)
385 }
386 }
387
388 if rStream.Advance() || rStream.Err() != nil {
389 t.Errorf("Reply stream should have been closed %v", rStream.Err())
390 }
391
392 total, err := addStream.Finish()
393
394 if err != nil {
395 t.Errorf("Count failed with %v", err)
396 }
397
398 if total != expectedSum {
399 t.Errorf("Got %d but expexted %d", total, expectedSum)
400 }
401
402 if err := ar.GenError(ctx); err == nil {
403 t.Errorf("GenError: got %v but expected %v", err, generatedError)
404 }
405
406 // Server-side stubs
407
408 serverStub := arith.ArithServer(&serverArith{})
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700409 expectDesc(t, serverStub.Describe__(), []rpc.InterfaceDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800410 {
411 Name: "Arith",
412 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700413 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800414 {
415 Name: "Add",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700416 InArgs: []rpc.ArgDesc{{Name: "a"}, {Name: "b"}},
417 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800418 },
419 {
420 Name: "DivMod",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700421 InArgs: []rpc.ArgDesc{{Name: "a"}, {Name: "b"}},
422 OutArgs: []rpc.ArgDesc{{Name: "quot"}, {Name: "rem"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800423 },
424 {
425 Name: "Sub",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700426 InArgs: []rpc.ArgDesc{{Name: "args"}},
427 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800428 },
429 {
430 Name: "Mul",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700431 InArgs: []rpc.ArgDesc{{Name: "nested"}},
432 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800433 },
434 {
435 Name: "GenError",
436 Tags: []*vdl.Value{vdl.StringValue("foo"), vdl.StringValue("barz"), vdl.StringValue("hello"), vdl.Int32Value(129), vdl.Uint64Value(0x24)},
437 },
438 {
439 Name: "Count",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700440 InArgs: []rpc.ArgDesc{{Name: "start"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800441 },
442 {
443 Name: "StreamingAdd",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700444 OutArgs: []rpc.ArgDesc{{Name: "total"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800445 },
446 {
447 Name: "QuoteAny",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700448 InArgs: []rpc.ArgDesc{{Name: "a"}},
449 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800450 },
451 },
452 },
453 })
454 }
455}
456
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700457func expectDesc(t *testing.T, got, want []rpc.InterfaceDesc) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800458 stripDesc(got)
459 stripDesc(want)
460 if !reflect.DeepEqual(got, want) {
461 t.Errorf("Describe__ got %#v, want %#v", got, want)
462 }
463}
464
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700465func stripDesc(desc []rpc.InterfaceDesc) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800466 // Don't bother testing the documentation, to avoid spurious changes.
467 for i := range desc {
468 desc[i].Doc = ""
469 for j := range desc[i].Embeds {
470 desc[i].Embeds[j].Doc = ""
471 }
472 for j := range desc[i].Methods {
473 desc[i].Methods[j].Doc = ""
474 for k := range desc[i].Methods[j].InArgs {
475 desc[i].Methods[j].InArgs[k].Doc = ""
476 }
477 for k := range desc[i].Methods[j].OutArgs {
478 desc[i].Methods[j].OutArgs[k].Doc = ""
479 }
480 desc[i].Methods[j].InStream.Doc = ""
481 desc[i].Methods[j].OutStream.Doc = ""
482 }
483 }
484}