blob: a50fc678eeb0c4d927ceed2f0288427d02c08696 [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 Simsa337af232015-02-27 14:36:46 -080017 "v.io/x/lib/vlog"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070018)
19
Matt Rosencrantz86ba1a12015-03-09 13:19:02 -070020type clientWithTimesCalled interface {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070021 rpc.Client
Bogdan Capritae96cd042015-02-03 17:32:57 -080022 TimesCalled(method string) int
23}
24
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070025// NewSimpleClient creates a new mocked rpc client where the given map of method name
Jiri Simsa5293dcb2014-05-10 09:56:38 -070026// to outputs is used for evaluating the method calls.
27// It also adds some testing features such as counters for number of times a method is called
Matt Rosencrantz86ba1a12015-03-09 13:19:02 -070028func newSimpleClient(methodsResults map[string][]interface{}) clientWithTimesCalled {
Bogdan Capritae96cd042015-02-03 17:32:57 -080029 return &simpleMockClient{
Jiri Simsa5293dcb2014-05-10 09:56:38 -070030 results: methodsResults,
31 timesCalled: make(map[string]int),
32 }
33}
34
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070035// simpleMockClient implements rpc.Client
Bogdan Capritae96cd042015-02-03 17:32:57 -080036type simpleMockClient struct {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070037 // Protects timesCalled
38 sync.Mutex
39
40 // results is a map of method names to results
41 results map[string][]interface{}
42 // timesCalled is a counter for number of times StartCall is called on a specific method name
43 timesCalled map[string]int
44}
45
46// TimesCalled returns number of times the given method has been called.
Bogdan Capritae96cd042015-02-03 17:32:57 -080047func (c *simpleMockClient) TimesCalled(method string) int {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070048 return c.timesCalled[method]
49}
50
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070051// StartCall Implements rpc.Client
52func (c *simpleMockClient) StartCall(ctx *context.T, name, method string, args []interface{}, opts ...rpc.CallOpt) (rpc.ClientCall, error) {
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -070053 defer vlog.LogCall()()
Jiri Simsa5293dcb2014-05-10 09:56:38 -070054 results, ok := c.results[method]
55 if !ok {
Suharsh Sivakumar076e9532015-04-09 17:36:25 -070056 return nil, fmt.Errorf("method %s not found", method)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070057 }
58
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -080059 // Copy the results so that they can be modified without effecting the original.
60 // This must be done via vom encode and decode rather than a direct deep copy because (among other reasons)
61 // reflect-based deep copy on vdl.Type objects will fail because of their private fields. This is not a problem with vom
62 // 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 -080063 vomBytes, err := vom.Encode(results)
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -080064 if err != nil {
65 panic(fmt.Sprintf("Error copying value with vom (failed on encode): %v", err))
66 }
67 var copiedResults []interface{}
Todd Wang3425a902015-01-21 18:43:59 -080068 if err := vom.Decode(vomBytes, &copiedResults); err != nil {
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -080069 panic(fmt.Sprintf("Error copying value with vom (failed on decode): %v", err))
70 }
71
Jiri Simsa5293dcb2014-05-10 09:56:38 -070072 clientCall := mockCall{
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -080073 results: copiedResults,
Jiri Simsa5293dcb2014-05-10 09:56:38 -070074 }
75
76 c.Lock()
77 c.timesCalled[method]++
78 c.Unlock()
79
80 return &clientCall, nil
81}
82
Suharsh Sivakumar076e9532015-04-09 17:36:25 -070083func (c *simpleMockClient) Call(ctx *context.T, name, method string, inArgs, outArgs []interface{}, callOpts ...rpc.CallOpt) error {
84 call, err := c.StartCall(ctx, name, method, inArgs, callOpts...)
85 if err != nil {
86 return err
87 }
88 return call.Finish(outArgs...)
89}
90
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070091// Close implements rpc.Client
Bogdan Capritae96cd042015-02-03 17:32:57 -080092func (*simpleMockClient) Close() {
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -070093 defer vlog.LogCall()()
Jiri Simsa5293dcb2014-05-10 09:56:38 -070094}
95
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070096// mockCall implements rpc.ClientCall
Jiri Simsa5293dcb2014-05-10 09:56:38 -070097type mockCall struct {
98 mockStream
99 results []interface{}
100}
101
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700102// Cancel implements rpc.ClientCall
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700103func (*mockCall) Cancel() {
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -0700104 defer vlog.LogCall()()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700105}
106
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700107// CloseSend implements rpc.ClientCall
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700108func (*mockCall) CloseSend() error {
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -0700109 defer vlog.LogCall()()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700110 return nil
111}
112
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700113// Finish implements rpc.ClientCall
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700114func (mc *mockCall) Finish(resultptrs ...interface{}) error {
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -0700115 defer vlog.LogCall()()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700116 if got, want := len(resultptrs), len(mc.results); got != want {
117 return errors.New(fmt.Sprintf("wrong number of output results; expected resultptrs of size %d but got %d", want, got))
118 }
119 for ax, res := range resultptrs {
120 if mc.results[ax] != nil {
Todd Wang52cd5322015-02-13 18:01:56 -0800121 if err := vdl.Convert(res, mc.results[ax]); err != nil {
Benjamin Prosnitz0db77a22015-01-20 14:25:15 -0800122 panic(fmt.Sprintf("Error converting out argument %#v: %v", mc.results[ax], err))
123 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700124 }
125 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700126 return nil
127}
128
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700129// RemoteBlessings implements rpc.ClientCall
Asim Shankar2d731a92014-09-29 17:46:38 -0700130func (*mockCall) RemoteBlessings() ([]string, security.Blessings) {
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800131 return []string{}, security.Blessings{}
Asim Shankar2d731a92014-09-29 17:46:38 -0700132}
133
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700134//mockStream implements rpc.Stream
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700135type mockStream struct{}
136
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700137//Send implements rpc.Stream
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700138func (*mockStream) Send(interface{}) error {
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -0700139 defer vlog.LogCall()()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700140 return nil
141}
142
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700143//Recv implements rpc.Stream
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700144func (*mockStream) Recv(interface{}) error {
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -0700145 defer vlog.LogCall()()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700146 return nil
147}