github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/api/base/testing/apicaller.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package testing 5 6 import ( 7 "net/url" 8 9 "github.com/juju/errors" 10 "github.com/juju/httprequest" 11 "github.com/juju/names" 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/api/base" 17 coretesting "github.com/juju/juju/testing" 18 ) 19 20 // APICallerFunc is a function type that implements APICaller. 21 // The only method that actually does anything is APICall itself 22 // which calls the function. The other methods are just stubs. 23 type APICallerFunc func(objType string, version int, id, request string, params, response interface{}) error 24 25 func (f APICallerFunc) APICall(objType string, version int, id, request string, params, response interface{}) error { 26 return f(objType, version, id, request, params, response) 27 } 28 29 func (APICallerFunc) BestFacadeVersion(facade string) int { 30 // TODO(fwereade): this should return something arbitrary (e.g. 37) 31 // so that it can't be confused with mere uninitialized data. 32 return 0 33 } 34 35 func (APICallerFunc) ModelTag() (names.ModelTag, error) { 36 return coretesting.ModelTag, nil 37 } 38 39 func (APICallerFunc) Close() error { 40 return nil 41 } 42 43 func (APICallerFunc) HTTPClient() (*httprequest.Client, error) { 44 return nil, errors.New("no HTTP client available in this test") 45 } 46 47 func (APICallerFunc) ConnectStream(path string, attrs url.Values) (base.Stream, error) { 48 return nil, errors.New("stream connection unimplemented") 49 } 50 51 // CheckArgs holds the possible arguments to CheckingAPICaller(). Any 52 // fields non empty fields will be checked to match the arguments 53 // recieved by the APICall() method of the returned APICallerFunc. If 54 // Id is empty, but IdIsEmpty is true, the id argument is checked to 55 // be empty. The same applies to Version being empty, but if 56 // VersionIsZero set to true the version is checked to be 0. 57 type CheckArgs struct { 58 Facade string 59 Version int 60 Id string 61 Method string 62 Args interface{} 63 Results interface{} 64 65 IdIsEmpty bool 66 VersionIsZero bool 67 } 68 69 func checkArgs(c *gc.C, args *CheckArgs, facade string, version int, id, method string, inArgs, outResults interface{}) { 70 if args == nil { 71 c.Logf("checkArgs: args is nil!") 72 return 73 } else { 74 if args.Facade != "" { 75 c.Check(facade, gc.Equals, args.Facade) 76 } 77 if args.Version != 0 { 78 c.Check(version, gc.Equals, args.Version) 79 } else if args.VersionIsZero { 80 c.Check(version, gc.Equals, 0) 81 } 82 if args.Id != "" { 83 c.Check(id, gc.Equals, args.Id) 84 } else if args.IdIsEmpty { 85 c.Check(id, gc.Equals, "") 86 } 87 if args.Method != "" { 88 c.Check(method, gc.Equals, args.Method) 89 } 90 if args.Args != nil { 91 c.Check(inArgs, jc.DeepEquals, args.Args) 92 } 93 if args.Results != nil { 94 c.Check(outResults, gc.NotNil) 95 testing.PatchValue(outResults, args.Results) 96 } 97 } 98 } 99 100 // CheckingAPICaller returns an APICallerFunc which can report the 101 // number of times its APICall() method was called (if numCalls is not 102 // nil), as well as check if any of the arguments passed to the 103 // APICall() method match the values given in args (if args itself is 104 // not nil, otherwise no arguments are checked). The final error 105 // result of the APICall() will be set to err. 106 func CheckingAPICaller(c *gc.C, args *CheckArgs, numCalls *int, err error) base.APICallCloser { 107 return APICallerFunc( 108 func(facade string, version int, id, method string, inArgs, outResults interface{}) error { 109 if numCalls != nil { 110 *numCalls++ 111 } 112 if args != nil { 113 checkArgs(c, args, facade, version, id, method, inArgs, outResults) 114 } 115 return err 116 }, 117 ) 118 } 119 120 // NotifyingCheckingAPICaller returns an APICallerFunc which sends a message on the channel "called" every 121 // time it recives a call, as well as check if any of the arguments passed to the APICall() method match 122 // the values given in args (if args itself is not nil, otherwise no arguments are checked). The final 123 // error result of the APICall() will be set to err. 124 func NotifyingCheckingAPICaller(c *gc.C, args *CheckArgs, called chan struct{}, err error) base.APICaller { 125 return APICallerFunc( 126 func(facade string, version int, id, method string, inArgs, outResults interface{}) error { 127 called <- struct{}{} 128 if args != nil { 129 checkArgs(c, args, facade, version, id, method, inArgs, outResults) 130 } 131 return err 132 }, 133 ) 134 } 135 136 // CheckingAPICallerMultiArgs checks each call against the indexed expected argument. Once expected 137 // arguments run out it doesn't check them. This is useful if your test continues to make calls after 138 // you have checked the ones you care about. 139 func CheckingAPICallerMultiArgs(c *gc.C, args []CheckArgs, numCalls *int, err error) base.APICallCloser { 140 if numCalls == nil { 141 panic("numCalls must be non-nill") 142 } 143 return APICallerFunc( 144 func(facade string, version int, id, method string, inArgs, outResults interface{}) error { 145 if len(args) > *numCalls { 146 checkArgs(c, &args[*numCalls], facade, version, id, method, inArgs, outResults) 147 } 148 *numCalls++ 149 return err 150 }, 151 ) 152 } 153 154 // StubFacadeCaller is a testing stub implementation of api/base.FacadeCaller. 155 type StubFacadeCaller struct { 156 // Stub is the raw stub used to track calls and errors. 157 Stub *testing.Stub 158 // These control the values returned by the stub's methods. 159 FacadeCallFn func(name string, params, response interface{}) error 160 ReturnName string 161 ReturnBestAPIVersion int 162 ReturnRawAPICaller base.APICaller 163 } 164 165 // FacadeCall implements api/base.FacadeCaller. 166 func (s *StubFacadeCaller) FacadeCall(request string, params, response interface{}) error { 167 s.Stub.AddCall("FacadeCall", request, params, response) 168 if err := s.Stub.NextErr(); err != nil { 169 return errors.Trace(err) 170 } 171 172 if s.FacadeCallFn != nil { 173 return s.FacadeCallFn(request, params, response) 174 } 175 return nil 176 } 177 178 // Name implements api/base.FacadeCaller. 179 func (s *StubFacadeCaller) Name() string { 180 s.Stub.AddCall("Name") 181 s.Stub.PopNoErr() 182 183 return s.ReturnName 184 } 185 186 // BestAPIVersion implements api/base.FacadeCaller. 187 func (s *StubFacadeCaller) BestAPIVersion() int { 188 s.Stub.AddCall("BestAPIVersion") 189 s.Stub.PopNoErr() 190 191 return s.ReturnBestAPIVersion 192 } 193 194 // RawAPICaller implements api/base.FacadeCaller. 195 func (s *StubFacadeCaller) RawAPICaller() base.APICaller { 196 s.Stub.AddCall("RawAPICaller") 197 s.Stub.PopNoErr() 198 199 return s.ReturnRawAPICaller 200 }