github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/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  	"github.com/juju/names"
     8  	jc "github.com/juju/testing/checkers"
     9  	gc "gopkg.in/check.v1"
    10  	"gopkg.in/juju/charm.v4"
    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  	statetesting "github.com/juju/juju/state/testing"
    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.Service
    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.SetAddresses(network.NewAddress("1.2.3.4", network.ScopeCloudLocal))
   102  	c.Assert(err, jc.ErrorIsNil)
   103  	address, err = apiRelUnit.PrivateAddress()
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	c.Assert(address, gc.Equals, "1.2.3.4")
   106  }
   107  
   108  func (s *relationUnitSuite) TestEnterScopeSuccessfully(c *gc.C) {
   109  	// NOTE: This test is not as exhaustive as the ones in state.
   110  	// Here, we just check the success case, while the two error
   111  	// cases are tested separately.
   112  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   113  	s.assertInScope(c, wpRelUnit, false)
   114  
   115  	err := apiRelUnit.EnterScope()
   116  	c.Assert(err, jc.ErrorIsNil)
   117  	s.assertInScope(c, wpRelUnit, true)
   118  }
   119  
   120  func (s *relationUnitSuite) TestEnterScopeErrCannotEnterScope(c *gc.C) {
   121  	// Test the ErrCannotEnterScope gets forwarded correctly.
   122  	// We need to enter the scope wit the other unit first.
   123  	myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit)
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	err = myRelUnit.EnterScope(nil)
   126  	c.Assert(err, jc.ErrorIsNil)
   127  	s.assertInScope(c, myRelUnit, true)
   128  
   129  	// Now we destroy mysqlService, so the relation is be set to
   130  	// dying.
   131  	err = s.mysqlService.Destroy()
   132  	c.Assert(err, jc.ErrorIsNil)
   133  	err = s.stateRelation.Refresh()
   134  	c.Assert(err, jc.ErrorIsNil)
   135  	c.Assert(s.stateRelation.Life(), gc.Equals, state.Dying)
   136  
   137  	// Enter the scope with wordpressUnit.
   138  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   139  	s.assertInScope(c, wpRelUnit, false)
   140  	err = apiRelUnit.EnterScope()
   141  	c.Assert(err, gc.NotNil)
   142  	c.Check(err, jc.Satisfies, params.IsCodeCannotEnterScope)
   143  	c.Check(err, gc.ErrorMatches, "cannot enter scope: unit or relation is not alive")
   144  }
   145  
   146  func (s *relationUnitSuite) TestEnterScopeErrCannotEnterScopeYet(c *gc.C) {
   147  	// Test the ErrCannotEnterScopeYet gets forwarded correctly.
   148  	// First we need to destroy the stateRelation.
   149  	err := s.stateRelation.Destroy()
   150  	c.Assert(err, jc.ErrorIsNil)
   151  
   152  	// Now we create a subordinate of wordpressUnit and enter scope.
   153  	subRel, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   154  	wpRelUnit, err := subRel.Unit(s.wordpressUnit)
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	s.assertInScope(c, wpRelUnit, true)
   157  
   158  	// Leave scope, destroy the subordinate and try entering again.
   159  	err = wpRelUnit.LeaveScope()
   160  	c.Assert(err, jc.ErrorIsNil)
   161  	s.assertInScope(c, wpRelUnit, false)
   162  	err = loggingSub.Destroy()
   163  	c.Assert(err, jc.ErrorIsNil)
   164  
   165  	apiUnit, err := s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag))
   166  	c.Assert(err, jc.ErrorIsNil)
   167  	apiRel, err := s.uniter.Relation(subRel.Tag().(names.RelationTag))
   168  	c.Assert(err, jc.ErrorIsNil)
   169  	apiRelUnit, err := apiRel.Unit(apiUnit)
   170  	c.Assert(err, jc.ErrorIsNil)
   171  	err = apiRelUnit.EnterScope()
   172  	c.Assert(err, gc.NotNil)
   173  	c.Check(err, jc.Satisfies, params.IsCodeCannotEnterScopeYet)
   174  	c.Check(err, gc.ErrorMatches, "cannot enter scope yet: non-alive subordinate unit has not been removed")
   175  }
   176  
   177  func (s *relationUnitSuite) TestLeaveScope(c *gc.C) {
   178  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   179  	s.assertInScope(c, wpRelUnit, false)
   180  
   181  	err := wpRelUnit.EnterScope(nil)
   182  	c.Assert(err, jc.ErrorIsNil)
   183  	s.assertInScope(c, wpRelUnit, true)
   184  
   185  	err = apiRelUnit.LeaveScope()
   186  	c.Assert(err, jc.ErrorIsNil)
   187  	s.assertInScope(c, wpRelUnit, false)
   188  }
   189  
   190  func (s *relationUnitSuite) TestSettings(c *gc.C) {
   191  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   192  	settings := map[string]interface{}{
   193  		"some":  "settings",
   194  		"other": "things",
   195  	}
   196  	err := wpRelUnit.EnterScope(settings)
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	s.assertInScope(c, wpRelUnit, true)
   199  
   200  	gotSettings, err := apiRelUnit.Settings()
   201  	c.Assert(err, jc.ErrorIsNil)
   202  	c.Assert(gotSettings.Map(), gc.DeepEquals, params.Settings{
   203  		"some":  "settings",
   204  		"other": "things",
   205  	})
   206  }
   207  
   208  func (s *relationUnitSuite) TestReadSettings(c *gc.C) {
   209  	// First try to read the settings which are not set.
   210  	myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit)
   211  	c.Assert(err, jc.ErrorIsNil)
   212  	err = myRelUnit.EnterScope(nil)
   213  	c.Assert(err, jc.ErrorIsNil)
   214  	s.assertInScope(c, myRelUnit, true)
   215  
   216  	// Try reading - should be ok.
   217  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   218  	s.assertInScope(c, wpRelUnit, false)
   219  	gotSettings, err := apiRelUnit.ReadSettings("mysql/0")
   220  	c.Assert(err, jc.ErrorIsNil)
   221  	c.Assert(gotSettings, gc.HasLen, 0)
   222  
   223  	// Now leave and re-enter scope with some settings.
   224  	settings := map[string]interface{}{
   225  		"some":  "settings",
   226  		"other": "things",
   227  	}
   228  	err = myRelUnit.LeaveScope()
   229  	c.Assert(err, jc.ErrorIsNil)
   230  	s.assertInScope(c, myRelUnit, false)
   231  	err = myRelUnit.EnterScope(settings)
   232  	c.Assert(err, jc.ErrorIsNil)
   233  	s.assertInScope(c, myRelUnit, true)
   234  	gotSettings, err = apiRelUnit.ReadSettings("mysql/0")
   235  	c.Assert(err, jc.ErrorIsNil)
   236  	c.Assert(gotSettings, gc.DeepEquals, params.Settings{
   237  		"some":  "settings",
   238  		"other": "things",
   239  	})
   240  }
   241  
   242  func (s *relationUnitSuite) TestReadSettingsInvalidUnitTag(c *gc.C) {
   243  	// First try to read the settings which are not set.
   244  	myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit)
   245  	c.Assert(err, jc.ErrorIsNil)
   246  	err = myRelUnit.EnterScope(nil)
   247  	c.Assert(err, jc.ErrorIsNil)
   248  	s.assertInScope(c, myRelUnit, true)
   249  
   250  	// Try reading - should be ok.
   251  	wpRelUnit, apiRelUnit := s.getRelationUnits(c)
   252  	s.assertInScope(c, wpRelUnit, false)
   253  	_, err = apiRelUnit.ReadSettings("mysql")
   254  	c.Assert(err, gc.ErrorMatches, "\"mysql\" is not a valid unit")
   255  }
   256  
   257  func (s *relationUnitSuite) TestWatchRelationUnits(c *gc.C) {
   258  	// Enter scope with mysqlUnit.
   259  	myRelUnit, err := s.stateRelation.Unit(s.mysqlUnit)
   260  	c.Assert(err, jc.ErrorIsNil)
   261  	err = myRelUnit.EnterScope(nil)
   262  	c.Assert(err, jc.ErrorIsNil)
   263  	s.assertInScope(c, myRelUnit, true)
   264  
   265  	apiRel, err := s.uniter.Relation(s.stateRelation.Tag().(names.RelationTag))
   266  	c.Assert(err, jc.ErrorIsNil)
   267  	apiUnit, err := s.uniter.Unit(names.NewUnitTag("wordpress/0"))
   268  	c.Assert(err, jc.ErrorIsNil)
   269  	apiRelUnit, err := apiRel.Unit(apiUnit)
   270  	c.Assert(err, jc.ErrorIsNil)
   271  
   272  	w, err := apiRelUnit.Watch()
   273  	defer statetesting.AssertStop(c, w)
   274  	wc := statetesting.NewRelationUnitsWatcherC(c, s.BackingState, w)
   275  
   276  	// Initial event.
   277  	wc.AssertChange([]string{"mysql/0"}, nil)
   278  
   279  	// Leave scope with mysqlUnit, check it's detected.
   280  	err = myRelUnit.LeaveScope()
   281  	c.Assert(err, jc.ErrorIsNil)
   282  	s.assertInScope(c, myRelUnit, false)
   283  	wc.AssertChange(nil, []string{"mysql/0"})
   284  
   285  	// Non-change is not reported.
   286  	err = myRelUnit.LeaveScope()
   287  	c.Assert(err, jc.ErrorIsNil)
   288  	wc.AssertNoChange()
   289  
   290  	// NOTE: This test is not as exhaustive as the one in state,
   291  	// because the watcher is already tested there. Here we just
   292  	// ensure we get the events when we expect them and don't get
   293  	// them when they're not expected.
   294  
   295  	statetesting.AssertStop(c, w)
   296  	wc.AssertClosed()
   297  }