github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/api_mock.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 import ( 7 "errors" 8 "io" 9 "net/http" 10 11 "golang.org/x/net/context" 12 ) 13 14 type NullMockAPI struct{} 15 16 var _ API = (*NullMockAPI)(nil) 17 18 func (n *NullMockAPI) Get(MetaContext, APIArg) (*APIRes, error) { return nil, nil } 19 func (n *NullMockAPI) GetDecode(MetaContext, APIArg, APIResponseWrapper) error { return nil } 20 func (n *NullMockAPI) GetDecodeCtx(context.Context, APIArg, APIResponseWrapper) error { return nil } 21 func (n *NullMockAPI) GetResp(MetaContext, APIArg) (*http.Response, func(), error) { 22 return nil, noopFinisher, nil 23 } 24 func (n *NullMockAPI) Post(MetaContext, APIArg) (*APIRes, error) { return nil, nil } 25 func (n *NullMockAPI) PostJSON(MetaContext, APIArg) (*APIRes, error) { return nil, nil } 26 func (n *NullMockAPI) PostDecode(MetaContext, APIArg, APIResponseWrapper) error { return nil } 27 func (n *NullMockAPI) PostDecodeCtx(context.Context, APIArg, APIResponseWrapper) error { return nil } 28 func (n *NullMockAPI) PostRaw(MetaContext, APIArg, string, io.Reader) (*APIRes, error) { 29 return nil, nil 30 } 31 func (n *NullMockAPI) Delete(MetaContext, APIArg) (*APIRes, error) { return nil, nil } 32 33 type APIMethodType int 34 35 const ( 36 MethodGet APIMethodType = iota 37 MethodGetDecode 38 MethodGetDecodeCtx 39 MethodGetResp 40 MethodPost 41 MethodPostJSON 42 MethodPostDecode 43 MethodPostDecodeCtx 44 MethodPostRaw 45 MethodDelete 46 ) 47 48 type APIRecord struct { 49 Arg APIArg 50 Method APIMethodType 51 // various inputs and outputs of the API interface methods. 52 Res *APIRes 53 RespWrapper APIResponseWrapper 54 HTTPResp *http.Response 55 Func func() 56 S string 57 R io.Reader 58 Err error 59 } 60 61 // FilterAPIRecords returns only the records on which the filter function outputs true 62 func FilterAPIRecords(recs []APIRecord, filter func(*APIRecord) bool) (filtered []APIRecord) { 63 for _, rec := range recs { 64 if filter(&rec) { 65 filtered = append(filtered, rec) 66 } 67 } 68 return filtered 69 } 70 71 // APIArgRecorder forwards all its calls to the underlying API, but records all 72 // the inputs and outputs to be used in tests. 73 type APIArgRecorder struct { 74 API 75 Records []APIRecord 76 } 77 78 var _ API = (*APIArgRecorder)(nil) 79 80 func NewAPIArgRecorderWithNullAPI() *APIArgRecorder { 81 return NewAPIArgRecorder(&NullMockAPI{}) 82 } 83 84 func NewAPIArgRecorder(inner API) *APIArgRecorder { 85 return &APIArgRecorder{API: inner} 86 } 87 88 func (a *APIArgRecorder) Reset() { 89 a.Records = nil 90 } 91 92 func (a *APIArgRecorder) NumCalls() int { 93 return len(a.Records) 94 } 95 96 func (a *APIArgRecorder) GetFilteredRecordsAndReset(filter func(*APIRecord) bool) (filtered []APIRecord) { 97 filtered = FilterAPIRecords(a.Records, filter) 98 a.Reset() 99 return filtered 100 } 101 102 func (a *APIArgRecorder) Get(mctx MetaContext, arg APIArg) (*APIRes, error) { 103 res, err := a.API.Get(mctx, arg) 104 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodGet, Res: res, Err: err}) 105 return res, err 106 } 107 func (a *APIArgRecorder) GetDecode(mctx MetaContext, arg APIArg, arw APIResponseWrapper) error { 108 err := a.API.GetDecode(mctx, arg, arw) 109 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodGetDecode, RespWrapper: arw, Err: err}) 110 return err 111 } 112 func (a *APIArgRecorder) GetDecodeCtx(ctx context.Context, arg APIArg, arw APIResponseWrapper) error { 113 err := a.API.GetDecodeCtx(ctx, arg, arw) 114 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodGetDecodeCtx, RespWrapper: arw, Err: err}) 115 return err 116 } 117 func (a *APIArgRecorder) GetResp(mctx MetaContext, arg APIArg) (*http.Response, func(), error) { 118 httpR, f, err := a.API.GetResp(mctx, arg) 119 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodGetResp, HTTPResp: httpR, Func: f, Err: err}) 120 return httpR, f, err 121 } 122 func (a *APIArgRecorder) Post(mctx MetaContext, arg APIArg) (*APIRes, error) { 123 res, err := a.API.Post(mctx, arg) 124 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodPost, Res: res, Err: err}) 125 return res, err 126 } 127 func (a *APIArgRecorder) PostJSON(mctx MetaContext, arg APIArg) (*APIRes, error) { 128 res, err := a.API.PostJSON(mctx, arg) 129 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodPostJSON, Res: res, Err: err}) 130 return res, err 131 } 132 func (a *APIArgRecorder) PostDecode(mctx MetaContext, arg APIArg, arw APIResponseWrapper) error { 133 err := a.API.PostDecode(mctx, arg, arw) 134 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodPostDecode, RespWrapper: arw, Err: err}) 135 return err 136 } 137 func (a *APIArgRecorder) PostDecodeCtx(ctx context.Context, arg APIArg, arw APIResponseWrapper) error { 138 err := a.API.PostDecodeCtx(ctx, arg, arw) 139 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodPostDecodeCtx, RespWrapper: arw, Err: err}) 140 return err 141 } 142 func (a *APIArgRecorder) PostRaw(mctx MetaContext, arg APIArg, s string, r io.Reader) (*APIRes, error) { 143 res, err := a.API.PostRaw(mctx, arg, s, r) 144 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodPostRaw, S: s, R: r, Res: res, Err: err}) 145 return res, err 146 } 147 func (a *APIArgRecorder) Delete(mctx MetaContext, arg APIArg) (*APIRes, error) { 148 res, err := a.API.Delete(mctx, arg) 149 a.Records = append(a.Records, APIRecord{Arg: arg, Method: MethodDelete, Res: res, Err: err}) 150 return res, err 151 } 152 153 // APIRouter forwards each API call to one of the underlying API implementations 154 // depending on an internal filter function passed to its constructor. Be 155 // careful that the filter always returns a value in bound for the api array. 156 // This is meant to be used in tests to mock some but not all api calls. 157 type APIRouter struct { 158 APIs []API 159 Filter func(arg APIArg, method APIMethodType) int 160 } 161 162 var _ API = (*APIRouter)(nil) 163 164 func NewAPIRouter(apis []API, filter func(arg APIArg, method APIMethodType) int) *APIRouter { 165 return &APIRouter{APIs: apis, Filter: filter} 166 } 167 168 func (a *APIRouter) Get(mctx MetaContext, arg APIArg) (*APIRes, error) { 169 return a.APIs[a.Filter(arg, MethodGet)].Get(mctx, arg) 170 } 171 func (a *APIRouter) GetDecode(mctx MetaContext, arg APIArg, arw APIResponseWrapper) error { 172 return a.APIs[a.Filter(arg, MethodGetDecode)].GetDecode(mctx, arg, arw) 173 } 174 func (a *APIRouter) GetDecodeCtx(ctx context.Context, arg APIArg, arw APIResponseWrapper) error { 175 return a.APIs[a.Filter(arg, MethodGetDecodeCtx)].GetDecodeCtx(ctx, arg, arw) 176 } 177 func (a *APIRouter) GetResp(mctx MetaContext, arg APIArg) (*http.Response, func(), error) { 178 return a.APIs[a.Filter(arg, MethodGetResp)].GetResp(mctx, arg) 179 } 180 func (a *APIRouter) Post(mctx MetaContext, arg APIArg) (*APIRes, error) { 181 return a.APIs[a.Filter(arg, MethodPost)].Post(mctx, arg) 182 } 183 func (a *APIRouter) PostJSON(mctx MetaContext, arg APIArg) (*APIRes, error) { 184 return a.APIs[a.Filter(arg, MethodPostJSON)].PostJSON(mctx, arg) 185 } 186 func (a *APIRouter) PostDecode(mctx MetaContext, arg APIArg, arw APIResponseWrapper) error { 187 return a.APIs[a.Filter(arg, MethodPostDecode)].PostDecode(mctx, arg, arw) 188 } 189 func (a *APIRouter) PostDecodeCtx(ctx context.Context, arg APIArg, arw APIResponseWrapper) error { 190 return a.APIs[a.Filter(arg, MethodPostDecodeCtx)].PostDecodeCtx(ctx, arg, arw) 191 } 192 func (a *APIRouter) PostRaw(mctx MetaContext, arg APIArg, s string, r io.Reader) (*APIRes, error) { 193 return a.APIs[a.Filter(arg, MethodPostRaw)].PostRaw(mctx, arg, s, r) 194 } 195 func (a *APIRouter) Delete(mctx MetaContext, arg APIArg) (*APIRes, error) { 196 return a.APIs[a.Filter(arg, MethodDelete)].Delete(mctx, arg) 197 } 198 199 type ErrorMockAPI struct{} 200 201 var _ API = (*ErrorMockAPI)(nil) 202 203 var errMockAPI = errors.New("ErrorMockAPI error") 204 205 func (n *ErrorMockAPI) Get(MetaContext, APIArg) (*APIRes, error) { return nil, errMockAPI } 206 func (n *ErrorMockAPI) GetDecode(MetaContext, APIArg, APIResponseWrapper) error { return errMockAPI } 207 func (n *ErrorMockAPI) GetDecodeCtx(context.Context, APIArg, APIResponseWrapper) error { 208 return errMockAPI 209 } 210 func (n *ErrorMockAPI) GetResp(MetaContext, APIArg) (*http.Response, func(), error) { 211 return nil, noopFinisher, nil 212 } 213 func (n *ErrorMockAPI) Post(MetaContext, APIArg) (*APIRes, error) { return nil, errMockAPI } 214 func (n *ErrorMockAPI) PostJSON(MetaContext, APIArg) (*APIRes, error) { return nil, errMockAPI } 215 func (n *ErrorMockAPI) PostDecode(MetaContext, APIArg, APIResponseWrapper) error { return errMockAPI } 216 func (n *ErrorMockAPI) PostDecodeCtx(context.Context, APIArg, APIResponseWrapper) error { 217 return errMockAPI 218 } 219 func (n *ErrorMockAPI) PostRaw(MetaContext, APIArg, string, io.Reader) (*APIRes, error) { 220 return nil, errMockAPI 221 } 222 func (n *ErrorMockAPI) Delete(MetaContext, APIArg) (*APIRes, error) { return nil, errMockAPI }