func (r *rootSuite) TestFindMethodEnsuresTypeMatch(c *gc.C) { srvRoot := apiserver.TestingSrvRoot(nil) defer common.Facades.Discard("my-testing-facade", 0) defer common.Facades.Discard("my-testing-facade", 1) defer common.Facades.Discard("my-testing-facade", 2) myBadFacade := func( *state.State, *common.Resources, common.Authorizer, string, ) ( interface{}, error, ) { return &badType{}, nil } myGoodFacade := func( *state.State, *common.Resources, common.Authorizer, string, ) ( interface{}, error, ) { return &testingType{}, nil } myErrFacade := func( *state.State, *common.Resources, common.Authorizer, string, ) ( interface{}, error, ) { return nil, fmt.Errorf("you shall not pass") } expectedType := reflect.TypeOf((*testingType)(nil)) common.RegisterFacade("my-testing-facade", 0, myBadFacade, expectedType) common.RegisterFacade("my-testing-facade", 1, myGoodFacade, expectedType) common.RegisterFacade("my-testing-facade", 2, myErrFacade, expectedType) // Now, myGoodFacade returns the right type, so calling it should work // fine caller, err := srvRoot.FindMethod("my-testing-facade", 1, "Exposed") c.Assert(err, gc.IsNil) _, err = caller.Call("", reflect.Value{}) c.Check(err, gc.ErrorMatches, "Exposed was bogus") // However, myBadFacade returns the wrong type, so trying to access it // should create an error caller, err = srvRoot.FindMethod("my-testing-facade", 0, "Exposed") c.Assert(err, gc.IsNil) _, err = caller.Call("", reflect.Value{}) c.Check(err, gc.ErrorMatches, `internal error, my-testing-facade\(0\) claimed to return \*apiserver_test.testingType but returned \*apiserver_test.badType`) // myErrFacade had the permissions change, so calling it returns an // error, but that shouldn't trigger the type checking code. caller, err = srvRoot.FindMethod("my-testing-facade", 2, "Exposed") c.Assert(err, gc.IsNil) res, err := caller.Call("", reflect.Value{}) c.Check(err, gc.ErrorMatches, `you shall not pass`) c.Check(res.IsValid(), jc.IsFalse) }
func (r *rootSuite) TestFindMethodCacheRaceSafe(c *gc.C) { srvRoot := apiserver.TestingSrvRoot(nil) defer common.Facades.Discard("my-counting-facade", 0) var count int64 newIdCounter := func( _ *state.State, _ *common.Resources, _ common.Authorizer, id string, ) (interface{}, error) { count += 1 return &countingType{count: count, id: id}, nil } reflectType := reflect.TypeOf((*countingType)(nil)) common.RegisterFacade("my-counting-facade", 0, newIdCounter, reflectType) caller, err := srvRoot.FindMethod("my-counting-facade", 0, "Count") c.Assert(err, gc.IsNil) // This is designed to trigger the race detector var wg sync.WaitGroup wg.Add(4) go func() { caller.Call("first", reflect.Value{}); wg.Done() }() go func() { caller.Call("second", reflect.Value{}); wg.Done() }() go func() { caller.Call("first", reflect.Value{}); wg.Done() }() go func() { caller.Call("second", reflect.Value{}); wg.Done() }() wg.Wait() // Once we're done, we should have only instantiated 2 different // objects. If we pass a different Id, we should be at 3 total count. assertCallResult(c, caller, "third", "third3") }
func (r *rootSuite) TestFindMethodCachesFacadesWithId(c *gc.C) { srvRoot := apiserver.TestingSrvRoot(nil) defer common.Facades.Discard("my-counting-facade", 0) var count int64 // like newCounter, but also tracks the "id" that was requested for // this counter newIdCounter := func( _ *state.State, _ *common.Resources, _ common.Authorizer, id string, ) (interface{}, error) { count += 1 return &countingType{count: count, id: id}, nil } reflectType := reflect.TypeOf((*countingType)(nil)) common.RegisterFacade("my-counting-facade", 0, newIdCounter, reflectType) // The first time we call FindMethod, it should lookup a facade, and // request a new object. caller, err := srvRoot.FindMethod("my-counting-facade", 0, "Count") c.Assert(err, gc.IsNil) assertCallResult(c, caller, "orig-id", "orig-id1") // However, if we place another call for a different Id, it should grab // a new object assertCallResult(c, caller, "alt-id", "alt-id2") // Asking for the original object gives us the cached value assertCallResult(c, caller, "orig-id", "orig-id1") // Asking for the original object gives us the cached value assertCallResult(c, caller, "alt-id", "alt-id2") // We get the same results asking for the other method caller, err = srvRoot.FindMethod("my-counting-facade", 0, "AltCount") c.Assert(err, gc.IsNil) assertCallResult(c, caller, "orig-id", "ALT-orig-id1") assertCallResult(c, caller, "alt-id", "ALT-alt-id2") assertCallResult(c, caller, "third-id", "ALT-third-id3") }
func init() { common.RegisterFacade( "AllWatcher", 0, newClientAllWatcher, reflect.TypeOf((*srvClientAllWatcher)(nil)), ) common.RegisterFacade( "NotifyWatcher", 0, newNotifyWatcher, reflect.TypeOf((*srvNotifyWatcher)(nil)), ) common.RegisterFacade( "StringsWatcher", 0, newStringsWatcher, reflect.TypeOf((*srvStringsWatcher)(nil)), ) common.RegisterFacade( "RelationUnitsWatcher", 0, newRelationUnitsWatcher, reflect.TypeOf((*srvRelationUnitsWatcher)(nil)), ) }