github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/relationunit_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"strconv"
    10  	"time"
    11  
    12  	"github.com/juju/charm/v12"
    13  	"github.com/juju/collections/set"
    14  	"github.com/juju/errors"
    15  	"github.com/juju/loggo"
    16  	jc "github.com/juju/testing/checkers"
    17  	"golang.org/x/sync/errgroup"
    18  	gc "gopkg.in/check.v1"
    19  
    20  	"github.com/juju/juju/core/network"
    21  	"github.com/juju/juju/state"
    22  	stateerrors "github.com/juju/juju/state/errors"
    23  	"github.com/juju/juju/state/testing"
    24  	coretesting "github.com/juju/juju/testing"
    25  )
    26  
    27  type RUs []*state.RelationUnit
    28  
    29  type RelationUnitSuite struct {
    30  	ConnSuite
    31  }
    32  
    33  var _ = gc.Suite(&RelationUnitSuite{})
    34  
    35  func assertInScope(c *gc.C, ru *state.RelationUnit) {
    36  	ok, err := ru.InScope()
    37  	c.Assert(err, jc.ErrorIsNil)
    38  	c.Assert(ok, jc.IsTrue)
    39  }
    40  
    41  func assertNotInScope(c *gc.C, ru *state.RelationUnit) {
    42  	assertNotJoined(c, ru)
    43  	ok, err := ru.InScope()
    44  	c.Assert(err, jc.ErrorIsNil)
    45  	c.Assert(ok, jc.IsFalse)
    46  }
    47  
    48  func assertJoined(c *gc.C, ru *state.RelationUnit) {
    49  	assertInScope(c, ru)
    50  	ok, err := ru.Joined()
    51  	c.Assert(err, jc.ErrorIsNil)
    52  	c.Assert(ok, jc.IsTrue)
    53  }
    54  
    55  func assertNotJoined(c *gc.C, ru *state.RelationUnit) {
    56  	ok, err := ru.Joined()
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	c.Assert(ok, jc.IsFalse)
    59  }
    60  
    61  func (s *RelationUnitSuite) TestReadSettingsErrors(c *gc.C) {
    62  	riak := s.AddTestingApplication(c, "riak", s.AddTestingCharm(c, "riak"))
    63  	u0, err := riak.AddUnit(state.AddUnitParams{})
    64  	c.Assert(err, jc.ErrorIsNil)
    65  	riakEP, err := riak.Endpoint("ring")
    66  	c.Assert(err, jc.ErrorIsNil)
    67  	rel, err := s.State.EndpointsRelation(riakEP)
    68  	c.Assert(err, jc.ErrorIsNil)
    69  	ru0, err := rel.Unit(u0)
    70  	c.Assert(err, jc.ErrorIsNil)
    71  
    72  	_, err = ru0.ReadSettings("nonsense")
    73  	c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "nonsense" in relation "riak:ring": "nonsense" is not a valid unit name`)
    74  	_, err = ru0.ReadSettings("unknown/0")
    75  	c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "unknown/0" in relation "riak:ring": application "unknown" is not a member of "riak:ring"`)
    76  	_, err = ru0.ReadSettings("riak/pressure")
    77  	c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/pressure" in relation "riak:ring": "riak/pressure" is not a valid unit name`)
    78  	_, err = ru0.ReadSettings("riak/1")
    79  	c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/1" in relation "riak:ring": unit "riak/1": settings not found`)
    80  }
    81  
    82  func (s *RelationUnitSuite) TestCounterpartApplications(c *gc.C) {
    83  	prr := newProReqRelation(c, &s.ConnSuite, charm.ScopeGlobal)
    84  
    85  	c.Check(prr.pru0.CounterpartApplications(), jc.DeepEquals, []string{"wordpress"})
    86  	c.Check(prr.pru1.CounterpartApplications(), jc.DeepEquals, []string{"wordpress"})
    87  	c.Check(prr.rru0.CounterpartApplications(), jc.DeepEquals, []string{"mysql"})
    88  	c.Check(prr.rru1.CounterpartApplications(), jc.DeepEquals, []string{"mysql"})
    89  }
    90  
    91  func (s *RelationUnitSuite) TestCounterpartApplicationsContainerScope(c *gc.C) {
    92  	prr := newProReqRelation(c, &s.ConnSuite, charm.ScopeContainer)
    93  
    94  	// The counterpart application for container scope is still the same
    95  	c.Check(prr.pru0.CounterpartApplications(), jc.DeepEquals, []string{"logging"})
    96  	c.Check(prr.pru1.CounterpartApplications(), jc.DeepEquals, []string{"logging"})
    97  	c.Check(prr.rru0.CounterpartApplications(), jc.DeepEquals, []string{"mysql"})
    98  	c.Check(prr.rru1.CounterpartApplications(), jc.DeepEquals, []string{"mysql"})
    99  }
   100  
   101  func (s *RelationUnitSuite) TestCounterpartApplicationsPeer(c *gc.C) {
   102  	pr := newPeerRelation(c, s.State)
   103  	c.Check(pr.ru0.CounterpartApplications(), jc.DeepEquals, []string{"riak"})
   104  	c.Check(pr.ru1.CounterpartApplications(), jc.DeepEquals, []string{"riak"})
   105  	c.Check(pr.ru2.CounterpartApplications(), jc.DeepEquals, []string{"riak"})
   106  	c.Check(pr.ru3.CounterpartApplications(), jc.DeepEquals, []string{"riak"})
   107  }
   108  
   109  func (s *RelationUnitSuite) TestPeerSettings(c *gc.C) {
   110  	pr := newPeerRelation(c, s.State)
   111  	rus := RUs{pr.ru0, pr.ru1}
   112  
   113  	// Check missing settings cannot be read by any RU.
   114  	for _, ru := range rus {
   115  		_, err := ru.ReadSettings("riak/0")
   116  		c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/0" in relation "riak:ring": unit "riak/0": settings not found`)
   117  	}
   118  
   119  	// Add settings for one RU.
   120  	assertNotInScope(c, pr.ru0)
   121  	err := pr.ru0.EnterScope(map[string]interface{}{"gene": "kelly"})
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	node, err := pr.ru0.Settings()
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	node.Set("meme", "socially-awkward-penguin")
   126  	_, err = node.Write()
   127  	c.Assert(err, jc.ErrorIsNil)
   128  	normal := map[string]interface{}{
   129  		"gene": "kelly",
   130  		"meme": "socially-awkward-penguin",
   131  	}
   132  
   133  	// Check settings can be read by every RU.
   134  	assertSettings := func(u *state.Unit, expect map[string]interface{}) {
   135  		for _, ru := range rus {
   136  			m, err := ru.ReadSettings(u.Name())
   137  			c.Assert(err, jc.ErrorIsNil)
   138  			c.Assert(m, gc.DeepEquals, expect)
   139  		}
   140  	}
   141  	assertSettings(pr.u0, normal)
   142  	assertJoined(c, pr.ru0)
   143  
   144  	// Check that EnterScope when scope already entered does not touch
   145  	// settings at all.
   146  	changed := map[string]interface{}{"foo": "bar"}
   147  	err = pr.ru0.EnterScope(changed)
   148  	c.Assert(err, jc.ErrorIsNil)
   149  	assertSettings(pr.u0, normal)
   150  	assertJoined(c, pr.ru0)
   151  
   152  	// Leave scope, check settings are still as accessible as before.
   153  	err = pr.ru0.LeaveScope()
   154  	c.Assert(err, jc.ErrorIsNil)
   155  	assertSettings(pr.u0, normal)
   156  	assertNotInScope(c, pr.ru0)
   157  
   158  	// Re-enter scope with changed settings, and check they completely overwrite
   159  	// the old ones.
   160  	err = pr.ru0.EnterScope(changed)
   161  	c.Assert(err, jc.ErrorIsNil)
   162  	assertSettings(pr.u0, changed)
   163  	assertJoined(c, pr.ru0)
   164  
   165  	// Leave and re-enter with nil nettings, and check they overwrite to become
   166  	// an empty map.
   167  	err = pr.ru0.LeaveScope()
   168  	c.Assert(err, jc.ErrorIsNil)
   169  	assertNotInScope(c, pr.ru0)
   170  	err = pr.ru0.EnterScope(nil)
   171  	c.Assert(err, jc.ErrorIsNil)
   172  	assertSettings(pr.u0, map[string]interface{}{})
   173  	assertJoined(c, pr.ru0)
   174  
   175  	// Check that entering scope for the first time with nil settings works correctly.
   176  	assertNotInScope(c, pr.ru1)
   177  	err = pr.ru1.EnterScope(nil)
   178  	c.Assert(err, jc.ErrorIsNil)
   179  	assertSettings(pr.u1, map[string]interface{}{})
   180  	assertJoined(c, pr.ru1)
   181  }
   182  
   183  func (s *RelationUnitSuite) TestRemoteUnitErrors(c *gc.C) {
   184  	_, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
   185  		Name:        "mysql",
   186  		SourceModel: coretesting.ModelTag,
   187  		Endpoints: []charm.Relation{{
   188  			Interface: "mysql",
   189  			Name:      "server",
   190  			Role:      charm.RoleProvider,
   191  			Scope:     charm.ScopeGlobal,
   192  		}}})
   193  	c.Assert(err, jc.ErrorIsNil)
   194  
   195  	_, err = s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
   196  		Name:        "mysql1",
   197  		SourceModel: coretesting.ModelTag,
   198  		Endpoints: []charm.Relation{{
   199  			Interface: "mysql",
   200  			Name:      "server",
   201  			Role:      charm.RoleProvider,
   202  			Scope:     charm.ScopeGlobal,
   203  		}}})
   204  	c.Assert(err, jc.ErrorIsNil)
   205  	s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   206  
   207  	eps, err := s.State.InferEndpoints("mysql", "wordpress")
   208  	c.Assert(err, jc.ErrorIsNil)
   209  	rel, err := s.State.AddRelation(eps...)
   210  	c.Assert(err, jc.ErrorIsNil)
   211  
   212  	_, err = rel.RemoteUnit("mysql")
   213  	c.Assert(err, gc.ErrorMatches, `"mysql" is not a valid unit name`)
   214  
   215  	_, err = rel.RemoteUnit("wordpress/0")
   216  	c.Assert(err, gc.ErrorMatches, `saas application "wordpress" not found`)
   217  
   218  	_, err = rel.RemoteUnit("mysql1/0")
   219  	c.Assert(err, gc.ErrorMatches, `application "mysql1" is not a member of "wordpress:db mysql:server"`)
   220  }
   221  
   222  func (s *RelationUnitSuite) TestAllRemoteUnits(c *gc.C) {
   223  	_, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
   224  		Name:        "mysql",
   225  		SourceModel: coretesting.ModelTag,
   226  		Endpoints: []charm.Relation{{
   227  			Interface: "mysql",
   228  			Name:      "server",
   229  			Role:      charm.RoleProvider,
   230  			Scope:     charm.ScopeGlobal,
   231  		}}})
   232  	c.Assert(err, jc.ErrorIsNil)
   233  	_, err = s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
   234  		Name:        "another",
   235  		SourceModel: coretesting.ModelTag,
   236  		Endpoints: []charm.Relation{{
   237  			Interface: "mysql",
   238  			Name:      "server",
   239  			Role:      charm.RoleProvider,
   240  			Scope:     charm.ScopeGlobal,
   241  		}}})
   242  	c.Assert(err, jc.ErrorIsNil)
   243  	s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   244  
   245  	eps, err := s.State.InferEndpoints("mysql", "wordpress")
   246  	c.Assert(err, jc.ErrorIsNil)
   247  	rel, err := s.State.AddRelation(eps...)
   248  	c.Assert(err, jc.ErrorIsNil)
   249  
   250  	ru1 := addRemoteRU(c, rel, "mysql/0")
   251  	err = ru1.EnterScope(nil)
   252  	c.Assert(err, jc.ErrorIsNil)
   253  	ru2 := addRemoteRU(c, rel, "mysql/1")
   254  	err = ru2.EnterScope(nil)
   255  	c.Assert(err, jc.ErrorIsNil)
   256  
   257  	_, err = rel.AllRemoteUnits("wordpress")
   258  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   259  	_, err = rel.AllRemoteUnits("another")
   260  	c.Assert(err, gc.ErrorMatches, `application "another" is not a member of "wordpress:db mysql:server"`)
   261  	all, err := rel.AllRemoteUnits("mysql")
   262  	c.Assert(err, jc.ErrorIsNil)
   263  	c.Assert(all, gc.HasLen, 2)
   264  	c.Assert(all, jc.SameContents, []*state.RelationUnit{ru1, ru2})
   265  }
   266  
   267  func (s *RelationUnitSuite) TestProReqSettings(c *gc.C) {
   268  	prr := newProReqRelation(c, &s.ConnSuite, charm.ScopeGlobal)
   269  	s.testProReqSettings(c, prr.pru0, prr.pru1, prr.rru0, prr.rru1)
   270  }
   271  
   272  func (s *RelationUnitSuite) TestRemoteProReqSettings(c *gc.C) {
   273  	prr := newRemoteProReqRelation(c, &s.ConnSuite)
   274  	s.testProReqSettings(c, prr.pru0, prr.pru1, prr.rru0, prr.rru1)
   275  }
   276  
   277  func (s *RelationUnitSuite) testProReqSettings(c *gc.C, pru0, pru1, rru0, rru1 *state.RelationUnit) {
   278  	rus := RUs{pru0, pru1, rru0, rru1}
   279  
   280  	// Check missing settings cannot be read by any RU.
   281  	for _, ru := range rus {
   282  		_, err := ru.ReadSettings("mysql/0")
   283  		c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "mysql/0" in relation "wordpress:db mysql:server": unit "mysql/0": settings not found`)
   284  	}
   285  
   286  	// Add settings for one RU.
   287  	assertNotInScope(c, pru0)
   288  	err := pru0.EnterScope(map[string]interface{}{"gene": "simmons"})
   289  	c.Assert(err, jc.ErrorIsNil)
   290  	node, err := pru0.Settings()
   291  	c.Assert(err, jc.ErrorIsNil)
   292  	node.Set("meme", "foul-bachelor-frog")
   293  	_, err = node.Write()
   294  	c.Assert(err, jc.ErrorIsNil)
   295  	assertJoined(c, pru0)
   296  
   297  	// Check settings can be read by every RU.
   298  	for _, ru := range rus {
   299  		m, err := ru.ReadSettings("mysql/0")
   300  		c.Assert(err, jc.ErrorIsNil)
   301  		c.Assert(m["gene"], gc.Equals, "simmons")
   302  		c.Assert(m["meme"], gc.Equals, "foul-bachelor-frog")
   303  	}
   304  }
   305  
   306  func (s *RelationUnitSuite) TestContainerSettings(c *gc.C) {
   307  	prr := newProReqRelation(c, &s.ConnSuite, charm.ScopeContainer)
   308  	rus := RUs{prr.pru0, prr.pru1, prr.rru0, prr.rru1}
   309  
   310  	// Check missing settings cannot be read by any RU.
   311  	for _, ru := range rus {
   312  		_, err := ru.ReadSettings("logging/0")
   313  		c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "logging/0" in relation "logging:info mysql:juju-info": unit "logging/0": settings not found`)
   314  	}
   315  
   316  	// Add settings for one RU.
   317  	assertNotInScope(c, prr.pru0)
   318  	err := prr.pru0.EnterScope(map[string]interface{}{"gene": "hackman"})
   319  	c.Assert(err, jc.ErrorIsNil)
   320  	node, err := prr.pru0.Settings()
   321  	c.Assert(err, jc.ErrorIsNil)
   322  	node.Set("meme", "foul-bachelor-frog")
   323  	_, err = node.Write()
   324  	c.Assert(err, jc.ErrorIsNil)
   325  	assertJoined(c, prr.pru0)
   326  
   327  	// Check settings can be read by RUs in the same container.
   328  	rus0 := RUs{prr.pru0, prr.rru0}
   329  	for _, ru := range rus0 {
   330  		m, err := ru.ReadSettings("mysql/0")
   331  		c.Assert(err, jc.ErrorIsNil)
   332  		c.Assert(m["gene"], gc.Equals, "hackman")
   333  		c.Assert(m["meme"], gc.Equals, "foul-bachelor-frog")
   334  	}
   335  
   336  	// Check settings are still inaccessible to RUs outside that container
   337  	rus1 := RUs{prr.pru1, prr.rru1}
   338  	for _, ru := range rus1 {
   339  		_, err := ru.ReadSettings("mysql/0")
   340  		c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "mysql/0" in relation "logging:info mysql:juju-info": unit "mysql/0": settings not found`)
   341  	}
   342  }
   343  
   344  func (s *RelationUnitSuite) TestContainerCreateSubordinate(c *gc.C) {
   345  	papp := s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
   346  	rapp := s.AddTestingApplication(c, "logging", s.AddTestingCharm(c, "logging"))
   347  	eps, err := s.State.InferEndpoints("mysql", "logging")
   348  	c.Assert(err, jc.ErrorIsNil)
   349  	rel, err := s.State.AddRelation(eps...)
   350  	c.Assert(err, jc.ErrorIsNil)
   351  	punit, err := papp.AddUnit(state.AddUnitParams{})
   352  	c.Assert(err, jc.ErrorIsNil)
   353  	pru, err := rel.Unit(punit)
   354  	c.Assert(err, jc.ErrorIsNil)
   355  
   356  	// Check that no units of the subordinate application exist.
   357  	assertSubCount := func(expect int) []*state.Unit {
   358  		runits, err := rapp.AllUnits()
   359  		c.Assert(err, jc.ErrorIsNil)
   360  		c.Assert(runits, gc.HasLen, expect)
   361  		return runits
   362  	}
   363  	assertSubCount(0)
   364  
   365  	// Enter principal's scope and check a subordinate was created.
   366  	assertNotInScope(c, pru)
   367  	err = pru.EnterScope(nil)
   368  	c.Assert(err, jc.ErrorIsNil)
   369  	assertSubCount(1)
   370  	assertJoined(c, pru)
   371  
   372  	// Enter principal scope again and check no more subordinates created.
   373  	err = pru.EnterScope(nil)
   374  	c.Assert(err, jc.ErrorIsNil)
   375  	assertSubCount(1)
   376  	assertJoined(c, pru)
   377  
   378  	// Leave principal scope, then re-enter, and check that still no further
   379  	// subordinates are created.
   380  	err = pru.LeaveScope()
   381  	c.Assert(err, jc.ErrorIsNil)
   382  	assertNotInScope(c, pru)
   383  	err = pru.EnterScope(nil)
   384  	c.Assert(err, jc.ErrorIsNil)
   385  	runits := assertSubCount(1)
   386  	assertJoined(c, pru)
   387  
   388  	// Set the subordinate to Dying, and enter scope again; because the scope
   389  	// is already entered, no error is returned.
   390  	runit := runits[0]
   391  	err = runit.Destroy()
   392  	c.Assert(err, jc.ErrorIsNil)
   393  	err = pru.EnterScope(nil)
   394  	c.Assert(err, jc.ErrorIsNil)
   395  	assertJoined(c, pru)
   396  
   397  	// Leave scope, then try to enter again with the Dying subordinate.
   398  	err = pru.LeaveScope()
   399  	c.Assert(err, jc.ErrorIsNil)
   400  	assertNotInScope(c, pru)
   401  	err = pru.EnterScope(nil)
   402  	c.Assert(err, gc.ErrorMatches, ".*"+stateerrors.ErrCannotEnterScopeYet.Error())
   403  	assertNotInScope(c, pru)
   404  
   405  	// Remove the subordinate, and enter scope again; this should work, and
   406  	// create a new subordinate.
   407  	err = runit.EnsureDead()
   408  	c.Assert(err, jc.ErrorIsNil)
   409  	err = runit.Remove()
   410  	c.Assert(err, jc.ErrorIsNil)
   411  	assertSubCount(0)
   412  	assertNotInScope(c, pru)
   413  	err = pru.EnterScope(nil)
   414  	c.Assert(err, jc.ErrorIsNil)
   415  	assertSubCount(1)
   416  	assertJoined(c, pru)
   417  }
   418  
   419  func (s *RelationUnitSuite) TestDestroyRelationWithUnitsInScope(c *gc.C) {
   420  	pr := newPeerRelation(c, s.State)
   421  	preventPeerUnitsDestroyRemove(c, pr)
   422  	rel := pr.ru0.Relation()
   423  
   424  	// Enter two units, and check that Destroying the application sets the
   425  	// relation to Dying (rather than removing it directly).
   426  	assertNotInScope(c, pr.ru0)
   427  	err := pr.ru0.EnterScope(map[string]interface{}{"some": "settings"})
   428  	c.Assert(err, jc.ErrorIsNil)
   429  	assertJoined(c, pr.ru0)
   430  	assertNotInScope(c, pr.ru1)
   431  	err = pr.ru1.EnterScope(nil)
   432  	c.Assert(err, jc.ErrorIsNil)
   433  	assertJoined(c, pr.ru1)
   434  	err = pr.app.Destroy()
   435  	c.Assert(err, jc.ErrorIsNil)
   436  	err = rel.Refresh()
   437  	c.Assert(err, jc.ErrorIsNil)
   438  	c.Assert(rel.Life(), gc.Equals, state.Dying)
   439  
   440  	// Check that we can't add a new unit now.
   441  	assertNotInScope(c, pr.ru2)
   442  	err = pr.ru2.EnterScope(nil)
   443  	c.Assert(err, gc.ErrorMatches, ".*"+stateerrors.ErrCannotEnterScope.Error())
   444  	assertNotInScope(c, pr.ru2)
   445  
   446  	// Check that we created no settings for the unit we failed to add.
   447  	_, err = pr.ru0.ReadSettings("riak/2")
   448  	c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/2" in relation "riak:ring": unit "riak/2": settings not found`)
   449  
   450  	// ru0 leaves the scope; check that application Destroy is still a no-op.
   451  	assertJoined(c, pr.ru0)
   452  	err = pr.ru0.LeaveScope()
   453  	c.Assert(err, jc.ErrorIsNil)
   454  	assertNotInScope(c, pr.ru0)
   455  	err = pr.app.Destroy()
   456  	c.Assert(err, jc.ErrorIsNil)
   457  
   458  	// Check that unit settings for the original unit still exist, and have
   459  	// not yet been marked for deletion.
   460  	err = s.State.Cleanup()
   461  	c.Assert(err, jc.ErrorIsNil)
   462  	assertSettings := func() {
   463  		settings, err := pr.ru1.ReadSettings("riak/0")
   464  		c.Assert(err, jc.ErrorIsNil)
   465  		c.Assert(settings, gc.DeepEquals, map[string]interface{}{"some": "settings"})
   466  	}
   467  	assertSettings()
   468  
   469  	// The final unit leaves the scope, and cleans up after itself.
   470  	assertJoined(c, pr.ru1)
   471  	err = pr.ru1.LeaveScope()
   472  	c.Assert(err, jc.ErrorIsNil)
   473  	assertNotInScope(c, pr.ru1)
   474  	err = rel.Refresh()
   475  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   476  
   477  	// The settings were not themselves actually deleted yet...
   478  	assertSettings()
   479  
   480  	// ...but they were scheduled for deletion.
   481  	err = s.State.Cleanup()
   482  	c.Assert(err, jc.ErrorIsNil)
   483  	_, err = pr.ru1.ReadSettings("riak/0")
   484  	c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/0" in relation "riak:ring": unit "riak/0": settings not found`)
   485  }
   486  
   487  func (s *RelationUnitSuite) TestAliveRelationScope(c *gc.C) {
   488  	pr := newPeerRelation(c, s.State)
   489  	rel := pr.ru0.Relation()
   490  
   491  	// Two units enter...
   492  	assertNotInScope(c, pr.ru0)
   493  	err := pr.ru0.EnterScope(nil)
   494  	c.Assert(err, jc.ErrorIsNil)
   495  	assertJoined(c, pr.ru0)
   496  	assertNotInScope(c, pr.ru1)
   497  	err = pr.ru1.EnterScope(nil)
   498  	c.Assert(err, jc.ErrorIsNil)
   499  	assertJoined(c, pr.ru1)
   500  
   501  	// One unit becomes Dying, then re-enters the scope; this is not an error,
   502  	// because the state is already as requested.
   503  	err = pr.u0.Destroy()
   504  	c.Assert(err, jc.ErrorIsNil)
   505  	err = pr.ru0.EnterScope(nil)
   506  	c.Assert(err, jc.ErrorIsNil)
   507  	assertJoined(c, pr.ru0)
   508  
   509  	// Two units leave...
   510  	err = pr.ru0.LeaveScope()
   511  	c.Assert(err, jc.ErrorIsNil)
   512  	assertNotInScope(c, pr.ru0)
   513  	err = pr.ru1.LeaveScope()
   514  	c.Assert(err, jc.ErrorIsNil)
   515  	assertNotInScope(c, pr.ru1)
   516  
   517  	// The relation scope is empty, but the relation is still alive...
   518  	err = rel.Refresh()
   519  	c.Assert(err, jc.ErrorIsNil)
   520  	c.Assert(rel.Life(), gc.Equals, state.Alive)
   521  
   522  	// ...and new units can still join it...
   523  	assertNotInScope(c, pr.ru2)
   524  	err = pr.ru2.EnterScope(nil)
   525  	c.Assert(err, jc.ErrorIsNil)
   526  	assertJoined(c, pr.ru2)
   527  
   528  	// ...but Dying units cannot.
   529  	err = pr.u3.Destroy()
   530  	c.Assert(err, jc.ErrorIsNil)
   531  	assertNotInScope(c, pr.ru3)
   532  	err = pr.ru3.EnterScope(nil)
   533  	c.Assert(err, gc.ErrorMatches, ".*"+stateerrors.ErrCannotEnterScope.Error())
   534  	assertNotInScope(c, pr.ru3)
   535  }
   536  
   537  func (s *StateSuite) TestWatchScopeDiesOnStateClose(c *gc.C) {
   538  	testWatcherDiesWhenStateCloses(c, s.Session, s.modelTag, s.State.ControllerTag(), func(c *gc.C, st *state.State) waiter {
   539  		pr := newPeerRelation(c, st)
   540  		w := pr.ru0.WatchScope()
   541  		<-w.Changes()
   542  		return w
   543  	})
   544  }
   545  
   546  func (s *RelationUnitSuite) TestPeerWatchScope(c *gc.C) {
   547  	pr := newPeerRelation(c, s.State)
   548  
   549  	// Test empty initial event.
   550  	w0 := pr.ru0.WatchScope()
   551  	defer testing.AssertStop(c, w0)
   552  	s.assertScopeChange(c, w0, nil, nil)
   553  	s.assertNoScopeChange(c, w0)
   554  
   555  	// ru0 enters; check no change, but settings written.
   556  	assertNotInScope(c, pr.ru0)
   557  	err := pr.ru0.EnterScope(map[string]interface{}{"foo": "bar"})
   558  	c.Assert(err, jc.ErrorIsNil)
   559  	s.assertNoScopeChange(c, w0)
   560  	node, err := pr.ru0.Settings()
   561  	c.Assert(err, jc.ErrorIsNil)
   562  	c.Assert(node.Map(), gc.DeepEquals, map[string]interface{}{"foo": "bar"})
   563  	assertJoined(c, pr.ru0)
   564  
   565  	// ru1 enters; check change is observed.
   566  	assertNotInScope(c, pr.ru1)
   567  	err = pr.ru1.EnterScope(nil)
   568  	c.Assert(err, jc.ErrorIsNil)
   569  	s.assertScopeChange(c, w0, []string{"riak/1"}, nil)
   570  	s.assertNoScopeChange(c, w0)
   571  	assertJoined(c, pr.ru1)
   572  
   573  	// ru1 enters again, check no problems and no changes.
   574  	err = pr.ru1.EnterScope(nil)
   575  	c.Assert(err, jc.ErrorIsNil)
   576  	s.assertNoScopeChange(c, w0)
   577  	assertJoined(c, pr.ru1)
   578  
   579  	// Stop watching; ru2 enters.
   580  	testing.AssertStop(c, w0)
   581  	assertNotInScope(c, pr.ru2)
   582  	err = pr.ru2.EnterScope(nil)
   583  	c.Assert(err, jc.ErrorIsNil)
   584  	assertJoined(c, pr.ru2)
   585  
   586  	// Start watch again, check initial event.
   587  	w0 = pr.ru0.WatchScope()
   588  	defer testing.AssertStop(c, w0)
   589  	s.assertScopeChange(c, w0, []string{"riak/1", "riak/2"}, nil)
   590  	s.assertNoScopeChange(c, w0)
   591  
   592  	// ru1 leaves; check event.
   593  	assertJoined(c, pr.ru1)
   594  	err = pr.ru1.LeaveScope()
   595  	c.Assert(err, jc.ErrorIsNil)
   596  	s.assertScopeChange(c, w0, nil, []string{"riak/1"})
   597  	s.assertNoScopeChange(c, w0)
   598  	assertNotInScope(c, pr.ru1)
   599  
   600  	// ru1 leaves again; check no problems and no changes.
   601  	err = pr.ru1.LeaveScope()
   602  	c.Assert(err, jc.ErrorIsNil)
   603  	s.assertNoScopeChange(c, w0)
   604  	assertNotInScope(c, pr.ru1)
   605  }
   606  
   607  func (s *RelationUnitSuite) TestProReqWatchScope(c *gc.C) {
   608  	prr := newProReqRelation(c, &s.ConnSuite, charm.ScopeGlobal)
   609  	s.testProReqWatchScope(c, prr.pru0, prr.pru1, prr.rru0, prr.rru1, prr.watches)
   610  }
   611  
   612  func (s *RelationUnitSuite) TestRemoteProReqWatchScope(c *gc.C) {
   613  	prr := newRemoteProReqRelation(c, &s.ConnSuite)
   614  	s.testProReqWatchScope(c, prr.pru0, prr.pru1, prr.rru0, prr.rru1, prr.watches)
   615  }
   616  
   617  func stopAllRelationScope(c *gc.C, ws []*state.RelationScopeWatcher) {
   618  	for _, w := range ws {
   619  		testing.AssertStop(c, w)
   620  	}
   621  }
   622  
   623  func (s *RelationUnitSuite) testProReqWatchScope(
   624  	c *gc.C, pru0, pru1, rru0, rru1 *state.RelationUnit,
   625  	watches func() []*state.RelationScopeWatcher,
   626  ) {
   627  	// Test empty initial events for all RUs.
   628  	ws := watches()
   629  	defer stopAllRelationScope(c, ws)
   630  	for _, w := range ws {
   631  		s.assertScopeChange(c, w, nil, nil)
   632  	}
   633  	s.assertNoScopeChange(c, ws...)
   634  
   635  	// pru0 enters; check detected only by req RUs.
   636  	assertNotInScope(c, pru0)
   637  	err := pru0.EnterScope(nil)
   638  	c.Assert(err, jc.ErrorIsNil)
   639  	rws := func() []*state.RelationScopeWatcher {
   640  		return []*state.RelationScopeWatcher{ws[2], ws[3]}
   641  	}
   642  	for _, w := range rws() {
   643  		s.assertScopeChange(c, w, []string{"mysql/0"}, nil)
   644  	}
   645  	s.assertNoScopeChange(c, ws...)
   646  	assertJoined(c, pru0)
   647  
   648  	// req0 enters; check detected only by pro RUs.
   649  	assertNotInScope(c, rru0)
   650  	err = rru0.EnterScope(nil)
   651  	c.Assert(err, jc.ErrorIsNil)
   652  	pws := func() []*state.RelationScopeWatcher {
   653  		return []*state.RelationScopeWatcher{ws[0], ws[1]}
   654  	}
   655  	for _, w := range pws() {
   656  		s.assertScopeChange(c, w, []string{"wordpress/0"}, nil)
   657  	}
   658  	s.assertNoScopeChange(c, ws...)
   659  	assertJoined(c, rru0)
   660  
   661  	// Stop watches; remaining RUs enter.
   662  	for _, w := range ws {
   663  		testing.AssertStop(c, w)
   664  	}
   665  	assertNotInScope(c, pru1)
   666  	err = pru1.EnterScope(nil)
   667  	c.Assert(err, jc.ErrorIsNil)
   668  	assertJoined(c, pru1)
   669  	assertNotInScope(c, rru1)
   670  	err = rru1.EnterScope(nil)
   671  	c.Assert(err, jc.ErrorIsNil)
   672  	assertJoined(c, rru0)
   673  
   674  	// Start new watches, check initial events.
   675  	ws = watches()
   676  	defer stopAllRelationScope(c, ws)
   677  	for _, w := range pws() {
   678  		s.assertScopeChange(c, w, []string{"wordpress/0", "wordpress/1"}, nil)
   679  	}
   680  	for _, w := range rws() {
   681  		s.assertScopeChange(c, w, []string{"mysql/0", "mysql/1"}, nil)
   682  	}
   683  	s.assertNoScopeChange(c, ws...)
   684  
   685  	// pru0 leaves; check detected only by req RUs.
   686  	assertJoined(c, pru0)
   687  	err = pru0.LeaveScope()
   688  	c.Assert(err, jc.ErrorIsNil)
   689  	for _, w := range rws() {
   690  		s.assertScopeChange(c, w, nil, []string{"mysql/0"})
   691  	}
   692  	s.assertNoScopeChange(c, ws...)
   693  	assertNotInScope(c, pru0)
   694  
   695  	// rru0 leaves; check detected only by pro RUs.
   696  	assertJoined(c, rru0)
   697  	err = rru0.LeaveScope()
   698  	c.Assert(err, jc.ErrorIsNil)
   699  	for _, w := range pws() {
   700  		s.assertScopeChange(c, w, nil, []string{"wordpress/0"})
   701  	}
   702  	s.assertNoScopeChange(c, ws...)
   703  	assertNotInScope(c, rru0)
   704  }
   705  
   706  func (s *RelationUnitSuite) TestContainerWatchScope(c *gc.C) {
   707  	prr := newProReqRelation(c, &s.ConnSuite, charm.ScopeContainer)
   708  
   709  	// Test empty initial events for all RUs.
   710  	ws := prr.watches()
   711  	for _, w := range ws {
   712  		defer testing.AssertStop(c, w)
   713  	}
   714  	for _, w := range ws {
   715  		s.assertScopeChange(c, w, nil, nil)
   716  	}
   717  	s.assertNoScopeChange(c, ws...)
   718  
   719  	// pru0 enters; check detected only by same-container req.
   720  	assertNotInScope(c, prr.pru0)
   721  	err := prr.pru0.EnterScope(nil)
   722  	c.Assert(err, jc.ErrorIsNil)
   723  	s.assertScopeChange(c, ws[2], []string{"mysql/0"}, nil)
   724  	s.assertNoScopeChange(c, ws...)
   725  	assertJoined(c, prr.pru0)
   726  
   727  	// req1 enters; check detected only by same-container pro.
   728  	assertNotInScope(c, prr.rru1)
   729  	err = prr.rru1.EnterScope(nil)
   730  	c.Assert(err, jc.ErrorIsNil)
   731  	s.assertScopeChange(c, ws[1], []string{"logging/1"}, nil)
   732  	s.assertNoScopeChange(c, ws...)
   733  	assertJoined(c, prr.rru1)
   734  
   735  	// Stop watches; remaining RUs enter scope.
   736  	for _, w := range ws {
   737  		testing.AssertStop(c, w)
   738  	}
   739  	assertNotInScope(c, prr.pru1)
   740  	err = prr.pru1.EnterScope(nil)
   741  	c.Assert(err, jc.ErrorIsNil)
   742  	assertNotInScope(c, prr.rru0)
   743  	err = prr.rru0.EnterScope(nil)
   744  	c.Assert(err, jc.ErrorIsNil)
   745  
   746  	// Start new watches, check initial events.
   747  	ws = prr.watches()
   748  	for _, w := range ws {
   749  		defer testing.AssertStop(c, w)
   750  	}
   751  	s.assertScopeChange(c, ws[0], []string{"logging/0"}, nil)
   752  	s.assertScopeChange(c, ws[1], []string{"logging/1"}, nil)
   753  	s.assertScopeChange(c, ws[2], []string{"mysql/0"}, nil)
   754  	s.assertScopeChange(c, ws[3], []string{"mysql/1"}, nil)
   755  	s.assertNoScopeChange(c, ws...)
   756  	assertJoined(c, prr.pru1)
   757  	assertJoined(c, prr.rru0)
   758  
   759  	// pru0 leaves; check detected only by same-container req.
   760  	assertJoined(c, prr.pru0)
   761  	err = prr.pru0.LeaveScope()
   762  	c.Assert(err, jc.ErrorIsNil)
   763  	s.assertScopeChange(c, ws[2], nil, []string{"mysql/0"})
   764  	s.assertNoScopeChange(c, ws...)
   765  	assertNotInScope(c, prr.pru0)
   766  
   767  	// rru0 leaves; check detected only by same-container pro.
   768  	assertJoined(c, prr.rru0)
   769  	err = prr.rru0.LeaveScope()
   770  	c.Assert(err, jc.ErrorIsNil)
   771  	s.assertScopeChange(c, ws[0], nil, []string{"logging/0"})
   772  	s.assertNoScopeChange(c, ws...)
   773  	assertNotInScope(c, prr.rru0)
   774  }
   775  
   776  func (s *RelationUnitSuite) TestCoalesceWatchScope(c *gc.C) {
   777  	// TODO(quiescence): fix this test once the watcher has some reliable coalescence.
   778  	c.Skip("skip until watcher has better coalescing")
   779  	pr := newPeerRelation(c, s.State)
   780  
   781  	// Test empty initial event.
   782  	w0 := pr.ru0.WatchScope()
   783  	defer testing.AssertStop(c, w0)
   784  	s.assertScopeChange(c, w0, nil, nil)
   785  	s.assertNoScopeChange(c, w0)
   786  
   787  	// ru1 and ru2 enter; check changes observed together.
   788  	err := pr.ru1.EnterScope(nil)
   789  	c.Assert(err, jc.ErrorIsNil)
   790  	err = pr.ru2.EnterScope(nil)
   791  	c.Assert(err, jc.ErrorIsNil)
   792  
   793  	s.assertScopeChange(c, w0, []string{"riak/1", "riak/2"}, nil)
   794  	s.assertNoScopeChange(c, w0)
   795  
   796  	// ru1 leaves and re-enters; check no change observed.
   797  	err = pr.ru1.LeaveScope()
   798  	c.Assert(err, jc.ErrorIsNil)
   799  	err = pr.ru1.EnterScope(nil)
   800  	c.Assert(err, jc.ErrorIsNil)
   801  	s.assertNoScopeChange(c, w0)
   802  
   803  	// ru1 and ru2 leave; check changes observed together.
   804  	err = pr.ru1.LeaveScope()
   805  	c.Assert(err, jc.ErrorIsNil)
   806  	err = pr.ru2.LeaveScope()
   807  	c.Assert(err, jc.ErrorIsNil)
   808  	s.assertScopeChange(c, w0, nil, []string{"riak/1", "riak/2"})
   809  	s.assertNoScopeChange(c, w0)
   810  }
   811  
   812  func (s *RelationUnitSuite) TestPrepareLeaveScope(c *gc.C) {
   813  	prr := newProReqRelation(c, &s.ConnSuite, charm.ScopeGlobal)
   814  	s.testPrepareLeaveScope(c, prr.rel, prr.pru0, prr.pru1, prr.rru0, prr.rru1)
   815  }
   816  
   817  func (s *RelationUnitSuite) TestPrepareLeaveScopeRemote(c *gc.C) {
   818  	prr := newRemoteProReqRelation(c, &s.ConnSuite)
   819  	s.testPrepareLeaveScope(c, prr.rel, prr.pru0, prr.pru1, prr.rru0, prr.rru1)
   820  }
   821  
   822  func (s *RelationUnitSuite) testPrepareLeaveScope(c *gc.C, rel *state.Relation, pru0, pru1, rru0, rru1 *state.RelationUnit) {
   823  	// Test empty initial event.
   824  	w0 := pru0.WatchScope()
   825  	defer testing.AssertStop(c, w0)
   826  	s.assertScopeChange(c, w0, nil, nil)
   827  	s.assertNoScopeChange(c, w0)
   828  
   829  	// rru0 and rru1 enter; check changes.
   830  	err := rru0.EnterScope(nil)
   831  	c.Assert(err, jc.ErrorIsNil)
   832  	err = rru1.EnterScope(nil)
   833  	c.Assert(err, jc.ErrorIsNil)
   834  	s.assertScopeChange(c, w0, []string{"wordpress/0", "wordpress/1"}, nil)
   835  	s.assertNoScopeChange(c, w0)
   836  
   837  	// rru0 notifies that it will leave soon; it's reported as departed by the
   838  	// watcher, but InScope remains accurate.
   839  	err = rru0.PrepareLeaveScope()
   840  	c.Assert(err, jc.ErrorIsNil)
   841  	s.assertScopeChange(c, w0, nil, []string{"wordpress/0"})
   842  	s.assertNoScopeChange(c, w0)
   843  	assertInScope(c, rru0)
   844  	assertNotJoined(c, rru0)
   845  
   846  	// rru1 leaves, and the relation is destroyed; it's not removed, because
   847  	// rru0 keeps it alive until it really leaves scope.
   848  	err = rru1.LeaveScope()
   849  	c.Assert(err, jc.ErrorIsNil)
   850  	s.assertScopeChange(c, w0, nil, []string{"wordpress/1"})
   851  	s.assertNoScopeChange(c, w0)
   852  	err = rel.Refresh()
   853  	c.Assert(err, jc.ErrorIsNil)
   854  	err = rel.Destroy()
   855  	c.Assert(err, jc.ErrorIsNil)
   856  	err = rel.Refresh()
   857  	c.Assert(err, jc.ErrorIsNil)
   858  
   859  	// rru0 really leaves; the relation is cleaned up.
   860  	err = rru0.LeaveScope()
   861  	c.Assert(err, jc.ErrorIsNil)
   862  	err = rel.Destroy()
   863  	c.Assert(err, jc.ErrorIsNil)
   864  	s.assertNoScopeChange(c, w0)
   865  	err = rel.Refresh()
   866  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   867  }
   868  
   869  func (s *RelationUnitSuite) assertScopeChange(c *gc.C, w *state.RelationScopeWatcher, entered, left []string) {
   870  	timeout := time.After(coretesting.LongWait)
   871  	// Initial event special case.
   872  	if len(entered) == 0 && len(left) == 0 {
   873  		select {
   874  		case ch, ok := <-w.Changes():
   875  			c.Assert(ok, jc.IsTrue)
   876  			c.Assert(ch.Entered, gc.HasLen, 0)
   877  			c.Assert(ch.Left, gc.HasLen, 0)
   878  		case <-timeout:
   879  			c.Fatalf("no change")
   880  		}
   881  		return
   882  	}
   883  	enteredSet := set.NewStrings(entered...)
   884  	leftSet := set.NewStrings(left...)
   885  	for enteredSet.Size() > 0 || leftSet.Size() > 0 {
   886  		select {
   887  		case ch, ok := <-w.Changes():
   888  			c.Assert(ok, jc.IsTrue)
   889  			for _, v := range ch.Entered {
   890  				c.Check(enteredSet.Contains(v), jc.IsTrue, gc.Commentf("unexpected enter scope change %s", v))
   891  				enteredSet.Remove(v)
   892  			}
   893  			for _, v := range ch.Left {
   894  				c.Check(leftSet.Contains(v), jc.IsTrue, gc.Commentf("unexpected leave scope change %s", v))
   895  				leftSet.Remove(v)
   896  			}
   897  		case <-timeout:
   898  			c.Fatalf("missing changes for enter scope %v and leave scope %v",
   899  				enteredSet.SortedValues(), leftSet.SortedValues())
   900  		}
   901  	}
   902  }
   903  
   904  func (s *RelationUnitSuite) assertNoScopeChange(c *gc.C, ws ...*state.RelationScopeWatcher) {
   905  	for _, w := range ws {
   906  		select {
   907  		case ch, ok := <-w.Changes():
   908  			c.Fatalf("got unwanted change: %#v, %t", ch, ok)
   909  		case <-time.After(coretesting.ShortWait):
   910  		}
   911  	}
   912  }
   913  
   914  func (s *RelationUnitSuite) TestValidYes(c *gc.C) {
   915  	prr := newProReqRelation(c, &s.ConnSuite, charm.ScopeContainer)
   916  	rus := []*state.RelationUnit{prr.pru0, prr.pru1, prr.rru0, prr.rru1}
   917  	for _, ru := range rus {
   918  		result, err := ru.Valid()
   919  		c.Assert(err, jc.ErrorIsNil)
   920  		c.Assert(result, jc.IsTrue)
   921  	}
   922  }
   923  
   924  func (s *RelationUnitSuite) TestValidNo(c *gc.C) {
   925  	mysqlLogging := newProReqRelation(c, &s.ConnSuite, charm.ScopeContainer)
   926  	wpApp := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   927  	wpLogging := newProReqRelationForApps(c, s.State, wpApp, mysqlLogging.rapp)
   928  
   929  	// We have logging related to mysql and to wordpress. We can
   930  	// create an invalid RU by taking a logging unit from
   931  	// mysql-logging and getting the wp-logging RU for it.
   932  	ru, err := wpLogging.rel.Unit(mysqlLogging.ru0)
   933  	c.Assert(err, jc.ErrorIsNil)
   934  
   935  	result, err := ru.Valid()
   936  	c.Assert(err, jc.ErrorIsNil)
   937  	c.Assert(result, jc.IsFalse)
   938  }
   939  
   940  func (s *RelationUnitSuite) TestValidSubordinateToSubordinate(c *gc.C) {
   941  	// Relate mysql and logging...
   942  	mysqlLogging := newProReqRelation(c, &s.ConnSuite, charm.ScopeContainer)
   943  	monApp := s.AddTestingApplication(c, "monitoring", s.AddTestingCharm(c, "monitoring"))
   944  	// Relate mysql and monitoring - relation to a non-subordinate
   945  	// needed to trigger creation of monitoring unit.
   946  	mysqlMonitoring := newProReqRelationForApps(c, s.State, mysqlLogging.papp, monApp)
   947  	// Monitor the logging app (newProReqRelationForApps assumes that
   948  	// the providing app is a principal, so we need to do it by hand).
   949  	loggingApp := mysqlLogging.rapp
   950  
   951  	// Can't infer endpoints because they're ambiguous.
   952  	ep1, err := loggingApp.Endpoint("juju-info")
   953  	c.Assert(err, jc.ErrorIsNil)
   954  	ep2, err := monApp.Endpoint("info")
   955  	c.Assert(err, jc.ErrorIsNil)
   956  
   957  	rel, err := s.State.AddRelation(ep1, ep2)
   958  	c.Assert(err, jc.ErrorIsNil)
   959  	prr := &ProReqRelation{rel: rel, papp: loggingApp, rapp: monApp}
   960  
   961  	// The units already exist, create the relation units.
   962  	prr.pu0 = mysqlLogging.ru0
   963  	prr.pru0, err = rel.Unit(prr.pu0)
   964  	c.Assert(err, jc.ErrorIsNil)
   965  
   966  	prr.ru0 = mysqlMonitoring.ru0
   967  	prr.rru0, err = rel.Unit(prr.ru0)
   968  	c.Assert(err, jc.ErrorIsNil)
   969  
   970  	// Logging monitoring relation units should be valid.
   971  	res, err := prr.rru0.Valid()
   972  	c.Assert(err, jc.ErrorIsNil)
   973  	c.Assert(res, jc.IsTrue)
   974  	res, err = prr.pru0.Valid()
   975  	c.Assert(err, jc.ErrorIsNil)
   976  	c.Assert(res, jc.IsTrue)
   977  }
   978  
   979  type PeerRelation struct {
   980  	rel                *state.Relation
   981  	app                *state.Application
   982  	u0, u1, u2, u3     *state.Unit
   983  	ru0, ru1, ru2, ru3 *state.RelationUnit
   984  }
   985  
   986  func preventPeerUnitsDestroyRemove(c *gc.C, pr *PeerRelation) {
   987  	preventUnitDestroyRemove(c, pr.u0)
   988  	preventUnitDestroyRemove(c, pr.u1)
   989  	preventUnitDestroyRemove(c, pr.u2)
   990  	preventUnitDestroyRemove(c, pr.u3)
   991  }
   992  
   993  func newPeerRelation(c *gc.C, st *state.State) *PeerRelation {
   994  	app := state.AddTestingApplication(c, st, "riak", state.AddTestingCharm(c, st, "riak"))
   995  	ep, err := app.Endpoint("ring")
   996  	c.Assert(err, jc.ErrorIsNil)
   997  	rel, err := st.EndpointsRelation(ep)
   998  	c.Assert(err, jc.ErrorIsNil)
   999  	pr := &PeerRelation{rel: rel, app: app}
  1000  	pr.u0, pr.ru0 = addRU(c, app, rel, nil)
  1001  	pr.u1, pr.ru1 = addRU(c, app, rel, nil)
  1002  	pr.u2, pr.ru2 = addRU(c, app, rel, nil)
  1003  	pr.u3, pr.ru3 = addRU(c, app, rel, nil)
  1004  	return pr
  1005  }
  1006  
  1007  type ProReqRelation struct {
  1008  	rel                    *state.Relation
  1009  	papp, rapp             *state.Application
  1010  	pu0, pu1, ru0, ru1     *state.Unit
  1011  	pru0, pru1, rru0, rru1 *state.RelationUnit
  1012  }
  1013  
  1014  func preventProReqUnitsDestroyRemove(c *gc.C, prr *ProReqRelation) {
  1015  	preventUnitDestroyRemove(c, prr.pu0)
  1016  	preventUnitDestroyRemove(c, prr.pu1)
  1017  	preventUnitDestroyRemove(c, prr.ru0)
  1018  	preventUnitDestroyRemove(c, prr.ru1)
  1019  }
  1020  
  1021  func newProReqRelation(c *gc.C, s *ConnSuite, scope charm.RelationScope, assignedMachines ...*state.Machine) *ProReqRelation {
  1022  	papp := s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1023  	var rapp *state.Application
  1024  	if scope == charm.ScopeGlobal {
  1025  		rapp = s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
  1026  	} else {
  1027  		rapp = s.AddTestingApplication(c, "logging", s.AddTestingCharm(c, "logging"))
  1028  	}
  1029  	return newProReqRelationForApps(c, s.State, papp, rapp, assignedMachines...)
  1030  }
  1031  
  1032  func newProReqRelationForApps(c *gc.C, st *state.State, proApp, reqApp *state.Application, assignedMachines ...*state.Machine) *ProReqRelation {
  1033  	eps, err := st.InferEndpoints(proApp.Name(), reqApp.Name())
  1034  	c.Assert(err, jc.ErrorIsNil)
  1035  	rel, err := st.AddRelation(eps...)
  1036  	c.Assert(err, jc.ErrorIsNil)
  1037  	prr := &ProReqRelation{rel: rel, papp: proApp, rapp: reqApp}
  1038  	assignToMachine := func(unit *state.Unit) {
  1039  		if len(assignedMachines) == 0 {
  1040  			return
  1041  		}
  1042  		var machine *state.Machine
  1043  		machine, assignedMachines = assignedMachines[0], assignedMachines[1:]
  1044  		c.Assert(unit.AssignToMachine(machine), jc.ErrorIsNil)
  1045  	}
  1046  	prr.pu0, prr.pru0 = addRU(c, proApp, rel, nil)
  1047  	assignToMachine(prr.pu0)
  1048  	prr.pu1, prr.pru1 = addRU(c, proApp, rel, nil)
  1049  	assignToMachine(prr.pu1)
  1050  	if eps[0].Scope == charm.ScopeGlobal {
  1051  		prr.ru0, prr.rru0 = addRU(c, reqApp, rel, nil)
  1052  		assignToMachine(prr.ru0)
  1053  		prr.ru1, prr.rru1 = addRU(c, reqApp, rel, nil)
  1054  		assignToMachine(prr.ru1)
  1055  	} else {
  1056  		prr.ru0, prr.rru0 = addRU(c, reqApp, rel, prr.pu0)
  1057  		prr.ru1, prr.rru1 = addRU(c, reqApp, rel, prr.pu1)
  1058  	}
  1059  	return prr
  1060  }
  1061  
  1062  func (prr *ProReqRelation) watches() []*state.RelationScopeWatcher {
  1063  	return []*state.RelationScopeWatcher{
  1064  		prr.pru0.WatchScope(), prr.pru1.WatchScope(),
  1065  		prr.rru0.WatchScope(), prr.rru1.WatchScope(),
  1066  	}
  1067  }
  1068  
  1069  func (prr *ProReqRelation) allEnterScope(c *gc.C) {
  1070  	g, _ := errgroup.WithContext(context.Background())
  1071  
  1072  	g.Go(func() error { return prr.pru0.EnterScope(nil) })
  1073  	g.Go(func() error { return prr.pru1.EnterScope(nil) })
  1074  	g.Go(func() error { return prr.rru0.EnterScope(nil) })
  1075  	g.Go(func() error { return prr.rru1.EnterScope(nil) })
  1076  
  1077  	err := g.Wait()
  1078  	c.Assert(err, jc.ErrorIsNil)
  1079  }
  1080  
  1081  func addRU(c *gc.C, app *state.Application, rel *state.Relation, principal *state.Unit) (*state.Unit, *state.RelationUnit) {
  1082  	// Given the application app in the relation rel, add a unit of app and create
  1083  	// a RelationUnit with rel. If principal is supplied, app is assumed to be
  1084  	// subordinate and the unit will be created by temporarily entering the
  1085  	// relation's scope as the principal.
  1086  	var u *state.Unit
  1087  	if principal == nil {
  1088  		unit, err := app.AddUnit(state.AddUnitParams{})
  1089  		c.Assert(err, jc.ErrorIsNil)
  1090  		u = unit
  1091  	} else {
  1092  		origUnits, err := app.AllUnits()
  1093  		c.Assert(err, jc.ErrorIsNil)
  1094  		pru, err := rel.Unit(principal)
  1095  		c.Assert(err, jc.ErrorIsNil)
  1096  		err = pru.EnterScope(nil) // to create the subordinate
  1097  		c.Assert(err, jc.ErrorIsNil)
  1098  		err = pru.LeaveScope() // to reset to initial expected state
  1099  		c.Assert(err, jc.ErrorIsNil)
  1100  		newUnits, err := app.AllUnits()
  1101  		c.Assert(err, jc.ErrorIsNil)
  1102  		for _, unit := range newUnits {
  1103  			found := false
  1104  			for _, old := range origUnits {
  1105  				if unit.Name() == old.Name() {
  1106  					found = true
  1107  					break
  1108  				}
  1109  			}
  1110  			if !found {
  1111  				u = unit
  1112  				break
  1113  			}
  1114  		}
  1115  		c.Assert(u, gc.NotNil)
  1116  	}
  1117  	ru, err := rel.Unit(u)
  1118  	c.Assert(err, jc.ErrorIsNil)
  1119  	c.Assert(ru.UnitName(), gc.Equals, u.Name())
  1120  	return u, ru
  1121  }
  1122  
  1123  type RemoteProReqRelation struct {
  1124  	rel                    *state.Relation
  1125  	papp                   *state.RemoteApplication
  1126  	rapp                   *state.Application
  1127  	pru0, pru1, rru0, rru1 *state.RelationUnit
  1128  	ru0, ru1               *state.Unit
  1129  }
  1130  
  1131  func newRemoteProReqRelation(c *gc.C, s *ConnSuite) *RemoteProReqRelation {
  1132  	papp, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
  1133  		Name:        "mysql",
  1134  		SourceModel: coretesting.ModelTag,
  1135  		Endpoints: []charm.Relation{{
  1136  			Interface: "mysql",
  1137  			Name:      "server",
  1138  			Role:      charm.RoleProvider,
  1139  			Scope:     charm.ScopeGlobal,
  1140  		}}})
  1141  	c.Assert(err, jc.ErrorIsNil)
  1142  	rapp := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
  1143  
  1144  	eps, err := s.State.InferEndpoints("mysql", "wordpress")
  1145  	c.Assert(err, jc.ErrorIsNil)
  1146  	rel, err := s.State.AddRelation(eps...)
  1147  	c.Assert(err, jc.ErrorIsNil)
  1148  
  1149  	prr := &RemoteProReqRelation{rel: rel, papp: papp, rapp: rapp}
  1150  	prr.pru0 = addRemoteRU(c, rel, "mysql/0")
  1151  	prr.pru1 = addRemoteRU(c, rel, "mysql/1")
  1152  	prr.ru0, prr.rru0 = addRU(c, rapp, rel, nil)
  1153  	prr.ru1, prr.rru1 = addRU(c, rapp, rel, nil)
  1154  	return prr
  1155  }
  1156  
  1157  func (prr *RemoteProReqRelation) watches() []*state.RelationScopeWatcher {
  1158  	return []*state.RelationScopeWatcher{
  1159  		prr.pru0.WatchScope(), prr.pru1.WatchScope(),
  1160  		prr.rru0.WatchScope(), prr.rru1.WatchScope(),
  1161  	}
  1162  }
  1163  
  1164  func addRemoteRU(c *gc.C, rel *state.Relation, unitName string) *state.RelationUnit {
  1165  	// Add a remote unit with the given name to rel.
  1166  	ru, err := rel.RemoteUnit(unitName)
  1167  	c.Assert(err, jc.ErrorIsNil)
  1168  	return ru
  1169  }
  1170  
  1171  type WatchRelationUnitsSuite struct {
  1172  	ConnSuite
  1173  }
  1174  
  1175  var _ = gc.Suite(&WatchRelationUnitsSuite{})
  1176  
  1177  func (s *WatchRelationUnitsSuite) TestPeer(c *gc.C) {
  1178  	// Create an application and get a peer relation.
  1179  	riak := s.AddTestingApplication(c, "riak", s.AddTestingCharm(c, "riak"))
  1180  	riakEP, err := riak.Endpoint("ring")
  1181  	c.Assert(err, jc.ErrorIsNil)
  1182  	rels, err := riak.Relations()
  1183  	c.Assert(err, jc.ErrorIsNil)
  1184  	c.Assert(rels, gc.HasLen, 1)
  1185  	rel := rels[0]
  1186  
  1187  	// Add some units to the application and set their private addresses; get
  1188  	// the relevant RelationUnits.
  1189  	// (Private addresses should be set by their unit agents on
  1190  	// startup; this test does not include that, but Join expects
  1191  	// the information to be available, and uses it to populate the
  1192  	// relation settings node.)
  1193  	addUnit := func(i int) *state.RelationUnit {
  1194  		unit, err := riak.AddUnit(state.AddUnitParams{})
  1195  		c.Assert(err, jc.ErrorIsNil)
  1196  		err = unit.AssignToNewMachine()
  1197  		c.Assert(err, jc.ErrorIsNil)
  1198  		mId, err := unit.AssignedMachineId()
  1199  		c.Assert(err, jc.ErrorIsNil)
  1200  		machine, err := s.State.Machine(mId)
  1201  		c.Assert(err, jc.ErrorIsNil)
  1202  		privateAddr := network.NewSpaceAddress(
  1203  			fmt.Sprintf("riak%d.example.com", i),
  1204  			network.WithScope(network.ScopeCloudLocal),
  1205  		)
  1206  		err = machine.SetProviderAddresses(privateAddr)
  1207  		c.Assert(err, jc.ErrorIsNil)
  1208  		ru, err := rel.Unit(unit)
  1209  		c.Assert(err, jc.ErrorIsNil)
  1210  		c.Assert(ru.Endpoint(), gc.Equals, riakEP)
  1211  		return ru
  1212  	}
  1213  	ru0 := addUnit(0)
  1214  	ru1 := addUnit(1)
  1215  	ru2 := addUnit(2)
  1216  
  1217  	s.WaitForModelWatchersIdle(c, s.State.ModelUUID())
  1218  
  1219  	// ---------- Single unit ----------
  1220  
  1221  	// Start watching the relation from the perspective of the first unit.
  1222  	w0 := ru0.Watch()
  1223  	defer testing.AssertStop(c, w0)
  1224  	w0c := testing.NewRelationUnitsWatcherC(c, w0)
  1225  	w0c.AssertChange(nil, []string{"riak"}, nil)
  1226  	w0c.AssertNoChange()
  1227  
  1228  	// Join the first unit to the relation, and change the settings, and
  1229  	// check that nothing apparently happens.
  1230  	err = ru0.EnterScope(nil)
  1231  	c.Assert(err, jc.ErrorIsNil)
  1232  	changeSettings(c, ru0)
  1233  	w0c.AssertNoChange()
  1234  
  1235  	// Update the application settings, and see that the units notice
  1236  	updateAppSettings(c, s.State, rel, riak, "riak/0", map[string]interface{}{"foo": "bar"})
  1237  	w0c.AssertChange(nil, []string{"riak"}, nil)
  1238  	w0c.AssertNoChange()
  1239  
  1240  	// ---------- Two units ----------
  1241  
  1242  	// Now join another unit to the relation...
  1243  	err = ru1.EnterScope(nil)
  1244  	c.Assert(err, jc.ErrorIsNil)
  1245  
  1246  	// ...and check that the first relation unit sees the change.
  1247  	expectChanged := []string{"riak/1"}
  1248  	w0c.AssertChange(expectChanged, nil, nil)
  1249  	w0c.AssertNoChange()
  1250  
  1251  	// Join again, check it's a no-op.
  1252  	err = ru1.EnterScope(nil)
  1253  	c.Assert(err, jc.ErrorIsNil)
  1254  	w0c.AssertNoChange()
  1255  
  1256  	// Start watching the relation from the perspective of the second unit,
  1257  	// and check that it sees the right state.
  1258  	w1 := ru1.Watch()
  1259  	defer testing.AssertStop(c, w1)
  1260  	w1c := testing.NewRelationUnitsWatcherC(c, w1)
  1261  	expectChanged = []string{"riak/0"}
  1262  	w1c.AssertChange(expectChanged, []string{"riak"}, nil)
  1263  	w1c.AssertNoChange()
  1264  
  1265  	// ---------- Three units ----------
  1266  
  1267  	// Whoa, it works. Ok, check the third unit's opinion of the state.
  1268  	w2 := ru2.Watch()
  1269  	defer testing.AssertStop(c, w2)
  1270  	w2c := testing.NewRelationUnitsWatcherC(c, w2)
  1271  	expectChanged = []string{"riak/0", "riak/1"}
  1272  	w2c.AssertChange(expectChanged, []string{"riak"}, nil)
  1273  	w2c.AssertNoChange()
  1274  
  1275  	// Join the third unit, and check the first and second units see it.
  1276  	err = ru2.EnterScope(nil)
  1277  	c.Assert(err, jc.ErrorIsNil)
  1278  	expectChanged = []string{"riak/2"}
  1279  	w0c.AssertChange(expectChanged, nil, nil)
  1280  	w0c.AssertNoChange()
  1281  	w1c.AssertChange(expectChanged, nil, nil)
  1282  	w1c.AssertNoChange()
  1283  
  1284  	// Change the second unit's settings, and check that only
  1285  	// the first and third see changes.
  1286  	changeSettings(c, ru1)
  1287  	w1c.AssertNoChange()
  1288  	expectChanged = []string{"riak/1"}
  1289  	w0c.AssertChange(expectChanged, nil, nil)
  1290  	w0c.AssertNoChange()
  1291  	w2c.AssertChange(expectChanged, nil, nil)
  1292  	w2c.AssertNoChange()
  1293  
  1294  	// Update the application settings, and see that the units notice
  1295  	updateAppSettings(c, s.State, rel, riak, "riak/0", map[string]interface{}{"foo": "baz"})
  1296  	w0c.AssertChange(nil, []string{"riak"}, nil)
  1297  	w0c.AssertNoChange()
  1298  	w1c.AssertChange(nil, []string{"riak"}, nil)
  1299  	w1c.AssertNoChange()
  1300  	w2c.AssertChange(nil, []string{"riak"}, nil)
  1301  	w2c.AssertNoChange()
  1302  
  1303  	// ---------- Two units again ----------
  1304  
  1305  	// Depart the second unit, and check that the first and third detect it.
  1306  	err = ru1.LeaveScope()
  1307  	c.Assert(err, jc.ErrorIsNil)
  1308  	expectDeparted := []string{"riak/1"}
  1309  	w0c.AssertChange(nil, nil, expectDeparted)
  1310  	w0c.AssertNoChange()
  1311  	w2c.AssertChange(nil, nil, expectDeparted)
  1312  	w2c.AssertNoChange()
  1313  
  1314  	// Change its settings, and check the others don't observe anything.
  1315  	changeSettings(c, ru1)
  1316  	w0c.AssertNoChange()
  1317  	w2c.AssertNoChange()
  1318  
  1319  	// Check no spurious events showed up on the second unit's watch, and check
  1320  	// it closes cleanly.
  1321  	w1c.AssertNoChange()
  1322  	testing.AssertStop(c, w1)
  1323  
  1324  	// OK, we're done here. Cleanup, and error detection during same,
  1325  	// will be handled by the deferred kill/stop calls. Phew.
  1326  }
  1327  
  1328  func (s *WatchRelationUnitsSuite) TestWatchAppSettings(c *gc.C) {
  1329  	loggo.GetLogger("juju.state.relationunits").SetLogLevel(loggo.TRACE)
  1330  	prr := newProReqRelation(c, &s.ConnSuite, charm.ScopeGlobal)
  1331  	prr.allEnterScope(c)
  1332  	s.WaitForModelWatchersIdle(c, s.State.ModelUUID())
  1333  
  1334  	// Watch from the perspective of the requiring unit, and see that a change to the
  1335  	// providing application is seen
  1336  	watcher := prr.rru0.Watch()
  1337  	defer testing.AssertStop(c, watcher)
  1338  	w0c := testing.NewRelationUnitsWatcherC(c, watcher)
  1339  	w0c.AssertChange([]string{"mysql/0", "mysql/1"}, []string{"mysql"}, nil)
  1340  	w0c.AssertNoChange()
  1341  	updateAppSettings(c, s.State, prr.rel, prr.papp, prr.pu0.Name(), map[string]interface{}{"foo": "bar"})
  1342  	w0c.AssertChange(nil, []string{prr.papp.Name()}, nil)
  1343  }
  1344  
  1345  func (s *WatchRelationUnitsSuite) TestProviderRequirerGlobal(c *gc.C) {
  1346  	// Create a pair of application and a relation between them.
  1347  	mysql := s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1348  	mysqlEP, err := mysql.Endpoint("server")
  1349  	c.Assert(err, jc.ErrorIsNil)
  1350  	wordpress := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
  1351  	wordpressEP, err := wordpress.Endpoint("db")
  1352  	c.Assert(err, jc.ErrorIsNil)
  1353  	rel, err := s.State.AddRelation(mysqlEP, wordpressEP)
  1354  	c.Assert(err, jc.ErrorIsNil)
  1355  
  1356  	// Add some units to the application and set their private addresses.
  1357  	addUnit := func(srv *state.Application, sub string, ep state.Endpoint) *state.RelationUnit {
  1358  		unit, err := srv.AddUnit(state.AddUnitParams{})
  1359  		c.Assert(err, jc.ErrorIsNil)
  1360  		ru, err := rel.Unit(unit)
  1361  		c.Assert(err, jc.ErrorIsNil)
  1362  		c.Assert(ru.Endpoint(), gc.Equals, ep)
  1363  		return ru
  1364  	}
  1365  	msru0 := addUnit(mysql, "ms0", mysqlEP)
  1366  	msru1 := addUnit(mysql, "ms1", mysqlEP)
  1367  	wpru0 := addUnit(wordpress, "wp0", wordpressEP)
  1368  	wpru1 := addUnit(wordpress, "wp1", wordpressEP)
  1369  
  1370  	s.WaitForModelWatchersIdle(c, s.State.ModelUUID())
  1371  
  1372  	// ---------- Single role active ----------
  1373  
  1374  	// Watch the relation from the perspective of the first provider unit and
  1375  	// check initial event.
  1376  	msw0 := msru0.Watch()
  1377  	defer testing.AssertStop(c, msw0)
  1378  	msw0c := testing.NewRelationUnitsWatcherC(c, msw0)
  1379  	msw0c.AssertChange(nil, []string{"wordpress"}, nil)
  1380  	msw0c.AssertNoChange()
  1381  
  1382  	// Join the unit to the relation, change its settings, and check that
  1383  	// nothing apparently happens.
  1384  	err = msru0.EnterScope(nil)
  1385  	c.Assert(err, jc.ErrorIsNil)
  1386  	changeSettings(c, msru0)
  1387  	msw0c.AssertNoChange()
  1388  
  1389  	// Join the second provider unit, start its watch, and check what it thinks the
  1390  	// state of the relation is.
  1391  	err = msru1.EnterScope(nil)
  1392  	c.Assert(err, jc.ErrorIsNil)
  1393  	msw1 := msru1.Watch()
  1394  	defer testing.AssertStop(c, msw1)
  1395  	msw1c := testing.NewRelationUnitsWatcherC(c, msw1)
  1396  	msw1c.AssertChange(nil, []string{"wordpress"}, nil)
  1397  	msw1c.AssertNoChange()
  1398  
  1399  	// Change the unit's settings, and check that neither provider unit
  1400  	// observes any change.
  1401  	changeSettings(c, msru1)
  1402  	msw1c.AssertNoChange()
  1403  	msw0c.AssertNoChange()
  1404  
  1405  	// ---------- Two roles active ----------
  1406  
  1407  	// Start watches from both requirer units' perspectives, and check that
  1408  	// they see the provider units.
  1409  	expectChanged := []string{"mysql/0", "mysql/1"}
  1410  	wpw0 := wpru0.Watch()
  1411  	defer testing.AssertStop(c, wpw0)
  1412  	wpw0c := testing.NewRelationUnitsWatcherC(c, wpw0)
  1413  	wpw0c.AssertChange(expectChanged, []string{"mysql"}, nil)
  1414  	wpw0c.AssertNoChange()
  1415  	wpw1 := wpru1.Watch()
  1416  	defer testing.AssertStop(c, wpw1)
  1417  	wpw1c := testing.NewRelationUnitsWatcherC(c, wpw1)
  1418  	wpw1c.AssertChange(expectChanged, []string{"mysql"}, nil)
  1419  	wpw1c.AssertNoChange()
  1420  
  1421  	// Join the first requirer unit, and check the provider units see it.
  1422  	err = wpru0.EnterScope(nil)
  1423  	c.Assert(err, jc.ErrorIsNil)
  1424  	expectChanged = []string{"wordpress/0"}
  1425  	msw0c.AssertChange(expectChanged, nil, nil)
  1426  	msw0c.AssertNoChange()
  1427  	msw1c.AssertChange(expectChanged, nil, nil)
  1428  	msw1c.AssertNoChange()
  1429  
  1430  	// Join again, check no-op.
  1431  	err = wpru0.EnterScope(nil)
  1432  	c.Assert(err, jc.ErrorIsNil)
  1433  	msw0c.AssertNoChange()
  1434  	msw1c.AssertNoChange()
  1435  
  1436  	// Join the second requirer, and check the provider units see the change.
  1437  	err = wpru1.EnterScope(nil)
  1438  	c.Assert(err, jc.ErrorIsNil)
  1439  	expectChanged = []string{"wordpress/1"}
  1440  	msw0c.AssertChange(expectChanged, nil, nil)
  1441  	msw0c.AssertNoChange()
  1442  	msw1c.AssertChange(expectChanged, nil, nil)
  1443  	msw1c.AssertNoChange()
  1444  
  1445  	// Verify that neither requirer has observed any change to the relation.
  1446  	wpw0c.AssertNoChange()
  1447  	wpw1c.AssertNoChange()
  1448  
  1449  	// Change settings for the first requirer, check providers see it...
  1450  	changeSettings(c, wpru0)
  1451  	expectChanged = []string{"wordpress/0"}
  1452  	msw0c.AssertChange(expectChanged, nil, nil)
  1453  	msw0c.AssertNoChange()
  1454  	msw1c.AssertChange(expectChanged, nil, nil)
  1455  	msw1c.AssertNoChange()
  1456  
  1457  	// ...and requirers don't.
  1458  	wpw0c.AssertNoChange()
  1459  	wpw1c.AssertNoChange()
  1460  
  1461  	// Change the application settings for the provider, and see that both
  1462  	// requirers see it, but the providers do not
  1463  	updateAppSettings(c, s.State, rel, mysql, "mysql/0", map[string]interface{}{"foo": "bar"})
  1464  	wpw0c.AssertChange(nil, []string{"mysql"}, nil)
  1465  	wpw1c.AssertChange(nil, []string{"mysql"}, nil)
  1466  	msw0c.AssertNoChange()
  1467  	msw1c.AssertNoChange()
  1468  
  1469  	// Depart the second requirer and check the providers see it...
  1470  	err = wpru1.LeaveScope()
  1471  	c.Assert(err, jc.ErrorIsNil)
  1472  	expectDeparted := []string{"wordpress/1"}
  1473  	msw0c.AssertChange(nil, nil, expectDeparted)
  1474  	msw0c.AssertNoChange()
  1475  	msw1c.AssertChange(nil, nil, expectDeparted)
  1476  	msw1c.AssertNoChange()
  1477  
  1478  	// ...and the requirers don't.
  1479  	wpw0c.AssertNoChange()
  1480  	wpw1c.AssertNoChange()
  1481  
  1482  	// Cleanup handled by defers as before.
  1483  }
  1484  
  1485  func (s *WatchRelationUnitsSuite) TestProviderRequirerContainer(c *gc.C) {
  1486  	// Create a pair of application and a relation between them.
  1487  	mysql := s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1488  	mysqlEP, err := mysql.Endpoint("juju-info")
  1489  	c.Assert(err, jc.ErrorIsNil)
  1490  	logging := s.AddTestingApplication(c, "logging", s.AddTestingCharm(c, "logging"))
  1491  	loggingEP, err := logging.Endpoint("info")
  1492  	c.Assert(err, jc.ErrorIsNil)
  1493  	rel, err := s.State.AddRelation(mysqlEP, loggingEP)
  1494  	c.Assert(err, jc.ErrorIsNil)
  1495  
  1496  	// Change mysqlEP to match the endpoint that will actually be used by the relation.
  1497  	mysqlEP.Scope = charm.ScopeContainer
  1498  
  1499  	// Add some units to the application and set their private addresses.
  1500  	addUnits := func(i int) (*state.RelationUnit, *state.RelationUnit) {
  1501  		msu, err := mysql.AddUnit(state.AddUnitParams{})
  1502  		c.Assert(err, jc.ErrorIsNil)
  1503  		msru, err := rel.Unit(msu)
  1504  		c.Assert(err, jc.ErrorIsNil)
  1505  		c.Assert(msru.Endpoint(), gc.Equals, mysqlEP)
  1506  		err = msru.EnterScope(nil)
  1507  		c.Assert(err, jc.ErrorIsNil)
  1508  		err = msru.LeaveScope()
  1509  		c.Assert(err, jc.ErrorIsNil)
  1510  		lgu, err := s.State.Unit("logging/" + strconv.Itoa(i))
  1511  		c.Assert(err, jc.ErrorIsNil)
  1512  		lgru, err := rel.Unit(lgu)
  1513  		c.Assert(err, jc.ErrorIsNil)
  1514  		c.Assert(lgru.Endpoint(), gc.Equals, loggingEP)
  1515  		return msru, lgru
  1516  	}
  1517  	msru0, lgru0 := addUnits(0)
  1518  	msru1, lgru1 := addUnits(1)
  1519  
  1520  	s.WaitForModelWatchersIdle(c, s.State.ModelUUID())
  1521  
  1522  	// ---------- Single role active ----------
  1523  
  1524  	// Start watching the relation from the perspective of the first unit, and
  1525  	// check the initial event.
  1526  	msw0 := msru0.Watch()
  1527  	defer testing.AssertStop(c, msw0)
  1528  	msw0c := testing.NewRelationUnitsWatcherC(c, msw0)
  1529  	msw0c.AssertChange(nil, []string{"logging"}, nil)
  1530  	msw0c.AssertNoChange()
  1531  
  1532  	// Join the unit to the relation, change its settings, and check that
  1533  	// nothing apparently happens.
  1534  	err = msru0.EnterScope(nil)
  1535  	c.Assert(err, jc.ErrorIsNil)
  1536  	changeSettings(c, msru0)
  1537  	msw0c.AssertNoChange()
  1538  
  1539  	// Watch the relation from the perspective of the second provider, and
  1540  	// check initial event.
  1541  	msw1 := msru1.Watch()
  1542  	defer testing.AssertStop(c, msw1)
  1543  	msw1c := testing.NewRelationUnitsWatcherC(c, msw1)
  1544  	msw1c.AssertChange(nil, []string{"logging"}, nil)
  1545  	msw1c.AssertNoChange()
  1546  
  1547  	// Join the second provider unit to the relation, and check that neither
  1548  	// watching unit observes any change.
  1549  	err = msru1.EnterScope(nil)
  1550  	c.Assert(err, jc.ErrorIsNil)
  1551  	msw1c.AssertNoChange()
  1552  	msw0c.AssertNoChange()
  1553  
  1554  	// Change the unit's settings, and check that nothing apparently happens.
  1555  	changeSettings(c, msru1)
  1556  	msw1c.AssertNoChange()
  1557  	msw0c.AssertNoChange()
  1558  
  1559  	// ---------- Two roles active ----------
  1560  
  1561  	// Start a watch from the first requirer unit's perspective, and check it
  1562  	// only sees the first provider (with which it shares a container).
  1563  	lgw0 := lgru0.Watch()
  1564  	defer testing.AssertStop(c, lgw0)
  1565  	lgw0c := testing.NewRelationUnitsWatcherC(c, lgw0)
  1566  	expectChanged := []string{"mysql/0"}
  1567  	lgw0c.AssertChange(expectChanged, []string{"mysql"}, nil)
  1568  	lgw0c.AssertNoChange()
  1569  
  1570  	// Join the first requirer unit, and check that only the first provider
  1571  	// observes the change.
  1572  	err = lgru0.EnterScope(nil)
  1573  	c.Assert(err, jc.ErrorIsNil)
  1574  	expectChanged = []string{"logging/0"}
  1575  	msw0c.AssertChange(expectChanged, nil, nil)
  1576  	msw0c.AssertNoChange()
  1577  	msw1c.AssertNoChange()
  1578  	lgw0c.AssertNoChange()
  1579  
  1580  	// Watch from the second requirer's perspective, and check it only sees the
  1581  	// second provider.
  1582  	lgw1 := lgru1.Watch()
  1583  	defer testing.AssertStop(c, lgw1)
  1584  	lgw1c := testing.NewRelationUnitsWatcherC(c, lgw1)
  1585  	expectChanged = []string{"mysql/1"}
  1586  	lgw1c.AssertChange(expectChanged, []string{"mysql"}, nil)
  1587  	lgw1c.AssertNoChange()
  1588  
  1589  	// Join the second requirer, and check that the first provider observes it...
  1590  	err = lgru1.EnterScope(nil)
  1591  	c.Assert(err, jc.ErrorIsNil)
  1592  	expectChanged = []string{"logging/1"}
  1593  	msw1c.AssertChange(expectChanged, nil, nil)
  1594  	msw1c.AssertNoChange()
  1595  
  1596  	// ...and that nothing else sees anything.
  1597  	msw0c.AssertNoChange()
  1598  	lgw0c.AssertNoChange()
  1599  	lgw1c.AssertNoChange()
  1600  
  1601  	// Change the second provider's settings and check that the second
  1602  	// requirer notices...
  1603  	changeSettings(c, msru1)
  1604  	expectChanged = []string{"mysql/1"}
  1605  	lgw1c.AssertChange(expectChanged, nil, nil)
  1606  	lgw1c.AssertNoChange()
  1607  
  1608  	// ...but that nothing else does.
  1609  	msw0c.AssertNoChange()
  1610  	msw1c.AssertNoChange()
  1611  	lgw0c.AssertNoChange()
  1612  
  1613  	// Change the provider application settings, and see that all requirers notice
  1614  	updateAppSettings(c, s.State, rel, mysql, "mysql/0", map[string]interface{}{"foo": "bar"})
  1615  	lgw0c.AssertChange(nil, []string{"mysql"}, nil)
  1616  	lgw1c.AssertChange(nil, []string{"mysql"}, nil)
  1617  	msw0c.AssertNoChange()
  1618  	msw1c.AssertNoChange()
  1619  
  1620  	// Finally, depart the first provider, and check that only the first
  1621  	// requirer observes any change.
  1622  	err = msru0.LeaveScope()
  1623  	c.Assert(err, jc.ErrorIsNil)
  1624  	expectDeparted := []string{"mysql/0"}
  1625  	lgw0c.AssertChange(nil, nil, expectDeparted)
  1626  	lgw0c.AssertNoChange()
  1627  	lgw1c.AssertNoChange()
  1628  	msw0c.AssertNoChange()
  1629  	msw1c.AssertNoChange()
  1630  
  1631  	// Again, I think we're done, and can be comfortable that the appropriate
  1632  	// connections are in place.
  1633  }
  1634  
  1635  type WatchUnitsSuite struct {
  1636  	ConnSuite
  1637  }
  1638  
  1639  var _ = gc.Suite(&WatchUnitsSuite{})
  1640  
  1641  // updateAppSettings will update the application settings in a relation.
  1642  // It claims leadership of the application for "unitName" and then sets the
  1643  // application settings for that application to the provided settings.
  1644  func updateAppSettings(c *gc.C, state *state.State, rel *state.Relation, app *state.Application, unitName string, settings map[string]interface{}) {
  1645  	c.Assert(rel.UpdateApplicationSettings(app.Name(), &fakeToken{}, settings), jc.ErrorIsNil)
  1646  }
  1647  
  1648  func (s *WatchUnitsSuite) TestProviderRequirerGlobal(c *gc.C) {
  1649  	// Create a pair of applications and a relation between them.
  1650  	mysql := s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1651  	mysqlEP, err := mysql.Endpoint("server")
  1652  	c.Assert(err, jc.ErrorIsNil)
  1653  	wordpress := s.AddTestingApplication(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
  1654  	wordpressEP, err := wordpress.Endpoint("db")
  1655  	c.Assert(err, jc.ErrorIsNil)
  1656  	rel, err := s.State.AddRelation(mysqlEP, wordpressEP)
  1657  	c.Assert(err, jc.ErrorIsNil)
  1658  
  1659  	// Add some units to the applications and set their private addresses.
  1660  	addUnit := func(srv *state.Application) *state.RelationUnit {
  1661  		unit, err := srv.AddUnit(state.AddUnitParams{})
  1662  		c.Assert(err, jc.ErrorIsNil)
  1663  		ru, err := rel.Unit(unit)
  1664  		c.Assert(err, jc.ErrorIsNil)
  1665  		return ru
  1666  	}
  1667  	mysql0 := addUnit(mysql)
  1668  	wordpress0 := addUnit(wordpress)
  1669  	s.WaitForModelWatchersIdle(c, s.State.ModelUUID())
  1670  
  1671  	wordpressWatcher, err := rel.WatchUnits("wordpress")
  1672  	c.Assert(err, jc.ErrorIsNil)
  1673  	defer testing.AssertStop(c, wordpressWatcher)
  1674  	wordpressWatcherC := testing.NewRelationUnitsWatcherC(c, wordpressWatcher)
  1675  	wordpressWatcherC.AssertChange(nil, []string{"wordpress"}, nil)
  1676  	wordpressWatcherC.AssertNoChange()
  1677  
  1678  	// Join the mysql unit to the relation, change settings, and check
  1679  	// that only the mysql relation units watcher triggers.
  1680  	err = mysql0.EnterScope(nil)
  1681  	c.Assert(err, jc.ErrorIsNil)
  1682  	changeSettings(c, mysql0)
  1683  	s.WaitForModelWatchersIdle(c, s.Model.UUID())
  1684  
  1685  	c.Logf("watching just mysql")
  1686  	mysqlWatcher, err := rel.WatchUnits("mysql")
  1687  	c.Assert(err, jc.ErrorIsNil)
  1688  	defer testing.AssertStop(c, mysqlWatcher)
  1689  	mysqlWatcherC := testing.NewRelationUnitsWatcherC(c, mysqlWatcher)
  1690  	mysqlWatcherC.AssertChange([]string{"mysql/0"}, []string{"mysql"}, nil)
  1691  	mysqlWatcherC.AssertNoChange()
  1692  	wordpressWatcherC.AssertNoChange()
  1693  
  1694  	// Now join the wordpress unit to the relation, and check that only
  1695  	// the wordpress relation units watcher triggers.
  1696  	err = wordpress0.EnterScope(nil)
  1697  	c.Assert(err, jc.ErrorIsNil)
  1698  	wordpressWatcherC.AssertChange([]string{"wordpress/0"}, nil, nil)
  1699  	wordpressWatcherC.AssertNoChange()
  1700  	mysqlWatcherC.AssertNoChange()
  1701  
  1702  	// Now update the mysql application settings, and see that only the mysql watcher notices
  1703  	updateAppSettings(c, s.State, rel, mysql, "mysql/0", map[string]interface{}{"foo": "bar"})
  1704  	mysqlWatcherC.AssertChange(nil, []string{"mysql"}, nil)
  1705  	mysqlWatcherC.AssertNoChange()
  1706  	wordpressWatcherC.AssertNoChange()
  1707  }
  1708  
  1709  func (s *WatchUnitsSuite) TestProviderRequirerContainer(c *gc.C) {
  1710  	// Create a pair of applications and a relation between them.
  1711  	mysql := s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1712  	mysqlEP, err := mysql.Endpoint("juju-info")
  1713  	c.Assert(err, jc.ErrorIsNil)
  1714  	logging := s.AddTestingApplication(c, "logging", s.AddTestingCharm(c, "logging"))
  1715  	loggingEP, err := logging.Endpoint("info")
  1716  	c.Assert(err, jc.ErrorIsNil)
  1717  	rel, err := s.State.AddRelation(mysqlEP, loggingEP)
  1718  	c.Assert(err, jc.ErrorIsNil)
  1719  	s.WaitForModelWatchersIdle(c, s.State.ModelUUID())
  1720  
  1721  	_, err = rel.WatchUnits("mysql")
  1722  	c.Assert(err, gc.ErrorMatches, `"juju-info" endpoint is not globally scoped`)
  1723  	_, err = rel.WatchUnits("logging")
  1724  	c.Assert(err, gc.ErrorMatches, `"info" endpoint is not globally scoped`)
  1725  }
  1726  
  1727  func changeSettings(c *gc.C, ru *state.RelationUnit) {
  1728  	node, err := ru.Settings()
  1729  	c.Assert(err, jc.ErrorIsNil)
  1730  	value, _ := node.Get("value")
  1731  	v, _ := value.(int)
  1732  	node.Set("value", v+1)
  1733  	_, err = node.Write()
  1734  	c.Assert(err, jc.ErrorIsNil)
  1735  }