github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 "github.com/juju/juju/apiserver/facade" 15 "github.com/juju/juju/apiserver/facade/facadetest" 16 apiservertesting "github.com/juju/juju/apiserver/testing" 17 "github.com/juju/juju/rpc/rpcreflect" 18 "github.com/juju/juju/state" 19 coretesting "github.com/juju/juju/testing" 20 ) 21 22 type facadeRegistrySuite struct { 23 coretesting.BaseSuite 24 } 25 26 var _ = gc.Suite(&facadeRegistrySuite{}) 27 28 func (s *facadeRegistrySuite) TestRegister(c *gc.C) { 29 common.SanitizeFacades(s) 30 var v interface{} 31 common.RegisterFacade("myfacade", 0, testFacade, reflect.TypeOf(&v).Elem()) 32 f, err := common.Facades.GetFactory("myfacade", 0) 33 c.Assert(err, jc.ErrorIsNil) 34 val, err := f(nil) 35 c.Assert(err, jc.ErrorIsNil) 36 c.Check(val, gc.Equals, "myobject") 37 } 38 39 func (s *facadeRegistrySuite) TestRegisterForFeature(c *gc.C) { 40 common.SanitizeFacades(s) 41 var v interface{} 42 common.RegisterFacadeForFeature("myfacade", 0, testFacade, reflect.TypeOf(&v).Elem(), "magic") 43 f, err := common.Facades.GetFactory("myfacade", 0) 44 c.Check(err, jc.Satisfies, errors.IsNotFound) 45 46 s.SetFeatureFlags("magic") 47 48 f, err = common.Facades.GetFactory("myfacade", 0) 49 c.Assert(err, jc.ErrorIsNil) 50 val, err := f(nil) 51 c.Assert(err, jc.ErrorIsNil) 52 c.Check(val, gc.Equals, "myobject") 53 } 54 55 func (s *facadeRegistrySuite) TestRegisterFacadePanicsOnDoubleRegistry(c *gc.C) { 56 var v interface{} 57 doRegister := func() { 58 common.RegisterFacade("myfacade", 0, testFacade, reflect.TypeOf(v)) 59 } 60 doRegister() 61 c.Assert(doRegister, gc.PanicMatches, `object "myfacade\(0\)" already registered`) 62 } 63 64 func (*facadeRegistrySuite) TestValidateNewFacade(c *gc.C) { 65 checkValidateNewFacadeFailsWith(c, nil, 66 `cannot wrap nil`) 67 checkValidateNewFacadeFailsWith(c, "notafunc", 68 `wrong type "string" is not a function`) 69 checkValidateNewFacadeFailsWith(c, noArgs, 70 `function ".*noArgs" does not take 3 parameters and return 2`) 71 checkValidateNewFacadeFailsWith(c, badCountIn, 72 `function ".*badCountIn" does not take 3 parameters and return 2`) 73 checkValidateNewFacadeFailsWith(c, badCountOut, 74 `function ".*badCountOut" does not take 3 parameters and return 2`) 75 checkValidateNewFacadeFailsWith(c, wrongIn, 76 `function ".*wrongIn" does not have the signature func \(\*state.State, facade.Resources, facade.Authorizer\) \(\*Type, error\)`) 77 checkValidateNewFacadeFailsWith(c, wrongOut, 78 `function ".*wrongOut" does not have the signature func \(\*state.State, facade.Resources, facade.Authorizer\) \(\*Type, error\)`) 79 err := common.ValidateNewFacade(reflect.ValueOf(validFactory)) 80 c.Assert(err, jc.ErrorIsNil) 81 } 82 83 func (*facadeRegistrySuite) TestWrapNewFacadeFailure(c *gc.C) { 84 _, _, err := common.WrapNewFacade("notafunc") 85 c.Check(err, gc.ErrorMatches, `wrong type "string" is not a function`) 86 } 87 88 func (*facadeRegistrySuite) TestWrapNewFacadeHandlesId(c *gc.C) { 89 wrapped, _, err := common.WrapNewFacade(validFactory) 90 c.Assert(err, jc.ErrorIsNil) 91 val, err := wrapped(facadetest.Context{ 92 ID_: "badId", 93 }) 94 c.Check(err, gc.ErrorMatches, "id not found") 95 c.Check(val, gc.Equals, nil) 96 } 97 98 func (*facadeRegistrySuite) TestWrapNewFacadeCallsFunc(c *gc.C) { 99 wrapped, _, err := common.WrapNewFacade(validFactory) 100 c.Assert(err, jc.ErrorIsNil) 101 val, err := wrapped(facadetest.Context{}) 102 c.Assert(err, jc.ErrorIsNil) 103 c.Check(*(val.(*int)), gc.Equals, 100) 104 } 105 106 func (*facadeRegistrySuite) TestWrapNewFacadeCallsWithRightParams(c *gc.C) { 107 authorizer := apiservertesting.FakeAuthorizer{} 108 resources := common.NewResources() 109 testFunc := func( 110 st *state.State, 111 resources facade.Resources, 112 authorizer facade.Authorizer, 113 ) (*myResult, error) { 114 return &myResult{st, resources, authorizer}, nil 115 } 116 wrapped, facadeType, err := common.WrapNewFacade(testFunc) 117 c.Assert(err, jc.ErrorIsNil) 118 c.Check(facadeType, gc.Equals, reflect.TypeOf((*myResult)(nil))) 119 120 val, err := wrapped(facadetest.Context{ 121 Resources_: resources, 122 Auth_: authorizer, 123 }) 124 c.Assert(err, jc.ErrorIsNil) 125 asResult := val.(*myResult) 126 c.Check(asResult.st, gc.IsNil) 127 c.Check(asResult.resources, gc.Equals, resources) 128 c.Check(asResult.auth, gc.Equals, authorizer) 129 } 130 131 func (s *facadeRegistrySuite) TestRegisterStandardFacade(c *gc.C) { 132 common.SanitizeFacades(s) 133 common.RegisterStandardFacade("testing", 0, validFactory) 134 wrapped, err := common.Facades.GetFactory("testing", 0) 135 c.Assert(err, jc.ErrorIsNil) 136 val, err := wrapped(facadetest.Context{}) 137 c.Assert(err, jc.ErrorIsNil) 138 c.Check(*(val.(*int)), gc.Equals, 100) 139 } 140 141 func (s *facadeRegistrySuite) TestRegisterStandardFacadePanic(c *gc.C) { 142 common.SanitizeFacades(s) 143 c.Assert( 144 func() { common.RegisterStandardFacade("badtest", 0, noArgs) }, 145 gc.PanicMatches, 146 `function ".*noArgs" does not take 3 parameters and return 2`) 147 _, err := common.Facades.GetFactory("badtest", 0) 148 c.Assert(err, jc.Satisfies, errors.IsNotFound) 149 c.Assert(err, gc.ErrorMatches, `badtest\(0\) not found`) 150 } 151 152 func (*facadeRegistrySuite) TestDiscardedAPIMethods(c *gc.C) { 153 allFacades := common.Facades.List() 154 c.Assert(allFacades, gc.Not(gc.HasLen), 0) 155 for _, description := range allFacades { 156 for _, version := range description.Versions { 157 facadeType, err := common.Facades.GetType(description.Name, version) 158 c.Assert(err, jc.ErrorIsNil) 159 facadeObjType := rpcreflect.ObjTypeOf(facadeType) 160 // We must have some methods on every object returned 161 // by a root-level method. 162 c.Assert(facadeObjType.MethodNames(), gc.Not(gc.HasLen), 0) 163 // We don't allow any methods that don't implement 164 // an RPC entry point. 165 c.Assert(facadeObjType.DiscardedMethods(), gc.HasLen, 0) 166 } 167 } 168 } 169 170 func testFacade(facade.Context) (facade.Facade, error) { 171 return "myobject", nil 172 } 173 174 type myResult struct { 175 st *state.State 176 resources facade.Resources 177 auth facade.Authorizer 178 } 179 180 func checkValidateNewFacadeFailsWith(c *gc.C, obj interface{}, errMsg string) { 181 err := common.ValidateNewFacade(reflect.ValueOf(obj)) 182 c.Check(err, gc.NotNil) 183 c.Check(err, gc.ErrorMatches, errMsg) 184 } 185 186 func noArgs() { 187 } 188 189 func badCountIn(a string) (*int, error) { 190 return nil, nil 191 } 192 193 func badCountOut(a, b, c string) error { 194 return nil 195 } 196 197 func wrongIn(a, b, c string) (*int, error) { 198 return nil, nil 199 } 200 201 func wrongOut(*state.State, facade.Resources, facade.Authorizer) (error, *int) { 202 return nil, nil 203 } 204 205 func validFactory(*state.State, facade.Resources, facade.Authorizer) (*int, error) { 206 var i = 100 207 return &i, nil 208 }