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  }