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