blob: f997fdaad5c93f64e5ab58841a064d12ee75b346 [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"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070024 "v.io/x/ref/test"
Todd Wang99b459d2015-04-02 12:32:09 -070025
Cosmos Nicolaouaa87e292015-04-21 22:15:50 -070026 _ "v.io/x/ref/profiles"
Matt Rosencrantzbca49812015-03-01 21:32:54 -080027)
28
29var generatedError = errors.New("generated error")
30
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070031func newServer(ctx *context.T) rpc.Server {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080032 s, err := v23.NewServer(ctx)
33 if err != nil {
34 panic(err)
35 }
36 return s
37}
38
39// serverArith implements the arith.Arith interface.
40type serverArith struct{}
41
Todd Wang54feabe2015-04-15 23:38:26 -070042func (*serverArith) Add(_ *context.T, _ rpc.ServerCall, A, B int32) (int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080043 return A + B, nil
44}
45
Todd Wang54feabe2015-04-15 23:38:26 -070046func (*serverArith) DivMod(_ *context.T, _ rpc.ServerCall, A, B int32) (int32, int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080047 return A / B, A % B, nil
48}
49
Todd Wang54feabe2015-04-15 23:38:26 -070050func (*serverArith) Sub(_ *context.T, _ rpc.ServerCall, args base.Args) (int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080051 return args.A - args.B, nil
52}
53
Todd Wang54feabe2015-04-15 23:38:26 -070054func (*serverArith) Mul(_ *context.T, _ rpc.ServerCall, nestedArgs base.NestedArgs) (int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080055 return nestedArgs.Args.A * nestedArgs.Args.B, nil
56}
57
Todd Wang54feabe2015-04-15 23:38:26 -070058func (*serverArith) Count(_ *context.T, call arith.ArithCountServerCall, start int32) error {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080059 const kNum = 1000
60 for i := int32(0); i < kNum; i++ {
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080061 if err := call.SendStream().Send(start + i); err != nil {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080062 return err
63 }
64 }
65 return nil
66}
67
Todd Wang54feabe2015-04-15 23:38:26 -070068func (*serverArith) StreamingAdd(_ *context.T, call arith.ArithStreamingAddServerCall) (int32, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080069 var total int32
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080070 for call.RecvStream().Advance() {
71 value := call.RecvStream().Value()
Matt Rosencrantzbca49812015-03-01 21:32:54 -080072 total += value
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080073 call.SendStream().Send(total)
Matt Rosencrantzbca49812015-03-01 21:32:54 -080074 }
Suharsh Sivakumar31f49852015-03-03 16:13:20 -080075 return total, call.RecvStream().Err()
Matt Rosencrantzbca49812015-03-01 21:32:54 -080076}
77
Todd Wang54feabe2015-04-15 23:38:26 -070078func (*serverArith) GenError(_ *context.T, _ rpc.ServerCall) error {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080079 return generatedError
80}
81
Todd Wang54feabe2015-04-15 23:38:26 -070082func (*serverArith) QuoteAny(_ *context.T, _ rpc.ServerCall, any *vdl.Value) (*vdl.Value, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080083 return vdl.StringValue(any.String()), nil
84}
85
86type serverCalculator struct {
87 serverArith
88}
89
Todd Wang54feabe2015-04-15 23:38:26 -070090func (*serverCalculator) Sine(_ *context.T, _ rpc.ServerCall, angle float64) (float64, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080091 return math.Sin(angle), nil
92}
93
Todd Wang54feabe2015-04-15 23:38:26 -070094func (*serverCalculator) Cosine(_ *context.T, _ rpc.ServerCall, angle float64) (float64, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080095 return math.Cos(angle), nil
96}
97
Todd Wang54feabe2015-04-15 23:38:26 -070098func (*serverCalculator) Exp(_ *context.T, _ rpc.ServerCall, x float64) (float64, error) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -080099 return math.Exp(x), nil
100}
101
Todd Wang54feabe2015-04-15 23:38:26 -0700102func (*serverCalculator) On(_ *context.T, _ rpc.ServerCall) error {
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800103 return nil
104}
105
Todd Wang54feabe2015-04-15 23:38:26 -0700106func (*serverCalculator) Off(_ *context.T, _ rpc.ServerCall) error {
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800107 return nil
108}
109
110func TestCalculator(t *testing.T) {
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -0700111 ctx, shutdown := test.InitForTest()
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800112 defer shutdown()
113
114 server := newServer(ctx)
115 eps, err := server.Listen(v23.GetListenSpec(ctx))
116 if err := server.Serve("", arith.CalculatorServer(&serverCalculator{}), nil); err != nil {
117 t.Fatal(err)
118 }
119 root := eps[0].Name()
120 // Synchronous calls
121 calculator := arith.CalculatorClient(root)
122 sine, err := calculator.Sine(ctx, 0)
123 if err != nil {
124 t.Errorf("Sine: got %q but expected no error", err)
125 }
126 if sine != 0 {
127 t.Errorf("Sine: expected 0 got %f", sine)
128 }
129 cosine, err := calculator.Cosine(ctx, 0)
130 if err != nil {
131 t.Errorf("Cosine: got %q but expected no error", err)
132 }
133 if cosine != 1 {
134 t.Errorf("Cosine: expected 1 got %f", cosine)
135 }
136
137 ar := arith.ArithClient(root)
138 sum, err := ar.Add(ctx, 7, 8)
139 if err != nil {
140 t.Errorf("Add: got %q but expected no error", err)
141 }
142 if sum != 15 {
143 t.Errorf("Add: expected 15 got %d", sum)
144 }
145 ar = calculator
146 sum, err = ar.Add(ctx, 7, 8)
147 if err != nil {
148 t.Errorf("Add: got %q but expected no error", err)
149 }
150 if sum != 15 {
151 t.Errorf("Add: expected 15 got %d", sum)
152 }
153
154 trig := arith.TrigonometryClient(root)
155 cosine, err = trig.Cosine(ctx, 0)
156 if err != nil {
157 t.Errorf("Cosine: got %q but expected no error", err)
158 }
159 if cosine != 1 {
160 t.Errorf("Cosine: expected 1 got %f", cosine)
161 }
162
163 // Test auto-generated methods.
164 serverStub := arith.CalculatorServer(&serverCalculator{})
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700165 expectDesc(t, serverStub.Describe__(), []rpc.InterfaceDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800166 {
167 Name: "Calculator",
168 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700169 Embeds: []rpc.EmbedDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800170 {
171 Name: "Arith",
172 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
173 },
174 {
175 Name: "AdvancedMath",
176 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
177 },
178 },
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700179 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800180 {Name: "On"},
181 {Name: "Off", Tags: []*vdl.Value{vdl.StringValue("offtag")}},
182 },
183 },
184 {
185 Name: "Arith",
186 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700187 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800188 {
189 Name: "Add",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700190 InArgs: []rpc.ArgDesc{{Name: "a"}, {Name: "b"}},
191 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800192 },
193 {
194 Name: "DivMod",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700195 InArgs: []rpc.ArgDesc{{Name: "a"}, {Name: "b"}},
196 OutArgs: []rpc.ArgDesc{{Name: "quot"}, {Name: "rem"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800197 },
198 {
199 Name: "Sub",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700200 InArgs: []rpc.ArgDesc{{Name: "args"}},
201 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800202 },
203 {
204 Name: "Mul",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700205 InArgs: []rpc.ArgDesc{{Name: "nested"}},
206 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800207 },
208 {
209 Name: "GenError",
210 Tags: []*vdl.Value{vdl.StringValue("foo"), vdl.StringValue("barz"), vdl.StringValue("hello"), vdl.Int32Value(129), vdl.Uint64Value(0x24)},
211 },
212 {
213 Name: "Count",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700214 InArgs: []rpc.ArgDesc{{Name: "start"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800215 },
216 {
217 Name: "StreamingAdd",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700218 OutArgs: []rpc.ArgDesc{{Name: "total"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800219 },
220 {
221 Name: "QuoteAny",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700222 InArgs: []rpc.ArgDesc{{Name: "a"}},
223 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800224 },
225 },
226 },
227 {
228 Name: "AdvancedMath",
229 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700230 Embeds: []rpc.EmbedDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800231 {
232 Name: "Trigonometry",
233 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
234 },
235 {
236 Name: "Exp",
237 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith/exp",
238 }},
239 },
240 {
241 Name: "Trigonometry",
242 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
243 Doc: "// Trigonometry is an interface that specifies a couple trigonometric functions.",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700244 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800245 {
246 Name: "Sine",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700247 InArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800248 {"angle", ``}, // float64
249 },
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700250 OutArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800251 {"", ``}, // float64
252 },
253 },
254 {
255 Name: "Cosine",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700256 InArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800257 {"angle", ``}, // float64
258 },
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700259 OutArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800260 {"", ``}, // float64
261 },
262 },
263 },
264 },
265 {
266 Name: "Exp",
267 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith/exp",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700268 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800269 {
270 Name: "Exp",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700271 InArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800272 {"x", ``}, // float64
273 },
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700274 OutArgs: []rpc.ArgDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800275 {"", ``}, // float64
276 },
277 },
278 },
279 },
280 })
281}
282
283func TestArith(t *testing.T) {
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -0700284 ctx, shutdown := test.InitForTest()
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800285 defer shutdown()
286
287 // TODO(bprosnitz) Split this test up -- it is quite long and hard to debug.
288
289 // We try a few types of dispatchers on the server side, to verify that
290 // anything dispatching to Arith or an interface embedding Arith (like
291 // Calculator) works for a client looking to talk to an Arith service.
292 objects := []interface{}{
293 arith.ArithServer(&serverArith{}),
294 arith.ArithServer(&serverCalculator{}),
295 arith.CalculatorServer(&serverCalculator{}),
296 }
297
298 for i, obj := range objects {
299 server := newServer(ctx)
300 defer server.Stop()
301 eps, err := server.Listen(v23.GetListenSpec(ctx))
302 if err != nil {
303 t.Fatal(err)
304 }
305 root := eps[0].Name()
306 if err := server.Serve("", obj, nil); err != nil {
307 t.Fatalf("%d: %v", i, err)
308 }
309 // Synchronous calls
310 ar := arith.ArithClient(root)
311 sum, err := ar.Add(ctx, 7, 8)
312 if err != nil {
313 t.Errorf("Add: got %q but expected no error", err)
314 }
315 if sum != 15 {
316 t.Errorf("Add: expected 15 got %d", sum)
317 }
318 q, r, err := ar.DivMod(ctx, 7, 3)
319 if err != nil {
320 t.Errorf("DivMod: got %q but expected no error", err)
321 }
322 if q != 2 || r != 1 {
323 t.Errorf("DivMod: expected (2,1) got (%d,%d)", q, r)
324 }
325 diff, err := ar.Sub(ctx, base.Args{7, 8})
326 if err != nil {
327 t.Errorf("Sub: got %q but expected no error", err)
328 }
329 if diff != -1 {
330 t.Errorf("Sub: got %d, expected -1", diff)
331 }
332 prod, err := ar.Mul(ctx, base.NestedArgs{base.Args{7, 8}})
333 if err != nil {
334 t.Errorf("Mul: got %q, but expected no error", err)
335 }
336 if prod != 56 {
337 t.Errorf("Sub: got %d, expected 56", prod)
338 }
339 stream, err := ar.Count(ctx, 35)
340 if err != nil {
341 t.Fatalf("error while executing Count %v", err)
342 }
343
344 countIterator := stream.RecvStream()
345 for i := int32(0); i < 1000; i++ {
346 if !countIterator.Advance() {
347 t.Errorf("Error getting value %v", countIterator.Err())
348 }
349 val := countIterator.Value()
350 if val != 35+i {
351 t.Errorf("Expected value %d, got %d", 35+i, val)
352 }
353 }
354 if countIterator.Advance() || countIterator.Err() != nil {
355 t.Errorf("Reply stream should have been closed %v", countIterator.Err())
356 }
357
358 if err := stream.Finish(); err != nil {
359 t.Errorf("Count failed with %v", err)
360 }
361
362 addStream, err := ar.StreamingAdd(ctx)
363
364 go func() {
365 sender := addStream.SendStream()
366 for i := int32(0); i < 100; i++ {
367 if err := sender.Send(i); err != nil {
368 t.Errorf("Send error %v", err)
369 }
370 }
371 if err := sender.Close(); err != nil {
372 t.Errorf("Close error %v", err)
373 }
374 }()
375
376 var expectedSum int32
377 rStream := addStream.RecvStream()
378 for i := int32(0); i < 100; i++ {
379 expectedSum += i
380 if !rStream.Advance() {
381 t.Errorf("Error getting value %v", rStream.Err())
382 }
383 value := rStream.Value()
384 if value != expectedSum {
385 t.Errorf("Got %d but expected %d", value, expectedSum)
386 }
387 }
388
389 if rStream.Advance() || rStream.Err() != nil {
390 t.Errorf("Reply stream should have been closed %v", rStream.Err())
391 }
392
393 total, err := addStream.Finish()
394
395 if err != nil {
396 t.Errorf("Count failed with %v", err)
397 }
398
399 if total != expectedSum {
400 t.Errorf("Got %d but expexted %d", total, expectedSum)
401 }
402
403 if err := ar.GenError(ctx); err == nil {
404 t.Errorf("GenError: got %v but expected %v", err, generatedError)
405 }
406
407 // Server-side stubs
408
409 serverStub := arith.ArithServer(&serverArith{})
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700410 expectDesc(t, serverStub.Describe__(), []rpc.InterfaceDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800411 {
412 Name: "Arith",
413 PkgPath: "v.io/x/ref/lib/vdl/testdata/arith",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700414 Methods: []rpc.MethodDesc{
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800415 {
416 Name: "Add",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700417 InArgs: []rpc.ArgDesc{{Name: "a"}, {Name: "b"}},
418 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800419 },
420 {
421 Name: "DivMod",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700422 InArgs: []rpc.ArgDesc{{Name: "a"}, {Name: "b"}},
423 OutArgs: []rpc.ArgDesc{{Name: "quot"}, {Name: "rem"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800424 },
425 {
426 Name: "Sub",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700427 InArgs: []rpc.ArgDesc{{Name: "args"}},
428 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800429 },
430 {
431 Name: "Mul",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700432 InArgs: []rpc.ArgDesc{{Name: "nested"}},
433 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800434 },
435 {
436 Name: "GenError",
437 Tags: []*vdl.Value{vdl.StringValue("foo"), vdl.StringValue("barz"), vdl.StringValue("hello"), vdl.Int32Value(129), vdl.Uint64Value(0x24)},
438 },
439 {
440 Name: "Count",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700441 InArgs: []rpc.ArgDesc{{Name: "start"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800442 },
443 {
444 Name: "StreamingAdd",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700445 OutArgs: []rpc.ArgDesc{{Name: "total"}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800446 },
447 {
448 Name: "QuoteAny",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700449 InArgs: []rpc.ArgDesc{{Name: "a"}},
450 OutArgs: []rpc.ArgDesc{{}},
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800451 },
452 },
453 },
454 })
455 }
456}
457
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700458func expectDesc(t *testing.T, got, want []rpc.InterfaceDesc) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800459 stripDesc(got)
460 stripDesc(want)
461 if !reflect.DeepEqual(got, want) {
462 t.Errorf("Describe__ got %#v, want %#v", got, want)
463 }
464}
465
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700466func stripDesc(desc []rpc.InterfaceDesc) {
Matt Rosencrantzbca49812015-03-01 21:32:54 -0800467 // Don't bother testing the documentation, to avoid spurious changes.
468 for i := range desc {
469 desc[i].Doc = ""
470 for j := range desc[i].Embeds {
471 desc[i].Embeds[j].Doc = ""
472 }
473 for j := range desc[i].Methods {
474 desc[i].Methods[j].Doc = ""
475 for k := range desc[i].Methods[j].InArgs {
476 desc[i].Methods[j].InArgs[k].Doc = ""
477 }
478 for k := range desc[i].Methods[j].OutArgs {
479 desc[i].Methods[j].OutArgs[k].Doc = ""
480 }
481 desc[i].Methods[j].InStream.Doc = ""
482 desc[i].Methods[j].OutStream.Doc = ""
483 }
484 }
485}