Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 1 | package ipc |
| 2 | |
| 3 | import ( |
| 4 | "errors" |
| 5 | "fmt" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 6 | "sync" |
| 7 | |
Jiri Simsa | 764efb7 | 2014-12-25 20:57:03 -0800 | [diff] [blame] | 8 | "v.io/core/veyron2/context" |
| 9 | "v.io/core/veyron2/ipc" |
| 10 | "v.io/core/veyron2/security" |
Benjamin Prosnitz | 0db77a2 | 2015-01-20 14:25:15 -0800 | [diff] [blame] | 11 | "v.io/core/veyron2/vdl/valconv" |
Jiri Simsa | 764efb7 | 2014-12-25 20:57:03 -0800 | [diff] [blame] | 12 | "v.io/core/veyron2/vlog" |
Todd Wang | 3425a90 | 2015-01-21 18:43:59 -0800 | [diff] [blame^] | 13 | "v.io/core/veyron2/vom" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 14 | ) |
| 15 | |
| 16 | // NewSimpleClient creates a new mocked ipc client where the given map of method name |
| 17 | // to outputs is used for evaluating the method calls. |
| 18 | // It also adds some testing features such as counters for number of times a method is called |
| 19 | func NewSimpleClient(methodsResults map[string][]interface{}) *SimpleMockClient { |
| 20 | return &SimpleMockClient{ |
| 21 | results: methodsResults, |
| 22 | timesCalled: make(map[string]int), |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | // SimpleMockClient implements ipc.Client |
| 27 | type SimpleMockClient struct { |
| 28 | // Protects timesCalled |
| 29 | sync.Mutex |
| 30 | |
| 31 | // results is a map of method names to results |
| 32 | results map[string][]interface{} |
| 33 | // timesCalled is a counter for number of times StartCall is called on a specific method name |
| 34 | timesCalled map[string]int |
| 35 | } |
| 36 | |
| 37 | // TimesCalled returns number of times the given method has been called. |
| 38 | func (c *SimpleMockClient) TimesCalled(method string) int { |
| 39 | return c.timesCalled[method] |
| 40 | } |
| 41 | |
| 42 | // IPCBindOpt Implements ipc.Client |
Mehrdad Afshari | cd9852b | 2014-09-26 11:07:35 -0700 | [diff] [blame] | 43 | func (c *SimpleMockClient) IPCBindOpt() { |
| 44 | //nologcall |
| 45 | } |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 46 | |
| 47 | // StartCall Implements ipc.Client |
Matt Rosencrantz | 4f8ac60 | 2014-12-29 14:42:48 -0800 | [diff] [blame] | 48 | func (c *SimpleMockClient) StartCall(ctx *context.T, name, method string, args []interface{}, opts ...ipc.CallOpt) (ipc.Call, error) { |
Mehrdad Afshari | cd9852b | 2014-09-26 11:07:35 -0700 | [diff] [blame] | 49 | defer vlog.LogCall()() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 50 | results, ok := c.results[method] |
| 51 | if !ok { |
| 52 | return nil, errors.New(fmt.Sprintf("method %s not found", method)) |
| 53 | } |
| 54 | |
Benjamin Prosnitz | 0db77a2 | 2015-01-20 14:25:15 -0800 | [diff] [blame] | 55 | // Copy the results so that they can be modified without effecting the original. |
| 56 | // This must be done via vom encode and decode rather than a direct deep copy because (among other reasons) |
| 57 | // reflect-based deep copy on vdl.Type objects will fail because of their private fields. This is not a problem with vom |
| 58 | // as it manually creates the type objects. It is also more realistic to use the same mechanism as the ultimate calls. |
Todd Wang | 3425a90 | 2015-01-21 18:43:59 -0800 | [diff] [blame^] | 59 | vomBytes, err := vom.Encode(results) |
Benjamin Prosnitz | 0db77a2 | 2015-01-20 14:25:15 -0800 | [diff] [blame] | 60 | if err != nil { |
| 61 | panic(fmt.Sprintf("Error copying value with vom (failed on encode): %v", err)) |
| 62 | } |
| 63 | var copiedResults []interface{} |
Todd Wang | 3425a90 | 2015-01-21 18:43:59 -0800 | [diff] [blame^] | 64 | if err := vom.Decode(vomBytes, &copiedResults); err != nil { |
Benjamin Prosnitz | 0db77a2 | 2015-01-20 14:25:15 -0800 | [diff] [blame] | 65 | panic(fmt.Sprintf("Error copying value with vom (failed on decode): %v", err)) |
| 66 | } |
| 67 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 68 | clientCall := mockCall{ |
Benjamin Prosnitz | 0db77a2 | 2015-01-20 14:25:15 -0800 | [diff] [blame] | 69 | results: copiedResults, |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 70 | } |
| 71 | |
| 72 | c.Lock() |
| 73 | c.timesCalled[method]++ |
| 74 | c.Unlock() |
| 75 | |
| 76 | return &clientCall, nil |
| 77 | } |
| 78 | |
Asim Shankar | 2d731a9 | 2014-09-29 17:46:38 -0700 | [diff] [blame] | 79 | // Close implements ipc.Client |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 80 | func (*SimpleMockClient) Close() { |
Mehrdad Afshari | cd9852b | 2014-09-26 11:07:35 -0700 | [diff] [blame] | 81 | defer vlog.LogCall()() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 82 | } |
| 83 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 84 | // mockCall implements ipc.Call |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 85 | type mockCall struct { |
| 86 | mockStream |
| 87 | results []interface{} |
| 88 | } |
| 89 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 90 | // Cancel implements ipc.Call |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 91 | func (*mockCall) Cancel() { |
Mehrdad Afshari | cd9852b | 2014-09-26 11:07:35 -0700 | [diff] [blame] | 92 | defer vlog.LogCall()() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 93 | } |
| 94 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 95 | // CloseSend implements ipc.Call |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 96 | func (*mockCall) CloseSend() error { |
Mehrdad Afshari | cd9852b | 2014-09-26 11:07:35 -0700 | [diff] [blame] | 97 | defer vlog.LogCall()() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 98 | return nil |
| 99 | } |
| 100 | |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 101 | // Finish implements ipc.Call |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 102 | func (mc *mockCall) Finish(resultptrs ...interface{}) error { |
Mehrdad Afshari | cd9852b | 2014-09-26 11:07:35 -0700 | [diff] [blame] | 103 | defer vlog.LogCall()() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 104 | if got, want := len(resultptrs), len(mc.results); got != want { |
| 105 | return errors.New(fmt.Sprintf("wrong number of output results; expected resultptrs of size %d but got %d", want, got)) |
| 106 | } |
| 107 | for ax, res := range resultptrs { |
| 108 | if mc.results[ax] != nil { |
Benjamin Prosnitz | 0db77a2 | 2015-01-20 14:25:15 -0800 | [diff] [blame] | 109 | if err := valconv.Convert(res, mc.results[ax]); err != nil { |
| 110 | panic(fmt.Sprintf("Error converting out argument %#v: %v", mc.results[ax], err)) |
| 111 | } |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 112 | } |
| 113 | } |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 114 | return nil |
| 115 | } |
| 116 | |
Asim Shankar | 2d731a9 | 2014-09-29 17:46:38 -0700 | [diff] [blame] | 117 | // RemoteBlessings implements ipc.Call |
| 118 | func (*mockCall) RemoteBlessings() ([]string, security.Blessings) { |
| 119 | return []string{}, nil |
| 120 | } |
| 121 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 122 | //mockStream implements ipc.Stream |
| 123 | type mockStream struct{} |
| 124 | |
| 125 | //Send implements ipc.Stream |
| 126 | func (*mockStream) Send(interface{}) error { |
Mehrdad Afshari | cd9852b | 2014-09-26 11:07:35 -0700 | [diff] [blame] | 127 | defer vlog.LogCall()() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 128 | return nil |
| 129 | } |
| 130 | |
| 131 | //Recv implements ipc.Stream |
| 132 | func (*mockStream) Recv(interface{}) error { |
Mehrdad Afshari | cd9852b | 2014-09-26 11:07:35 -0700 | [diff] [blame] | 133 | defer vlog.LogCall()() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 134 | return nil |
| 135 | } |