blob: a46fd826b3687d9c44b0b4e05c3990a04c31522a [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 Rosencrantz86ba1a12015-03-09 13:19:02 -07005package lib
Jiri Simsa5293dcb2014-05-10 09:56:38 -07006
7import (
8 "errors"
9 "fmt"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070010 "sync"
11
Jiri Simsa6ac95222015-02-23 16:11:49 -080012 "v.io/v23/context"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070013 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080014 "v.io/v23/security"
15 "v.io/v23/vdl"
Jiri Simsa6ac95222015-02-23 16:11:49 -080016 "v.io/v23/vom"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070017)
18
Matt Rosencrantz86ba1a12015-03-09 13:19:02 -070019type clientWithTimesCalled interface {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070020 rpc.Client
Bogdan Capritae96cd042015-02-03 17:32:57 -080021 TimesCalled(method string) int
22}
23
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070024// NewSimpleClient creates a new mocked rpc client where the given map of method name
Jiri Simsa5293dcb2014-05-10 09:56:38 -070025// to outputs is used for evaluating the method calls.
26// It also adds some testing features such as counters for number of times a method is called
Matt Rosencrantz86ba1a12015-03-09 13:19:02 -070027func newSimpleClient(methodsResults map[string][]interface{}) clientWithTimesCalled {
Bogdan Capritae96cd042015-02-03 17:32:57 -080028 return &simpleMockClient{
Jiri Simsa5293dcb2014-05-10 09:56:38 -070029 results: methodsResults,
30 timesCalled: make(map[string]int),
31 }
32}
33
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070034// simpleMockClient implements rpc.Client
Bogdan Capritae96cd042015-02-03 17:32:57 -080035type simpleMockClient struct {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070036 // Protects timesCalled
37 sync.Mutex
38
39 // results is a map of method names to results
40 results map[string][]interface{}
41 // timesCalled is a counter for number of times StartCall is called on a specific method name
42 timesCalled map[string]int
43}
44
45// TimesCalled returns number of times the given method has been called.
Bogdan Capritae96cd042015-02-03 17:32:57 -080046func (c *simpleMockClient) TimesCalled(method string) int {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070047 return c.timesCalled[method]
48}
49
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070050// StartCall Implements rpc.Client
51func (c *simpleMockClient) StartCall(ctx *context.T, name, method string, args []interface{}, opts ...rpc.CallOpt) (rpc.ClientCall, error) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070052 results, ok := c.results[method]
53 if !ok {
Suharsh Sivakumar076e9532015-04-09 17:36:25 -070054 return nil, fmt.Errorf("method %s not found", method)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070055 }
56
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -080057 // Copy the results so that they can be modified without effecting the original.
58 // This must be done via vom encode and decode rather than a direct deep copy because (among other reasons)
59 // reflect-based deep copy on vdl.Type objects will fail because of their private fields. This is not a problem with vom
60 // as it manually creates the type objects. It is also more realistic to use the same mechanism as the ultimate calls.
Todd Wang3425a902015-01-21 18:43:59 -080061 vomBytes, err := vom.Encode(results)
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -080062 if err != nil {
63 panic(fmt.Sprintf("Error copying value with vom (failed on encode): %v", err))
64 }
65 var copiedResults []interface{}
Todd Wang3425a902015-01-21 18:43:59 -080066 if err := vom.Decode(vomBytes, &copiedResults); err != nil {
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -080067 panic(fmt.Sprintf("Error copying value with vom (failed on decode): %v", err))
68 }
69
Jiri Simsa5293dcb2014-05-10 09:56:38 -070070 clientCall := mockCall{
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -080071 results: copiedResults,
Jiri Simsa5293dcb2014-05-10 09:56:38 -070072 }
73
74 c.Lock()
75 c.timesCalled[method]++
76 c.Unlock()
77
78 return &clientCall, nil
79}
80
Suharsh Sivakumar076e9532015-04-09 17:36:25 -070081func (c *simpleMockClient) Call(ctx *context.T, name, method string, inArgs, outArgs []interface{}, callOpts ...rpc.CallOpt) error {
82 call, err := c.StartCall(ctx, name, method, inArgs, callOpts...)
83 if err != nil {
84 return err
85 }
86 return call.Finish(outArgs...)
87}
88
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070089// Close implements rpc.Client
Bogdan Capritae96cd042015-02-03 17:32:57 -080090func (*simpleMockClient) Close() {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070091}
92
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070093// mockCall implements rpc.ClientCall
Jiri Simsa5293dcb2014-05-10 09:56:38 -070094type mockCall struct {
95 mockStream
96 results []interface{}
97}
98
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070099// Cancel implements rpc.ClientCall
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700100func (*mockCall) Cancel() {
101}
102
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700103// CloseSend implements rpc.ClientCall
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700104func (*mockCall) CloseSend() error {
105 return nil
106}
107
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700108// Finish implements rpc.ClientCall
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700109func (mc *mockCall) Finish(resultptrs ...interface{}) error {
110 if got, want := len(resultptrs), len(mc.results); got != want {
111 return errors.New(fmt.Sprintf("wrong number of output results; expected resultptrs of size %d but got %d", want, got))
112 }
113 for ax, res := range resultptrs {
114 if mc.results[ax] != nil {
Todd Wang52cd5322015-02-13 18:01:56 -0800115 if err := vdl.Convert(res, mc.results[ax]); err != nil {
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -0800116 panic(fmt.Sprintf("Error converting out argument %#v: %v", mc.results[ax], err))
117 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700118 }
119 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700120 return nil
121}
122
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700123// RemoteBlessings implements rpc.ClientCall
Asim Shankar2d731a92014-09-29 17:46:38 -0700124func (*mockCall) RemoteBlessings() ([]string, security.Blessings) {
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800125 return []string{}, security.Blessings{}
Asim Shankar2d731a92014-09-29 17:46:38 -0700126}
127
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700128//mockStream implements rpc.Stream
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700129type mockStream struct{}
130
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700131//Send implements rpc.Stream
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700132func (*mockStream) Send(interface{}) error {
133 return nil
134}
135
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700136//Recv implements rpc.Stream
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700137func (*mockStream) Recv(interface{}) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700138 return nil
139}