github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/api/uniter/relationunit_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter_test
     5  
     6  import (
     7  	jc "github.com/juju/testing/checkers"
     8  	gc "gopkg.in/check.v1"
     9  	"gopkg.in/juju/charm.v6-unstable"
    10  	"gopkg.in/juju/names.v2"
    11  
    12  	"github.com/juju/juju/api/uniter"
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/network"
    15  	"github.com/juju/juju/state"
    16  	"github.com/juju/juju/watcher/watchertest"
    17  )
    18  
    19  // commonRelationSuiteMixin contains fields used by both relationSuite
    20  // and relationUnitSuite. We're not just embeddnig relationUnitSuite
    21  // into relationSuite to avoid running the former's tests twice.
    22  type commonRelationSuiteMixin struct {
    23  	mysqlMachine *state.Machine
    24  	mysqlService *state.Application
    25  	mysqlCharm   *state.Charm
    26  	mysqlUnit    *state.Unit
    27  
    28  	stateRelation *state.Relation
    29  }
    30  
    31  type relationUnitSuite struct {
    32  	uniterSuite
    33  	commonRelationSuiteMixin
    34  }
    35  
    36  var _ = gc.Suite(&relationUnitSuite{})
    37  
    38  func (m *commonRelationSuiteMixin) SetUpTest(c *gc.C, s uniterSuite) {
    39  	// Create another machine, service and unit, so we can
    40  	// test relations and relation units.
    41  	m.mysqlMachine, m.mysqlService, m.mysqlCharm, m.mysqlUnit = s.addMachineServiceCharmAndUnit(c, "mysql")
    42  
    43  	// Add a relation, used by both this suite and relationSuite.
    44  	m.stateRelation = s.addRelation(c, "wordpress", "mysql")
    45  }
    46  
    47  func (s *relationUnitSuite) SetUpTest(c *gc.C) {
    48  	s.uniterSuite.SetUpTest(c)
    49  	s.commonRelationSuiteMixin.SetUpTest(c, s.uniterSuite)
    50  }
    51  
    52  func (s *relationUnitSuite) TearDownTest(c *gc.C) {
    53  	s.uniterSuite.TearDownTest(c)
    54  }
    55  
    56  func (s *relationUnitSuite) getRelationUnits(c *gc.C) (*state.RelationUnit, *uniter.RelationUnit) {
    57  	wpRelUnit, err := s.stateRelation.Unit(s.wordpressUnit)
    58  	c.Assert(err, jc.ErrorIsNil)
    59  	apiRelation, err := s.uniter.Relation(s.stateRelation.Tag().(names.RelationTag))
    60  	c.Assert(err, jc.ErrorIsNil)
    61  	// TODO(dfc)
    62  	apiUnit, err := s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag))
    63  	c.Assert(err, jc.ErrorIsNil)
    64  	apiRelUnit, err := apiRelation.Unit(apiUnit)
    65  	c.Assert(err, jc.ErrorIsNil)
    66  	return wpRelUnit, apiRelUnit
    67  }
    68  
    69  func (s *relationUnitSuite) TestRelation(c *gc.C) {
    70  	_, apiRelUnit := s.getRelationUnits(c)
    71  
    72  	apiRel := apiRelUnit.Relation()
    73  	c.Assert(apiRel, gc.NotNil)
    74  	c.Assert(apiRel.String(), gc.Equals, "wordpress:db mysql:server")
    75  }
    76  
    77  func (s *relationUnitSuite) TestEndpoint(c *gc.C) {
    78  	_, apiRelUnit := s.getRelationUnits(c)
    79  
    80  	apiEndpoint := apiRelUnit.Endpoint()
    81  	c.Assert(apiEndpoint, gc.DeepEquals, uniter.Endpoint{
    82  		charm.Relation{
    83  			Name:      "db",
    84  			Role:      "requirer",
    85  			Interface: "mysql",
    86  			Optional:  false,
    87  			Limit:     1,
    88  			Scope:     "global",
    89  		},
    90  	})
    91  }
    92  
    93  func (s *relationUnitSuite) TestPrivateAddress(c *gc.C) {
    94  	_, apiRelUnit := s.getRelationUnits(c)
    95  
    96  	// Try getting it first without an address set.
    97  	address, err := apiRelUnit.PrivateAddress()
    98  	c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no private address set`)
    99  
   100  	// Set an address and try again.
   101  	err = s.wordpressMachine.SetProviderAddresses(
   102  		network.NewScopedAddress("1.2.3.4", network.ScopeCloudLocal),
   103  	)
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	address, err = apiRelUnit.PrivateAddress()
   106  	c.Assert(err, jc.ErrorIsNil)
   107  	c.Assert(address, gc.Equals, "1.2.3.4")
   108  }
   109  
   110  func (s *relationUnitSuite) TestEnterScopeSuccessfully(c *gc.C) {
   111  	// NOTE: This test is not as exhaustive as the ones in state.
   112  	// Here, we just check the success case, while the two error
   113  	// cases are tested separately.
   114  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   115  	s.assertInScope(c, wpRelUnit, false)
   116  
   117  	err := apiRelUnit.EnterScope()
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	s.assertInScope(c, wpRelUnit, true)
   120  }
   121  
   122  func (s *relationUnitSuite) TestEnterScopeErrCannotEnterScope(c *gc.C) {
   123  	// Test the ErrCannotEnterScope gets forwarded correctly.
   124  	// We need to enter the scope wit the other unit first.
   125  	myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit)
   126  	c.Assert(err, jc.ErrorIsNil)
   127  	err = myRelUnit.EnterScope(nil)
   128  	c.Assert(err, jc.ErrorIsNil)
   129  	s.assertInScope(c, myRelUnit, true)
   130  
   131  	// Now we destroy mysqlService, so the relation is be set to
   132  	// dying.
   133  	err = s.mysqlService.Destroy()
   134  	c.Assert(err, jc.ErrorIsNil)
   135  	err = s.stateRelation.Refresh()
   136  	c.Assert(err, jc.ErrorIsNil)
   137  	c.Assert(s.stateRelation.Life(), gc.Equals, state.Dying)
   138  
   139  	// Enter the scope with wordpressUnit.
   140  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   141  	s.assertInScope(c, wpRelUnit, false)
   142  	err = apiRelUnit.EnterScope()
   143  	c.Assert(err, gc.NotNil)
   144  	c.Check(err, jc.Satisfies, params.IsCodeCannotEnterScope)
   145  	c.Check(err, gc.ErrorMatches, "cannot enter scope: unit or relation is not alive")
   146  }
   147  
   148  func (s *relationUnitSuite) TestEnterScopeErrCannotEnterScopeYet(c *gc.C) {
   149  	// Test the ErrCannotEnterScopeYet gets forwarded correctly.
   150  	// First we need to destroy the stateRelation.
   151  	err := s.stateRelation.Destroy()
   152  	c.Assert(err, jc.ErrorIsNil)
   153  
   154  	// Now we create a subordinate of wordpressUnit and enter scope.
   155  	subRel, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   156  	wpRelUnit, err := subRel.Unit(s.wordpressUnit)
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	s.assertInScope(c, wpRelUnit, true)
   159  
   160  	// Leave scope, destroy the subordinate and try entering again.
   161  	err = wpRelUnit.LeaveScope()
   162  	c.Assert(err, jc.ErrorIsNil)
   163  	s.assertInScope(c, wpRelUnit, false)
   164  	err = loggingSub.Destroy()
   165  	c.Assert(err, jc.ErrorIsNil)
   166  
   167  	apiUnit, err := s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag))
   168  	c.Assert(err, jc.ErrorIsNil)
   169  	apiRel, err := s.uniter.Relation(subRel.Tag().(names.RelationTag))
   170  	c.Assert(err, jc.ErrorIsNil)
   171  	apiRelUnit, err := apiRel.Unit(apiUnit)
   172  	c.Assert(err, jc.ErrorIsNil)
   173  	err = apiRelUnit.EnterScope()
   174  	c.Assert(err, gc.NotNil)
   175  	c.Check(err, jc.Satisfies, params.IsCodeCannotEnterScopeYet)
   176  	c.Check(err, gc.ErrorMatches, "cannot enter scope yet: non-alive subordinate unit has not been removed")
   177  }
   178  
   179  func (s *relationUnitSuite) TestLeaveScope(c *gc.C) {
   180  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   181  	s.assertInScope(c, wpRelUnit, false)
   182  
   183  	err := wpRelUnit.EnterScope(nil)
   184  	c.Assert(err, jc.ErrorIsNil)
   185  	s.assertInScope(c, wpRelUnit, true)
   186  
   187  	err = apiRelUnit.LeaveScope()
   188  	c.Assert(err, jc.ErrorIsNil)
   189  	s.assertInScope(c, wpRelUnit, false)
   190  }
   191  
   192  func (s *relationUnitSuite) TestSettings(c *gc.C) {
   193  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   194  	settings := map[string]interface{}{
   195  		"some":  "settings",
   196  		"other": "things",
   197  	}
   198  	err := wpRelUnit.EnterScope(settings)
   199  	c.Assert(err, jc.ErrorIsNil)
   200  	s.assertInScope(c, wpRelUnit, true)
   201  
   202  	gotSettings, err := apiRelUnit.Settings()
   203  	c.Assert(err, jc.ErrorIsNil)
   204  	c.Assert(gotSettings.Map(), gc.DeepEquals, params.Settings{
   205  		"some":  "settings",
   206  		"other": "things",
   207  	})
   208  }
   209  
   210  func (s *relationUnitSuite) TestReadSettings(c *gc.C) {
   211  	// First try to read the settings which are not set.
   212  	myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit)
   213  	c.Assert(err, jc.ErrorIsNil)
   214  	err = myRelUnit.EnterScope(nil)
   215  	c.Assert(err, jc.ErrorIsNil)
   216  	s.assertInScope(c, myRelUnit, true)
   217  
   218  	// Try reading - should be ok.
   219  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   220  	s.assertInScope(c, wpRelUnit, false)
   221  	gotSettings, err := apiRelUnit.ReadSettings("mysql/0")
   222  	c.Assert(err, jc.ErrorIsNil)
   223  	c.Assert(gotSettings, gc.HasLen, 0)
   224  
   225  	// Now leave and re-enter scope with some settings.
   226  	settings := map[string]interface{}{
   227  		"some":  "settings",
   228  		"other": "things",
   229  	}
   230  	err = myRelUnit.LeaveScope()
   231  	c.Assert(err, jc.ErrorIsNil)
   232  	s.assertInScope(c, myRelUnit, false)
   233  	err = myRelUnit.EnterScope(settings)
   234  	c.Assert(err, jc.ErrorIsNil)
   235  	s.assertInScope(c, myRelUnit, true)
   236  	gotSettings, err = apiRelUnit.ReadSettings("mysql/0")
   237  	c.Assert(err, jc.ErrorIsNil)
   238  	c.Assert(gotSettings, gc.DeepEquals, params.Settings{
   239  		"some":  "settings",
   240  		"other": "things",
   241  	})
   242  }
   243  
   244  func (s *relationUnitSuite) TestReadSettingsInvalidUnitTag(c *gc.C) {
   245  	// First try to read the settings which are not set.
   246  	myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit)
   247  	c.Assert(err, jc.ErrorIsNil)
   248  	err = myRelUnit.EnterScope(nil)
   249  	c.Assert(err, jc.ErrorIsNil)
   250  	s.assertInScope(c, myRelUnit, true)
   251  
   252  	// Try reading - should be ok.
   253  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   254  	s.assertInScope(c, wpRelUnit, false)
   255  	_, err = apiRelUnit.ReadSettings("mysql")
   256  	c.Assert(err, gc.ErrorMatches, "\"mysql\" is not a valid unit")
   257  }
   258  
   259  func (s *relationUnitSuite) TestWatchRelationUnits(c *gc.C) {
   260  	// Enter scope with mysqlUnit.
   261  	myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit)
   262  	c.Assert(err, jc.ErrorIsNil)
   263  	err = myRelUnit.EnterScope(nil)
   264  	c.Assert(err, jc.ErrorIsNil)
   265  	s.assertInScope(c, myRelUnit, true)
   266  
   267  	apiRel, err := s.uniter.Relation(s.stateRelation.Tag().(names.RelationTag))
   268  	c.Assert(err, jc.ErrorIsNil)
   269  	apiUnit, err := s.uniter.Unit(names.NewUnitTag("wordpress/0"))
   270  	c.Assert(err, jc.ErrorIsNil)
   271  	apiRelUnit, err := apiRel.Unit(apiUnit)
   272  	c.Assert(err, jc.ErrorIsNil)
   273  
   274  	w, err := apiRelUnit.Watch()
   275  	wc := watchertest.NewRelationUnitsWatcherC(c, w, s.BackingState.StartSync)
   276  	defer wc.AssertStops()
   277  
   278  	// Initial event.
   279  	wc.AssertChange([]string{"mysql/0"}, nil)
   280  
   281  	// Leave scope with mysqlUnit, check it's detected.
   282  	err = myRelUnit.LeaveScope()
   283  	c.Assert(err, jc.ErrorIsNil)
   284  	s.assertInScope(c, myRelUnit, false)
   285  	wc.AssertChange(nil, []string{"mysql/0"})
   286  
   287  	// Non-change is not reported.
   288  	err = myRelUnit.LeaveScope()
   289  	c.Assert(err, jc.ErrorIsNil)
   290  	wc.AssertNoChange()
   291  }