github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/common/registry_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common_test 5 6 import ( 7 "reflect" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/apiserver/common" 14 apiservertesting "github.com/juju/juju/apiserver/testing" 15 "github.com/juju/juju/rpc/rpcreflect" 16 "github.com/juju/juju/state" 17 coretesting "github.com/juju/juju/testing" 18 ) 19 20 type facadeRegistrySuite struct { 21 coretesting.BaseSuite 22 } 23 24 var _ = gc.Suite(&facadeRegistrySuite{}) 25 26 func testFacade( 27 st *state.State, resources *common.Resources, 28 authorizer common.Authorizer, id string, 29 ) (interface{}, error) { 30 return "myobject", nil 31 } 32 33 func (s *facadeRegistrySuite) TestRegister(c *gc.C) { 34 common.SanitizeFacades(s) 35 var v interface{} 36 common.RegisterFacade("myfacade", 0, testFacade, reflect.TypeOf(&v).Elem()) 37 f, err := common.Facades.GetFactory("myfacade", 0) 38 c.Assert(err, jc.ErrorIsNil) 39 val, err := f(nil, nil, nil, "") 40 c.Assert(err, jc.ErrorIsNil) 41 c.Check(val, gc.Equals, "myobject") 42 } 43 44 func (*facadeRegistrySuite) TestGetFactoryUnknown(c *gc.C) { 45 r := &common.FacadeRegistry{} 46 f, err := r.GetFactory("name", 0) 47 c.Check(err, jc.Satisfies, errors.IsNotFound) 48 c.Check(err, gc.ErrorMatches, `name\(0\) not found`) 49 c.Check(f, gc.IsNil) 50 } 51 52 func (s *facadeRegistrySuite) TestRegisterForFeature(c *gc.C) { 53 common.SanitizeFacades(s) 54 var v interface{} 55 common.RegisterFacadeForFeature("myfacade", 0, testFacade, reflect.TypeOf(&v).Elem(), "magic") 56 f, err := common.Facades.GetFactory("myfacade", 0) 57 c.Check(err, jc.Satisfies, errors.IsNotFound) 58 59 s.SetFeatureFlags("magic") 60 61 f, err = common.Facades.GetFactory("myfacade", 0) 62 c.Assert(err, jc.ErrorIsNil) 63 val, err := f(nil, nil, nil, "") 64 c.Assert(err, jc.ErrorIsNil) 65 c.Check(val, gc.Equals, "myobject") 66 } 67 68 func (*facadeRegistrySuite) TestGetFactoryUnknownVersion(c *gc.C) { 69 r := &common.FacadeRegistry{} 70 c.Assert(r.Register("name", 0, validIdFactory, intPtrType, ""), gc.IsNil) 71 f, err := r.GetFactory("name", 1) 72 c.Check(err, jc.Satisfies, errors.IsNotFound) 73 c.Check(err, gc.ErrorMatches, `name\(1\) not found`) 74 c.Check(f, gc.IsNil) 75 } 76 77 func (s *facadeRegistrySuite) TestRegisterFacadePanicsOnDoubleRegistry(c *gc.C) { 78 var v interface{} 79 doRegister := func() { 80 common.RegisterFacade("myfacade", 0, testFacade, reflect.TypeOf(v)) 81 } 82 doRegister() 83 c.Assert(doRegister, gc.PanicMatches, `object "myfacade\(0\)" already registered`) 84 } 85 86 func checkValidateNewFacadeFailsWith(c *gc.C, obj interface{}, errMsg string) { 87 err := common.ValidateNewFacade(reflect.ValueOf(obj)) 88 c.Check(err, gc.NotNil) 89 c.Check(err, gc.ErrorMatches, errMsg) 90 } 91 92 func noArgs() { 93 } 94 95 func badCountIn(a string) (*int, error) { 96 return nil, nil 97 } 98 99 func badCountOut(a, b, c string) error { 100 return nil 101 } 102 103 func wrongIn(a, b, c string) (*int, error) { 104 return nil, nil 105 } 106 107 func wrongOut(*state.State, *common.Resources, common.Authorizer) (error, *int) { 108 return nil, nil 109 } 110 111 func validFactory(*state.State, *common.Resources, common.Authorizer) (*int, error) { 112 var i = 100 113 return &i, nil 114 } 115 116 func (*facadeRegistrySuite) TestValidateNewFacade(c *gc.C) { 117 checkValidateNewFacadeFailsWith(c, nil, 118 `cannot wrap nil`) 119 checkValidateNewFacadeFailsWith(c, "notafunc", 120 `wrong type "string" is not a function`) 121 checkValidateNewFacadeFailsWith(c, noArgs, 122 `function ".*noArgs" does not take 3 parameters and return 2`) 123 checkValidateNewFacadeFailsWith(c, badCountIn, 124 `function ".*badCountIn" does not take 3 parameters and return 2`) 125 checkValidateNewFacadeFailsWith(c, badCountOut, 126 `function ".*badCountOut" does not take 3 parameters and return 2`) 127 checkValidateNewFacadeFailsWith(c, wrongIn, 128 `function ".*wrongIn" does not have the signature func \(\*state.State, \*common.Resources, common.Authorizer\) \(\*Type, error\)`) 129 checkValidateNewFacadeFailsWith(c, wrongOut, 130 `function ".*wrongOut" does not have the signature func \(\*state.State, \*common.Resources, common.Authorizer\) \(\*Type, error\)`) 131 err := common.ValidateNewFacade(reflect.ValueOf(validFactory)) 132 c.Assert(err, jc.ErrorIsNil) 133 } 134 135 func (*facadeRegistrySuite) TestWrapNewFacadeFailure(c *gc.C) { 136 _, _, err := common.WrapNewFacade("notafunc") 137 c.Check(err, gc.ErrorMatches, `wrong type "string" is not a function`) 138 } 139 140 func (*facadeRegistrySuite) TestWrapNewFacadeHandlesId(c *gc.C) { 141 wrapped, _, err := common.WrapNewFacade(validFactory) 142 c.Assert(err, jc.ErrorIsNil) 143 val, err := wrapped(nil, nil, nil, "badId") 144 c.Check(err, gc.ErrorMatches, "id not found") 145 c.Check(val, gc.Equals, nil) 146 } 147 148 func (*facadeRegistrySuite) TestWrapNewFacadeCallsFunc(c *gc.C) { 149 wrapped, _, err := common.WrapNewFacade(validFactory) 150 c.Assert(err, jc.ErrorIsNil) 151 val, err := wrapped(nil, nil, nil, "") 152 c.Assert(err, jc.ErrorIsNil) 153 c.Check(*(val.(*int)), gc.Equals, 100) 154 } 155 156 type myResult struct { 157 st *state.State 158 resources *common.Resources 159 auth common.Authorizer 160 } 161 162 func (*facadeRegistrySuite) TestWrapNewFacadeCallsWithRightParams(c *gc.C) { 163 authorizer := apiservertesting.FakeAuthorizer{} 164 resources := common.NewResources() 165 testFunc := func( 166 st *state.State, resources *common.Resources, 167 authorizer common.Authorizer, 168 ) (*myResult, error) { 169 return &myResult{st, resources, authorizer}, nil 170 } 171 wrapped, facadeType, err := common.WrapNewFacade(testFunc) 172 c.Assert(err, jc.ErrorIsNil) 173 c.Check(facadeType, gc.Equals, reflect.TypeOf((*myResult)(nil))) 174 val, err := wrapped(nil, resources, authorizer, "") 175 c.Assert(err, jc.ErrorIsNil) 176 asResult := val.(*myResult) 177 c.Check(asResult.st, gc.IsNil) 178 c.Check(asResult.resources, gc.Equals, resources) 179 c.Check(asResult.auth, gc.Equals, authorizer) 180 } 181 182 func (s *facadeRegistrySuite) TestRegisterStandardFacade(c *gc.C) { 183 common.SanitizeFacades(s) 184 common.RegisterStandardFacade("testing", 0, validFactory) 185 wrapped, err := common.Facades.GetFactory("testing", 0) 186 c.Assert(err, jc.ErrorIsNil) 187 val, err := wrapped(nil, nil, nil, "") 188 c.Assert(err, jc.ErrorIsNil) 189 c.Check(*(val.(*int)), gc.Equals, 100) 190 } 191 192 func (s *facadeRegistrySuite) TestRegisterStandardFacadePanic(c *gc.C) { 193 common.SanitizeFacades(s) 194 c.Assert( 195 func() { common.RegisterStandardFacade("badtest", 0, noArgs) }, 196 gc.PanicMatches, 197 `function ".*noArgs" does not take 3 parameters and return 2`) 198 _, err := common.Facades.GetFactory("badtest", 0) 199 c.Assert(err, jc.Satisfies, errors.IsNotFound) 200 c.Assert(err, gc.ErrorMatches, `badtest\(0\) not found`) 201 } 202 203 func (*facadeRegistrySuite) TestDiscardedAPIMethods(c *gc.C) { 204 allFacades := common.Facades.List() 205 c.Assert(allFacades, gc.Not(gc.HasLen), 0) 206 for _, description := range allFacades { 207 for _, version := range description.Versions { 208 facadeType, err := common.Facades.GetType(description.Name, version) 209 c.Assert(err, jc.ErrorIsNil) 210 facadeObjType := rpcreflect.ObjTypeOf(facadeType) 211 // We must have some methods on every object returned 212 // by a root-level method. 213 c.Assert(facadeObjType.MethodNames(), gc.Not(gc.HasLen), 0) 214 // We don't allow any methods that don't implement 215 // an RPC entry point. 216 c.Assert(facadeObjType.DiscardedMethods(), gc.HasLen, 0) 217 } 218 } 219 } 220 221 func validIdFactory(*state.State, *common.Resources, common.Authorizer, string) (interface{}, error) { 222 var i = 100 223 return &i, nil 224 } 225 226 var intPtr = new(int) 227 var intPtrType = reflect.TypeOf(&intPtr).Elem() 228 229 func (*facadeRegistrySuite) TestDescriptionFromVersions(c *gc.C) { 230 facades := common.Versions{0: common.NilFacadeRecord} 231 c.Check(common.DescriptionFromVersions("name", facades), 232 gc.DeepEquals, 233 common.FacadeDescription{ 234 Name: "name", 235 Versions: []int{0}, 236 }) 237 facades[2] = common.NilFacadeRecord 238 c.Check(common.DescriptionFromVersions("name", facades), 239 gc.DeepEquals, 240 common.FacadeDescription{ 241 Name: "name", 242 Versions: []int{0, 2}, 243 }) 244 } 245 246 func (*facadeRegistrySuite) TestDescriptionFromVersionsAreSorted(c *gc.C) { 247 facades := common.Versions{ 248 10: common.NilFacadeRecord, 249 5: common.NilFacadeRecord, 250 0: common.NilFacadeRecord, 251 18: common.NilFacadeRecord, 252 6: common.NilFacadeRecord, 253 4: common.NilFacadeRecord, 254 } 255 c.Check(common.DescriptionFromVersions("name", facades), 256 gc.DeepEquals, 257 common.FacadeDescription{ 258 Name: "name", 259 Versions: []int{0, 4, 5, 6, 10, 18}, 260 }) 261 } 262 263 func (*facadeRegistrySuite) TestRegisterAndList(c *gc.C) { 264 r := &common.FacadeRegistry{} 265 c.Assert(r.Register("name", 0, validIdFactory, intPtrType, ""), gc.IsNil) 266 c.Check(r.List(), gc.DeepEquals, []common.FacadeDescription{ 267 {Name: "name", Versions: []int{0}}, 268 }) 269 } 270 271 func (*facadeRegistrySuite) TestRegisterAndListMultiple(c *gc.C) { 272 r := &common.FacadeRegistry{} 273 c.Assert(r.Register("other", 0, validIdFactory, intPtrType, ""), gc.IsNil) 274 c.Assert(r.Register("name", 0, validIdFactory, intPtrType, ""), gc.IsNil) 275 c.Assert(r.Register("third", 2, validIdFactory, intPtrType, ""), gc.IsNil) 276 c.Assert(r.Register("third", 3, validIdFactory, intPtrType, ""), gc.IsNil) 277 c.Check(r.List(), gc.DeepEquals, []common.FacadeDescription{ 278 {Name: "name", Versions: []int{0}}, 279 {Name: "other", Versions: []int{0}}, 280 {Name: "third", Versions: []int{2, 3}}, 281 }) 282 } 283 284 func (s *facadeRegistrySuite) TestRegisterAndListMultipleWithFeatures(c *gc.C) { 285 r := &common.FacadeRegistry{} 286 c.Assert(r.Register("other", 0, validIdFactory, intPtrType, "special"), gc.IsNil) 287 c.Assert(r.Register("name", 0, validIdFactory, intPtrType, ""), gc.IsNil) 288 c.Assert(r.Register("name", 1, validIdFactory, intPtrType, "special"), gc.IsNil) 289 c.Assert(r.Register("third", 2, validIdFactory, intPtrType, ""), gc.IsNil) 290 c.Assert(r.Register("third", 3, validIdFactory, intPtrType, "magic"), gc.IsNil) 291 s.SetFeatureFlags("magic") 292 c.Check(r.List(), gc.DeepEquals, []common.FacadeDescription{ 293 {Name: "name", Versions: []int{0}}, 294 {Name: "third", Versions: []int{2, 3}}, 295 }) 296 } 297 298 func (*facadeRegistrySuite) TestRegisterAlreadyPresent(c *gc.C) { 299 r := &common.FacadeRegistry{} 300 err := r.Register("name", 0, validIdFactory, intPtrType, "") 301 c.Assert(err, jc.ErrorIsNil) 302 secondIdFactory := func(*state.State, *common.Resources, common.Authorizer, string) (interface{}, error) { 303 var i = 200 304 return &i, nil 305 } 306 err = r.Register("name", 0, secondIdFactory, intPtrType, "") 307 c.Check(err, gc.ErrorMatches, `object "name\(0\)" already registered`) 308 f, err := r.GetFactory("name", 0) 309 c.Assert(err, jc.ErrorIsNil) 310 c.Assert(f, gc.NotNil) 311 val, err := f(nil, nil, nil, "") 312 c.Assert(err, jc.ErrorIsNil) 313 asIntPtr := val.(*int) 314 c.Check(*asIntPtr, gc.Equals, 100) 315 } 316 317 func (*facadeRegistrySuite) TestGetFactory(c *gc.C) { 318 r := &common.FacadeRegistry{} 319 c.Assert(r.Register("name", 0, validIdFactory, intPtrType, ""), gc.IsNil) 320 f, err := r.GetFactory("name", 0) 321 c.Assert(err, jc.ErrorIsNil) 322 c.Assert(f, gc.NotNil) 323 res, err := f(nil, nil, nil, "") 324 c.Assert(err, jc.ErrorIsNil) 325 c.Assert(res, gc.NotNil) 326 asIntPtr := res.(*int) 327 c.Check(*asIntPtr, gc.Equals, 100) 328 } 329 330 func (*facadeRegistrySuite) TestGetType(c *gc.C) { 331 r := &common.FacadeRegistry{} 332 c.Assert(r.Register("name", 0, validIdFactory, intPtrType, ""), gc.IsNil) 333 typ, err := r.GetType("name", 0) 334 c.Assert(err, jc.ErrorIsNil) 335 c.Check(typ, gc.Equals, intPtrType) 336 } 337 338 func (*facadeRegistrySuite) TestDiscardHandlesNotPresent(c *gc.C) { 339 r := &common.FacadeRegistry{} 340 r.Discard("name", 1) 341 } 342 343 func (*facadeRegistrySuite) TestDiscardRemovesEntry(c *gc.C) { 344 r := &common.FacadeRegistry{} 345 c.Assert(r.Register("name", 0, validIdFactory, intPtrType, ""), gc.IsNil) 346 _, err := r.GetFactory("name", 0) 347 c.Assert(err, jc.ErrorIsNil) 348 r.Discard("name", 0) 349 f, err := r.GetFactory("name", 0) 350 c.Check(err, jc.Satisfies, errors.IsNotFound) 351 c.Check(err, gc.ErrorMatches, `name\(0\) not found`) 352 c.Check(f, gc.IsNil) 353 c.Check(r.List(), gc.DeepEquals, []common.FacadeDescription{}) 354 } 355 356 func (*facadeRegistrySuite) TestDiscardLeavesOtherVersions(c *gc.C) { 357 r := &common.FacadeRegistry{} 358 c.Assert(r.Register("name", 0, validIdFactory, intPtrType, ""), gc.IsNil) 359 c.Assert(r.Register("name", 1, validIdFactory, intPtrType, ""), gc.IsNil) 360 r.Discard("name", 0) 361 _, err := r.GetFactory("name", 0) 362 c.Check(err, jc.Satisfies, errors.IsNotFound) 363 _, err = r.GetFactory("name", 1) 364 c.Check(err, jc.ErrorIsNil) 365 c.Check(r.List(), gc.DeepEquals, []common.FacadeDescription{ 366 {Name: "name", Versions: []int{1}}, 367 }) 368 }