github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/uniter/uniter_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  	stdtesting "testing"
     8  
     9  	gc "launchpad.net/gocheck"
    10  
    11  	"launchpad.net/juju-core/charm"
    12  	envtesting "launchpad.net/juju-core/environs/testing"
    13  	"launchpad.net/juju-core/errors"
    14  	"launchpad.net/juju-core/instance"
    15  	"launchpad.net/juju-core/juju/testing"
    16  	"launchpad.net/juju-core/state"
    17  	"launchpad.net/juju-core/state/api/params"
    18  	"launchpad.net/juju-core/state/apiserver/common"
    19  	commontesting "launchpad.net/juju-core/state/apiserver/common/testing"
    20  	apiservertesting "launchpad.net/juju-core/state/apiserver/testing"
    21  	"launchpad.net/juju-core/state/apiserver/uniter"
    22  	statetesting "launchpad.net/juju-core/state/testing"
    23  	coretesting "launchpad.net/juju-core/testing"
    24  	jc "launchpad.net/juju-core/testing/checkers"
    25  )
    26  
    27  func Test(t *stdtesting.T) {
    28  	coretesting.MgoTestPackage(t)
    29  }
    30  
    31  type uniterSuite struct {
    32  	testing.JujuConnSuite
    33  	*commontesting.EnvironWatcherTest
    34  
    35  	authorizer apiservertesting.FakeAuthorizer
    36  	resources  *common.Resources
    37  
    38  	machine0      *state.Machine
    39  	machine1      *state.Machine
    40  	wordpress     *state.Service
    41  	wpCharm       *state.Charm
    42  	mysql         *state.Service
    43  	wordpressUnit *state.Unit
    44  	mysqlUnit     *state.Unit
    45  
    46  	uniter *uniter.UniterAPI
    47  }
    48  
    49  var _ = gc.Suite(&uniterSuite{})
    50  
    51  func (s *uniterSuite) SetUpTest(c *gc.C) {
    52  	s.JujuConnSuite.SetUpTest(c)
    53  
    54  	s.wpCharm = s.AddTestingCharm(c, "wordpress")
    55  	// Create two machines, two services and add a unit to each service.
    56  	var err error
    57  	s.machine0, err = s.State.AddMachine("quantal", state.JobHostUnits, state.JobManageEnviron)
    58  	c.Assert(err, gc.IsNil)
    59  	s.machine1, err = s.State.AddMachine("quantal", state.JobHostUnits)
    60  	c.Assert(err, gc.IsNil)
    61  	s.wordpress = s.AddTestingService(c, "wordpress", s.wpCharm)
    62  	s.mysql = s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
    63  	s.wordpressUnit, err = s.wordpress.AddUnit()
    64  	c.Assert(err, gc.IsNil)
    65  	s.mysqlUnit, err = s.mysql.AddUnit()
    66  	c.Assert(err, gc.IsNil)
    67  	// Assign each unit to each machine.
    68  	err = s.wordpressUnit.AssignToMachine(s.machine0)
    69  	c.Assert(err, gc.IsNil)
    70  	err = s.mysqlUnit.AssignToMachine(s.machine1)
    71  	c.Assert(err, gc.IsNil)
    72  
    73  	// Create a FakeAuthorizer so we can check permissions,
    74  	// set up assuming unit 0 has logged in.
    75  	s.authorizer = apiservertesting.FakeAuthorizer{
    76  		Tag:       s.wordpressUnit.Tag(),
    77  		LoggedIn:  true,
    78  		UnitAgent: true,
    79  		Entity:    s.wordpressUnit,
    80  	}
    81  
    82  	// Create the resource registry separately to track invocations to
    83  	// Register.
    84  	s.resources = common.NewResources()
    85  
    86  	// Create a uniter API for unit 0.
    87  	s.uniter, err = uniter.NewUniterAPI(
    88  		s.State,
    89  		s.resources,
    90  		s.authorizer,
    91  	)
    92  	c.Assert(err, gc.IsNil)
    93  	s.EnvironWatcherTest = commontesting.NewEnvironWatcherTest(s.uniter, s.State, s.resources, commontesting.NoSecrets)
    94  }
    95  
    96  func (s *uniterSuite) TestUniterFailsWithNonUnitAgentUser(c *gc.C) {
    97  	anAuthorizer := s.authorizer
    98  	anAuthorizer.UnitAgent = false
    99  	anUniter, err := uniter.NewUniterAPI(s.State, s.resources, anAuthorizer)
   100  	c.Assert(err, gc.NotNil)
   101  	c.Assert(anUniter, gc.IsNil)
   102  	c.Assert(err, gc.ErrorMatches, "permission denied")
   103  }
   104  
   105  func (s *uniterSuite) TestSetStatus(c *gc.C) {
   106  	err := s.wordpressUnit.SetStatus(params.StatusStarted, "blah", nil)
   107  	c.Assert(err, gc.IsNil)
   108  	err = s.mysqlUnit.SetStatus(params.StatusStopped, "foo", nil)
   109  	c.Assert(err, gc.IsNil)
   110  
   111  	args := params.SetStatus{
   112  		Entities: []params.SetEntityStatus{
   113  			{Tag: "unit-mysql-0", Status: params.StatusError, Info: "not really"},
   114  			{Tag: "unit-wordpress-0", Status: params.StatusStopped, Info: "foobar"},
   115  			{Tag: "unit-foo-42", Status: params.StatusStarted, Info: "blah"},
   116  		}}
   117  	result, err := s.uniter.SetStatus(args)
   118  	c.Assert(err, gc.IsNil)
   119  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   120  		Results: []params.ErrorResult{
   121  			{apiservertesting.ErrUnauthorized},
   122  			{nil},
   123  			{apiservertesting.ErrUnauthorized},
   124  		},
   125  	})
   126  
   127  	// Verify mysqlUnit - no change.
   128  	status, info, _, err := s.mysqlUnit.Status()
   129  	c.Assert(err, gc.IsNil)
   130  	c.Assert(status, gc.Equals, params.StatusStopped)
   131  	c.Assert(info, gc.Equals, "foo")
   132  	// ...wordpressUnit is fine though.
   133  	status, info, _, err = s.wordpressUnit.Status()
   134  	c.Assert(err, gc.IsNil)
   135  	c.Assert(status, gc.Equals, params.StatusStopped)
   136  	c.Assert(info, gc.Equals, "foobar")
   137  }
   138  
   139  func (s *uniterSuite) TestLife(c *gc.C) {
   140  	// Add a relation wordpress-mysql.
   141  	rel := s.addRelation(c, "wordpress", "mysql")
   142  	relUnit, err := rel.Unit(s.wordpressUnit)
   143  	c.Assert(err, gc.IsNil)
   144  	err = relUnit.EnterScope(nil)
   145  	c.Assert(err, gc.IsNil)
   146  	c.Assert(rel.Life(), gc.Equals, state.Alive)
   147  
   148  	// Make the wordpressUnit dead.
   149  	err = s.wordpressUnit.EnsureDead()
   150  	c.Assert(err, gc.IsNil)
   151  	err = s.wordpressUnit.Refresh()
   152  	c.Assert(err, gc.IsNil)
   153  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead)
   154  
   155  	// Add another unit, so the service will stay dying when we
   156  	// destroy it later.
   157  	extraUnit, err := s.wordpress.AddUnit()
   158  	c.Assert(err, gc.IsNil)
   159  	c.Assert(extraUnit, gc.NotNil)
   160  
   161  	// Make the wordpress service dying.
   162  	err = s.wordpress.Destroy()
   163  	c.Assert(err, gc.IsNil)
   164  	err = s.wordpress.Refresh()
   165  	c.Assert(err, gc.IsNil)
   166  	c.Assert(s.wordpress.Life(), gc.Equals, state.Dying)
   167  
   168  	args := params.Entities{Entities: []params.Entity{
   169  		{Tag: "unit-mysql-0"},
   170  		{Tag: "unit-wordpress-0"},
   171  		{Tag: "unit-foo-42"},
   172  		{Tag: "service-mysql"},
   173  		{Tag: "service-wordpress"},
   174  		{Tag: "service-foo"},
   175  		{Tag: "just-foo"},
   176  		{Tag: rel.Tag()},
   177  		{Tag: "relation-svc1.rel1#svc2.rel2"},
   178  		{Tag: "relation-blah"},
   179  	}}
   180  	result, err := s.uniter.Life(args)
   181  	c.Assert(err, gc.IsNil)
   182  	c.Assert(result, gc.DeepEquals, params.LifeResults{
   183  		Results: []params.LifeResult{
   184  			{Error: apiservertesting.ErrUnauthorized},
   185  			{Life: "dead"},
   186  			{Error: apiservertesting.ErrUnauthorized},
   187  			{Error: apiservertesting.ErrUnauthorized},
   188  			{Life: "dying"},
   189  			{Error: apiservertesting.ErrUnauthorized},
   190  			{Error: apiservertesting.ErrUnauthorized},
   191  			{Error: apiservertesting.ErrUnauthorized},
   192  			{Error: apiservertesting.ErrUnauthorized},
   193  			{Error: apiservertesting.ErrUnauthorized},
   194  		},
   195  	})
   196  }
   197  
   198  func (s *uniterSuite) TestEnsureDead(c *gc.C) {
   199  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive)
   200  	c.Assert(s.mysqlUnit.Life(), gc.Equals, state.Alive)
   201  
   202  	args := params.Entities{Entities: []params.Entity{
   203  		{Tag: "unit-mysql-0"},
   204  		{Tag: "unit-wordpress-0"},
   205  		{Tag: "unit-foo-42"},
   206  	}}
   207  	result, err := s.uniter.EnsureDead(args)
   208  	c.Assert(err, gc.IsNil)
   209  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   210  		Results: []params.ErrorResult{
   211  			{apiservertesting.ErrUnauthorized},
   212  			{nil},
   213  			{apiservertesting.ErrUnauthorized},
   214  		},
   215  	})
   216  
   217  	err = s.wordpressUnit.Refresh()
   218  	c.Assert(err, gc.IsNil)
   219  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead)
   220  	err = s.mysqlUnit.Refresh()
   221  	c.Assert(err, gc.IsNil)
   222  	c.Assert(s.mysqlUnit.Life(), gc.Equals, state.Alive)
   223  
   224  	// Try it again on a Dead unit; should work.
   225  	args = params.Entities{
   226  		Entities: []params.Entity{{Tag: "unit-wordpress-0"}},
   227  	}
   228  	result, err = s.uniter.EnsureDead(args)
   229  	c.Assert(err, gc.IsNil)
   230  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   231  		Results: []params.ErrorResult{{nil}},
   232  	})
   233  
   234  	// Verify Life is unchanged.
   235  	err = s.wordpressUnit.Refresh()
   236  	c.Assert(err, gc.IsNil)
   237  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead)
   238  }
   239  
   240  func (s *uniterSuite) assertOneStringsWatcher(c *gc.C, result params.StringsWatchResults, err error) {
   241  	c.Assert(err, gc.IsNil)
   242  	c.Assert(result.Results, gc.HasLen, 3)
   243  	c.Assert(result.Results[0].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized)
   244  	c.Assert(result.Results[1].StringsWatcherId, gc.Equals, "1")
   245  	c.Assert(result.Results[1].Changes, gc.NotNil)
   246  	c.Assert(result.Results[1].Error, gc.IsNil)
   247  	c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized)
   248  
   249  	// Verify the resource was registered and stop when done
   250  	c.Assert(s.resources.Count(), gc.Equals, 1)
   251  	resource := s.resources.Get("1")
   252  	defer statetesting.AssertStop(c, resource)
   253  
   254  	// Check that the Watch has consumed the initial event ("returned" in
   255  	// the Watch call)
   256  	wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher))
   257  	wc.AssertNoChange()
   258  }
   259  
   260  func (s *uniterSuite) TestWatch(c *gc.C) {
   261  	c.Assert(s.resources.Count(), gc.Equals, 0)
   262  
   263  	args := params.Entities{Entities: []params.Entity{
   264  		{Tag: "unit-mysql-0"},
   265  		{Tag: "unit-wordpress-0"},
   266  		{Tag: "unit-foo-42"},
   267  		{Tag: "service-mysql"},
   268  		{Tag: "service-wordpress"},
   269  		{Tag: "service-foo"},
   270  		{Tag: "just-foo"},
   271  	}}
   272  	result, err := s.uniter.Watch(args)
   273  	c.Assert(err, gc.IsNil)
   274  	c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{
   275  		Results: []params.NotifyWatchResult{
   276  			{Error: apiservertesting.ErrUnauthorized},
   277  			{NotifyWatcherId: "1"},
   278  			{Error: apiservertesting.ErrUnauthorized},
   279  			{Error: apiservertesting.ErrUnauthorized},
   280  			{NotifyWatcherId: "2"},
   281  			{Error: apiservertesting.ErrUnauthorized},
   282  			{Error: apiservertesting.ErrUnauthorized},
   283  		},
   284  	})
   285  
   286  	// Verify the resource was registered and stop when done
   287  	c.Assert(s.resources.Count(), gc.Equals, 2)
   288  	resource1 := s.resources.Get("1")
   289  	defer statetesting.AssertStop(c, resource1)
   290  	resource2 := s.resources.Get("2")
   291  	defer statetesting.AssertStop(c, resource2)
   292  
   293  	// Check that the Watch has consumed the initial event ("returned" in
   294  	// the Watch call)
   295  	wc := statetesting.NewNotifyWatcherC(c, s.State, resource1.(state.NotifyWatcher))
   296  	wc.AssertNoChange()
   297  	wc = statetesting.NewNotifyWatcherC(c, s.State, resource2.(state.NotifyWatcher))
   298  	wc.AssertNoChange()
   299  }
   300  
   301  func (s *uniterSuite) TestPublicAddress(c *gc.C) {
   302  	// Try first without setting an address.
   303  	args := params.Entities{Entities: []params.Entity{
   304  		{Tag: "unit-mysql-0"},
   305  		{Tag: "unit-wordpress-0"},
   306  		{Tag: "unit-foo-42"},
   307  	}}
   308  	expectErr := &params.Error{
   309  		Code:    params.CodeNoAddressSet,
   310  		Message: `"unit-wordpress-0" has no public address set`,
   311  	}
   312  	result, err := s.uniter.PublicAddress(args)
   313  	c.Assert(err, gc.IsNil)
   314  	c.Assert(result, gc.DeepEquals, params.StringResults{
   315  		Results: []params.StringResult{
   316  			{Error: apiservertesting.ErrUnauthorized},
   317  			{Error: expectErr},
   318  			{Error: apiservertesting.ErrUnauthorized},
   319  		},
   320  	})
   321  
   322  	// Now set it an try again.
   323  	err = s.wordpressUnit.SetPublicAddress("1.2.3.4")
   324  	c.Assert(err, gc.IsNil)
   325  	address, ok := s.wordpressUnit.PublicAddress()
   326  	c.Assert(address, gc.Equals, "1.2.3.4")
   327  	c.Assert(ok, jc.IsTrue)
   328  
   329  	result, err = s.uniter.PublicAddress(args)
   330  	c.Assert(err, gc.IsNil)
   331  	c.Assert(result, gc.DeepEquals, params.StringResults{
   332  		Results: []params.StringResult{
   333  			{Error: apiservertesting.ErrUnauthorized},
   334  			{Result: "1.2.3.4"},
   335  			{Error: apiservertesting.ErrUnauthorized},
   336  		},
   337  	})
   338  }
   339  
   340  func (s *uniterSuite) TestSetPublicAddress(c *gc.C) {
   341  	err := s.wordpressUnit.SetPublicAddress("1.2.3.4")
   342  	c.Assert(err, gc.IsNil)
   343  	address, ok := s.wordpressUnit.PublicAddress()
   344  	c.Assert(address, gc.Equals, "1.2.3.4")
   345  	c.Assert(ok, jc.IsTrue)
   346  
   347  	args := params.SetEntityAddresses{Entities: []params.SetEntityAddress{
   348  		{Tag: "unit-mysql-0", Address: "4.3.2.1"},
   349  		{Tag: "unit-wordpress-0", Address: "4.4.2.2"},
   350  		{Tag: "unit-foo-42", Address: "2.2.4.4"},
   351  	}}
   352  	result, err := s.uniter.SetPublicAddress(args)
   353  	c.Assert(err, gc.IsNil)
   354  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   355  		Results: []params.ErrorResult{
   356  			{apiservertesting.ErrUnauthorized},
   357  			{nil},
   358  			{apiservertesting.ErrUnauthorized},
   359  		},
   360  	})
   361  
   362  	// Verify wordpressUnit's address has changed.
   363  	err = s.wordpressUnit.Refresh()
   364  	c.Assert(err, gc.IsNil)
   365  	address, ok = s.wordpressUnit.PublicAddress()
   366  	c.Assert(address, gc.Equals, "4.4.2.2")
   367  	c.Assert(ok, jc.IsTrue)
   368  }
   369  
   370  func (s *uniterSuite) TestPrivateAddress(c *gc.C) {
   371  	args := params.Entities{Entities: []params.Entity{
   372  		{Tag: "unit-mysql-0"},
   373  		{Tag: "unit-wordpress-0"},
   374  		{Tag: "unit-foo-42"},
   375  	}}
   376  	expectErr := &params.Error{
   377  		Code:    params.CodeNoAddressSet,
   378  		Message: `"unit-wordpress-0" has no private address set`,
   379  	}
   380  	result, err := s.uniter.PrivateAddress(args)
   381  	c.Assert(err, gc.IsNil)
   382  	c.Assert(result, gc.DeepEquals, params.StringResults{
   383  		Results: []params.StringResult{
   384  			{Error: apiservertesting.ErrUnauthorized},
   385  			{Error: expectErr},
   386  			{Error: apiservertesting.ErrUnauthorized},
   387  		},
   388  	})
   389  
   390  	// Now set it and try again.
   391  	err = s.wordpressUnit.SetPrivateAddress("1.2.3.4")
   392  	c.Assert(err, gc.IsNil)
   393  	address, ok := s.wordpressUnit.PrivateAddress()
   394  	c.Assert(address, gc.Equals, "1.2.3.4")
   395  	c.Assert(ok, jc.IsTrue)
   396  
   397  	result, err = s.uniter.PrivateAddress(args)
   398  	c.Assert(err, gc.IsNil)
   399  	c.Assert(result, gc.DeepEquals, params.StringResults{
   400  		Results: []params.StringResult{
   401  			{Error: apiservertesting.ErrUnauthorized},
   402  			{Result: "1.2.3.4"},
   403  			{Error: apiservertesting.ErrUnauthorized},
   404  		},
   405  	})
   406  }
   407  
   408  func (s *uniterSuite) TestSetPrivateAddress(c *gc.C) {
   409  	err := s.wordpressUnit.SetPrivateAddress("1.2.3.4")
   410  	c.Assert(err, gc.IsNil)
   411  	address, ok := s.wordpressUnit.PrivateAddress()
   412  	c.Assert(address, gc.Equals, "1.2.3.4")
   413  	c.Assert(ok, jc.IsTrue)
   414  
   415  	args := params.SetEntityAddresses{Entities: []params.SetEntityAddress{
   416  		{Tag: "unit-mysql-0", Address: "4.3.2.1"},
   417  		{Tag: "unit-wordpress-0", Address: "4.4.2.2"},
   418  		{Tag: "unit-foo-42", Address: "2.2.4.4"},
   419  	}}
   420  	result, err := s.uniter.SetPrivateAddress(args)
   421  	c.Assert(err, gc.IsNil)
   422  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   423  		Results: []params.ErrorResult{
   424  			{apiservertesting.ErrUnauthorized},
   425  			{nil},
   426  			{apiservertesting.ErrUnauthorized},
   427  		},
   428  	})
   429  
   430  	// Verify wordpressUnit's address has changed.
   431  	err = s.wordpressUnit.Refresh()
   432  	c.Assert(err, gc.IsNil)
   433  	address, ok = s.wordpressUnit.PrivateAddress()
   434  	c.Assert(address, gc.Equals, "4.4.2.2")
   435  	c.Assert(ok, jc.IsTrue)
   436  }
   437  
   438  func (s *uniterSuite) TestResolved(c *gc.C) {
   439  	err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks)
   440  	c.Assert(err, gc.IsNil)
   441  	mode := s.wordpressUnit.Resolved()
   442  	c.Assert(mode, gc.Equals, state.ResolvedRetryHooks)
   443  
   444  	args := params.Entities{Entities: []params.Entity{
   445  		{Tag: "unit-mysql-0"},
   446  		{Tag: "unit-wordpress-0"},
   447  		{Tag: "unit-foo-42"},
   448  	}}
   449  	result, err := s.uniter.Resolved(args)
   450  	c.Assert(err, gc.IsNil)
   451  	c.Assert(result, gc.DeepEquals, params.ResolvedModeResults{
   452  		Results: []params.ResolvedModeResult{
   453  			{Error: apiservertesting.ErrUnauthorized},
   454  			{Mode: params.ResolvedMode(mode)},
   455  			{Error: apiservertesting.ErrUnauthorized},
   456  		},
   457  	})
   458  }
   459  
   460  func (s *uniterSuite) TestClearResolved(c *gc.C) {
   461  	err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks)
   462  	c.Assert(err, gc.IsNil)
   463  	mode := s.wordpressUnit.Resolved()
   464  	c.Assert(mode, gc.Equals, state.ResolvedRetryHooks)
   465  
   466  	args := params.Entities{Entities: []params.Entity{
   467  		{Tag: "unit-mysql-0"},
   468  		{Tag: "unit-wordpress-0"},
   469  		{Tag: "unit-foo-42"},
   470  	}}
   471  	result, err := s.uniter.ClearResolved(args)
   472  	c.Assert(err, gc.IsNil)
   473  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   474  		Results: []params.ErrorResult{
   475  			{apiservertesting.ErrUnauthorized},
   476  			{nil},
   477  			{apiservertesting.ErrUnauthorized},
   478  		},
   479  	})
   480  
   481  	// Verify wordpressUnit's resolved mode has changed.
   482  	err = s.wordpressUnit.Refresh()
   483  	c.Assert(err, gc.IsNil)
   484  	mode = s.wordpressUnit.Resolved()
   485  	c.Assert(mode, gc.Equals, state.ResolvedNone)
   486  }
   487  
   488  func (s *uniterSuite) TestGetPrincipal(c *gc.C) {
   489  	// Add a subordinate to wordpressUnit.
   490  	_, _, subordinate := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   491  
   492  	principal, ok := subordinate.PrincipalName()
   493  	c.Assert(principal, gc.Equals, s.wordpressUnit.Name())
   494  	c.Assert(ok, jc.IsTrue)
   495  
   496  	// First try it as wordpressUnit's agent.
   497  	args := params.Entities{Entities: []params.Entity{
   498  		{Tag: "unit-mysql-0"},
   499  		{Tag: "unit-wordpress-0"},
   500  		{Tag: subordinate.Tag()},
   501  		{Tag: "unit-foo-42"},
   502  	}}
   503  	result, err := s.uniter.GetPrincipal(args)
   504  	c.Assert(err, gc.IsNil)
   505  	c.Assert(result, gc.DeepEquals, params.StringBoolResults{
   506  		Results: []params.StringBoolResult{
   507  			{Error: apiservertesting.ErrUnauthorized},
   508  			{Result: "", Ok: false, Error: nil},
   509  			{Error: apiservertesting.ErrUnauthorized},
   510  			{Error: apiservertesting.ErrUnauthorized},
   511  		},
   512  	})
   513  
   514  	// Now try as subordinate's agent.
   515  	subAuthorizer := s.authorizer
   516  	subAuthorizer.Tag = subordinate.Tag()
   517  	subUniter, err := uniter.NewUniterAPI(s.State, s.resources, subAuthorizer)
   518  	c.Assert(err, gc.IsNil)
   519  
   520  	result, err = subUniter.GetPrincipal(args)
   521  	c.Assert(err, gc.IsNil)
   522  	c.Assert(result, gc.DeepEquals, params.StringBoolResults{
   523  		Results: []params.StringBoolResult{
   524  			{Error: apiservertesting.ErrUnauthorized},
   525  			{Error: apiservertesting.ErrUnauthorized},
   526  			{Result: "unit-wordpress-0", Ok: true, Error: nil},
   527  			{Error: apiservertesting.ErrUnauthorized},
   528  		},
   529  	})
   530  }
   531  
   532  func (s *uniterSuite) addRelatedService(c *gc.C, firstSvc, relatedSvc string, unit *state.Unit) (*state.Relation, *state.Service, *state.Unit) {
   533  	relatedService := s.AddTestingService(c, relatedSvc, s.AddTestingCharm(c, relatedSvc))
   534  	rel := s.addRelation(c, firstSvc, relatedSvc)
   535  	relUnit, err := rel.Unit(unit)
   536  	c.Assert(err, gc.IsNil)
   537  	err = relUnit.EnterScope(nil)
   538  	c.Assert(err, gc.IsNil)
   539  	relatedUnit, err := relatedService.Unit(relatedSvc + "/0")
   540  	c.Assert(err, gc.IsNil)
   541  	return rel, relatedService, relatedUnit
   542  }
   543  
   544  func (s *uniterSuite) TestHasSubordinates(c *gc.C) {
   545  	// Try first without any subordinates for wordpressUnit.
   546  	args := params.Entities{Entities: []params.Entity{
   547  		{Tag: "unit-mysql-0"},
   548  		{Tag: "unit-wordpress-0"},
   549  		{Tag: "unit-logging-0"},
   550  		{Tag: "unit-foo-42"},
   551  	}}
   552  	result, err := s.uniter.HasSubordinates(args)
   553  	c.Assert(err, gc.IsNil)
   554  	c.Assert(result, gc.DeepEquals, params.BoolResults{
   555  		Results: []params.BoolResult{
   556  			{Error: apiservertesting.ErrUnauthorized},
   557  			{Result: false},
   558  			{Error: apiservertesting.ErrUnauthorized},
   559  			{Error: apiservertesting.ErrUnauthorized},
   560  		},
   561  	})
   562  
   563  	// Add two subordinates to wordpressUnit and try again.
   564  	s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   565  	s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit)
   566  
   567  	result, err = s.uniter.HasSubordinates(args)
   568  	c.Assert(err, gc.IsNil)
   569  	c.Assert(result, gc.DeepEquals, params.BoolResults{
   570  		Results: []params.BoolResult{
   571  			{Error: apiservertesting.ErrUnauthorized},
   572  			{Result: true},
   573  			{Error: apiservertesting.ErrUnauthorized},
   574  			{Error: apiservertesting.ErrUnauthorized},
   575  		},
   576  	})
   577  }
   578  
   579  func (s *uniterSuite) TestDestroy(c *gc.C) {
   580  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive)
   581  
   582  	args := params.Entities{Entities: []params.Entity{
   583  		{Tag: "unit-mysql-0"},
   584  		{Tag: "unit-wordpress-0"},
   585  		{Tag: "unit-foo-42"},
   586  	}}
   587  	result, err := s.uniter.Destroy(args)
   588  	c.Assert(err, gc.IsNil)
   589  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   590  		Results: []params.ErrorResult{
   591  			{apiservertesting.ErrUnauthorized},
   592  			{nil},
   593  			{apiservertesting.ErrUnauthorized},
   594  		},
   595  	})
   596  
   597  	// Verify wordpressUnit is destroyed and removed.
   598  	err = s.wordpressUnit.Refresh()
   599  	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
   600  }
   601  
   602  func (s *uniterSuite) TestDestroyAllSubordinates(c *gc.C) {
   603  	// Add two subordinates to wordpressUnit.
   604  	_, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   605  	_, _, monitoringSub := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit)
   606  	c.Assert(loggingSub.Life(), gc.Equals, state.Alive)
   607  	c.Assert(monitoringSub.Life(), gc.Equals, state.Alive)
   608  
   609  	err := s.wordpressUnit.Refresh()
   610  	c.Assert(err, gc.IsNil)
   611  	subordinates := s.wordpressUnit.SubordinateNames()
   612  	c.Assert(subordinates, gc.DeepEquals, []string{"logging/0", "monitoring/0"})
   613  
   614  	args := params.Entities{Entities: []params.Entity{
   615  		{Tag: "unit-mysql-0"},
   616  		{Tag: "unit-wordpress-0"},
   617  		{Tag: "unit-foo-42"},
   618  	}}
   619  	result, err := s.uniter.DestroyAllSubordinates(args)
   620  	c.Assert(err, gc.IsNil)
   621  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   622  		Results: []params.ErrorResult{
   623  			{apiservertesting.ErrUnauthorized},
   624  			{nil},
   625  			{apiservertesting.ErrUnauthorized},
   626  		},
   627  	})
   628  
   629  	// Verify wordpressUnit's subordinates were destroyed.
   630  	err = loggingSub.Refresh()
   631  	c.Assert(err, gc.IsNil)
   632  	c.Assert(loggingSub.Life(), gc.Equals, state.Dying)
   633  	err = monitoringSub.Refresh()
   634  	c.Assert(err, gc.IsNil)
   635  	c.Assert(monitoringSub.Life(), gc.Equals, state.Dying)
   636  }
   637  
   638  func (s *uniterSuite) TestCharmURL(c *gc.C) {
   639  	// Set wordpressUnit's charm URL first.
   640  	err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL())
   641  	c.Assert(err, gc.IsNil)
   642  	curl, ok := s.wordpressUnit.CharmURL()
   643  	c.Assert(curl, gc.DeepEquals, s.wpCharm.URL())
   644  	c.Assert(ok, jc.IsTrue)
   645  
   646  	// Make sure wordpress service's charm is what we expect.
   647  	curl, force := s.wordpress.CharmURL()
   648  	c.Assert(curl, gc.DeepEquals, s.wpCharm.URL())
   649  	c.Assert(force, jc.IsFalse)
   650  
   651  	args := params.Entities{Entities: []params.Entity{
   652  		{Tag: "unit-mysql-0"},
   653  		{Tag: "unit-wordpress-0"},
   654  		{Tag: "unit-foo-42"},
   655  		{Tag: "service-mysql"},
   656  		{Tag: "service-wordpress"},
   657  		{Tag: "service-foo"},
   658  		{Tag: "just-foo"},
   659  	}}
   660  	result, err := s.uniter.CharmURL(args)
   661  	c.Assert(err, gc.IsNil)
   662  	c.Assert(result, gc.DeepEquals, params.StringBoolResults{
   663  		Results: []params.StringBoolResult{
   664  			{Error: apiservertesting.ErrUnauthorized},
   665  			{Result: s.wpCharm.String(), Ok: ok},
   666  			{Error: apiservertesting.ErrUnauthorized},
   667  			{Error: apiservertesting.ErrUnauthorized},
   668  			{Result: s.wpCharm.String(), Ok: force},
   669  			{Error: apiservertesting.ErrUnauthorized},
   670  			{Error: apiservertesting.ErrUnauthorized},
   671  		},
   672  	})
   673  }
   674  
   675  func (s *uniterSuite) TestSetCharmURL(c *gc.C) {
   676  	charmUrl, ok := s.wordpressUnit.CharmURL()
   677  	c.Assert(charmUrl, gc.IsNil)
   678  	c.Assert(ok, jc.IsFalse)
   679  
   680  	args := params.EntitiesCharmURL{Entities: []params.EntityCharmURL{
   681  		{Tag: "unit-mysql-0", CharmURL: "cs:quantal/service-42"},
   682  		{Tag: "unit-wordpress-0", CharmURL: s.wpCharm.String()},
   683  		{Tag: "unit-foo-42", CharmURL: "cs:quantal/foo-321"},
   684  	}}
   685  	result, err := s.uniter.SetCharmURL(args)
   686  	c.Assert(err, gc.IsNil)
   687  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   688  		Results: []params.ErrorResult{
   689  			{apiservertesting.ErrUnauthorized},
   690  			{nil},
   691  			{apiservertesting.ErrUnauthorized},
   692  		},
   693  	})
   694  
   695  	// Verify the charm URL was set.
   696  	err = s.wordpressUnit.Refresh()
   697  	c.Assert(err, gc.IsNil)
   698  	charmUrl, ok = s.wordpressUnit.CharmURL()
   699  	c.Assert(charmUrl, gc.NotNil)
   700  	c.Assert(charmUrl.String(), gc.Equals, s.wpCharm.String())
   701  	c.Assert(ok, jc.IsTrue)
   702  }
   703  
   704  func (s *uniterSuite) TestOpenPort(c *gc.C) {
   705  	openedPorts := s.wordpressUnit.OpenedPorts()
   706  	c.Assert(openedPorts, gc.HasLen, 0)
   707  
   708  	args := params.EntitiesPorts{Entities: []params.EntityPort{
   709  		{Tag: "unit-mysql-0", Protocol: "tcp", Port: 1234},
   710  		{Tag: "unit-wordpress-0", Protocol: "udp", Port: 4321},
   711  		{Tag: "unit-foo-42", Protocol: "tcp", Port: 42},
   712  	}}
   713  	result, err := s.uniter.OpenPort(args)
   714  	c.Assert(err, gc.IsNil)
   715  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   716  		Results: []params.ErrorResult{
   717  			{apiservertesting.ErrUnauthorized},
   718  			{nil},
   719  			{apiservertesting.ErrUnauthorized},
   720  		},
   721  	})
   722  
   723  	// Verify the wordpressUnit's port is opened.
   724  	err = s.wordpressUnit.Refresh()
   725  	c.Assert(err, gc.IsNil)
   726  	openedPorts = s.wordpressUnit.OpenedPorts()
   727  	c.Assert(openedPorts, gc.DeepEquals, []instance.Port{
   728  		{Protocol: "udp", Number: 4321},
   729  	})
   730  }
   731  
   732  func (s *uniterSuite) TestClosePort(c *gc.C) {
   733  	// Open port udp:4321 in advance on wordpressUnit.
   734  	err := s.wordpressUnit.OpenPort("udp", 4321)
   735  	c.Assert(err, gc.IsNil)
   736  	err = s.wordpressUnit.Refresh()
   737  	c.Assert(err, gc.IsNil)
   738  	openedPorts := s.wordpressUnit.OpenedPorts()
   739  	c.Assert(openedPorts, gc.DeepEquals, []instance.Port{
   740  		{Protocol: "udp", Number: 4321},
   741  	})
   742  
   743  	args := params.EntitiesPorts{Entities: []params.EntityPort{
   744  		{Tag: "unit-mysql-0", Protocol: "tcp", Port: 1234},
   745  		{Tag: "unit-wordpress-0", Protocol: "udp", Port: 4321},
   746  		{Tag: "unit-foo-42", Protocol: "tcp", Port: 42},
   747  	}}
   748  	result, err := s.uniter.ClosePort(args)
   749  	c.Assert(err, gc.IsNil)
   750  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   751  		Results: []params.ErrorResult{
   752  			{apiservertesting.ErrUnauthorized},
   753  			{nil},
   754  			{apiservertesting.ErrUnauthorized},
   755  		},
   756  	})
   757  
   758  	// Verify the wordpressUnit's port is closed.
   759  	err = s.wordpressUnit.Refresh()
   760  	c.Assert(err, gc.IsNil)
   761  	openedPorts = s.wordpressUnit.OpenedPorts()
   762  	c.Assert(openedPorts, gc.HasLen, 0)
   763  }
   764  
   765  func (s *uniterSuite) TestWatchConfigSettings(c *gc.C) {
   766  	err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL())
   767  	c.Assert(err, gc.IsNil)
   768  
   769  	c.Assert(s.resources.Count(), gc.Equals, 0)
   770  
   771  	args := params.Entities{Entities: []params.Entity{
   772  		{Tag: "unit-mysql-0"},
   773  		{Tag: "unit-wordpress-0"},
   774  		{Tag: "unit-foo-42"},
   775  	}}
   776  	result, err := s.uniter.WatchConfigSettings(args)
   777  	c.Assert(err, gc.IsNil)
   778  	c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{
   779  		Results: []params.NotifyWatchResult{
   780  			{Error: apiservertesting.ErrUnauthorized},
   781  			{NotifyWatcherId: "1"},
   782  			{Error: apiservertesting.ErrUnauthorized},
   783  		},
   784  	})
   785  
   786  	// Verify the resource was registered and stop when done
   787  	c.Assert(s.resources.Count(), gc.Equals, 1)
   788  	resource := s.resources.Get("1")
   789  	defer statetesting.AssertStop(c, resource)
   790  
   791  	// Check that the Watch has consumed the initial event ("returned" in
   792  	// the Watch call)
   793  	wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher))
   794  	wc.AssertNoChange()
   795  }
   796  
   797  func (s *uniterSuite) TestConfigSettings(c *gc.C) {
   798  	err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL())
   799  	c.Assert(err, gc.IsNil)
   800  	settings, err := s.wordpressUnit.ConfigSettings()
   801  	c.Assert(err, gc.IsNil)
   802  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"})
   803  
   804  	args := params.Entities{Entities: []params.Entity{
   805  		{Tag: "unit-mysql-0"},
   806  		{Tag: "unit-wordpress-0"},
   807  		{Tag: "unit-foo-42"},
   808  	}}
   809  	result, err := s.uniter.ConfigSettings(args)
   810  	c.Assert(err, gc.IsNil)
   811  	c.Assert(result, gc.DeepEquals, params.ConfigSettingsResults{
   812  		Results: []params.ConfigSettingsResult{
   813  			{Error: apiservertesting.ErrUnauthorized},
   814  			{Settings: params.ConfigSettings{"blog-title": "My Title"}},
   815  			{Error: apiservertesting.ErrUnauthorized},
   816  		},
   817  	})
   818  }
   819  
   820  func (s *uniterSuite) TestWatchServiceRelations(c *gc.C) {
   821  	c.Assert(s.resources.Count(), gc.Equals, 0)
   822  
   823  	args := params.Entities{Entities: []params.Entity{
   824  		{Tag: "service-mysql"},
   825  		{Tag: "service-wordpress"},
   826  		{Tag: "service-foo"},
   827  	}}
   828  	result, err := s.uniter.WatchServiceRelations(args)
   829  	s.assertOneStringsWatcher(c, result, err)
   830  }
   831  
   832  func (s *uniterSuite) TestCharmArchiveURL(c *gc.C) {
   833  	dummyCharm := s.AddTestingCharm(c, "dummy")
   834  
   835  	args := params.CharmURLs{URLs: []params.CharmURL{
   836  		{URL: "something-invalid"},
   837  		{URL: s.wpCharm.String()},
   838  		{URL: dummyCharm.String()},
   839  	}}
   840  	result, err := s.uniter.CharmArchiveURL(args)
   841  	c.Assert(err, gc.IsNil)
   842  	c.Assert(result, gc.DeepEquals, params.CharmArchiveURLResults{
   843  		Results: []params.CharmArchiveURLResult{
   844  			{Error: apiservertesting.ErrUnauthorized},
   845  			{
   846  				Result: s.wpCharm.BundleURL().String(),
   847  				DisableSSLHostnameVerification: false,
   848  			},
   849  			{
   850  				Result: dummyCharm.BundleURL().String(),
   851  				DisableSSLHostnameVerification: false,
   852  			},
   853  		},
   854  	})
   855  
   856  	envtesting.SetSSLHostnameVerification(c, s.State, false)
   857  
   858  	result, err = s.uniter.CharmArchiveURL(args)
   859  	c.Assert(err, gc.IsNil)
   860  	c.Assert(result, gc.DeepEquals, params.CharmArchiveURLResults{
   861  		Results: []params.CharmArchiveURLResult{
   862  			{Error: apiservertesting.ErrUnauthorized},
   863  			{
   864  				Result: s.wpCharm.BundleURL().String(),
   865  				DisableSSLHostnameVerification: true,
   866  			},
   867  			{
   868  				Result: dummyCharm.BundleURL().String(),
   869  				DisableSSLHostnameVerification: true,
   870  			},
   871  		},
   872  	})
   873  }
   874  
   875  func (s *uniterSuite) TestCharmArchiveSha256(c *gc.C) {
   876  	dummyCharm := s.AddTestingCharm(c, "dummy")
   877  
   878  	args := params.CharmURLs{URLs: []params.CharmURL{
   879  		{URL: "something-invalid"},
   880  		{URL: s.wpCharm.String()},
   881  		{URL: dummyCharm.String()},
   882  	}}
   883  	result, err := s.uniter.CharmArchiveSha256(args)
   884  	c.Assert(err, gc.IsNil)
   885  	c.Assert(result, gc.DeepEquals, params.StringResults{
   886  		Results: []params.StringResult{
   887  			{Error: apiservertesting.ErrUnauthorized},
   888  			{Result: s.wpCharm.BundleSha256()},
   889  			{Result: dummyCharm.BundleSha256()},
   890  		},
   891  	})
   892  }
   893  
   894  func (s *uniterSuite) TestCurrentEnvironUUID(c *gc.C) {
   895  	env, err := s.State.Environment()
   896  	c.Assert(err, gc.IsNil)
   897  
   898  	result, err := s.uniter.CurrentEnvironUUID()
   899  	c.Assert(err, gc.IsNil)
   900  	c.Assert(result, gc.DeepEquals, params.StringResult{Result: env.UUID()})
   901  }
   902  
   903  func (s *uniterSuite) TestCurrentEnvironment(c *gc.C) {
   904  	env, err := s.State.Environment()
   905  	c.Assert(err, gc.IsNil)
   906  
   907  	result, err := s.uniter.CurrentEnvironment()
   908  	c.Assert(err, gc.IsNil)
   909  	expected := params.EnvironmentResult{
   910  		Name: env.Name(),
   911  		UUID: env.UUID(),
   912  	}
   913  	c.Assert(result, gc.DeepEquals, expected)
   914  }
   915  
   916  func (s *uniterSuite) addRelation(c *gc.C, first, second string) *state.Relation {
   917  	eps, err := s.State.InferEndpoints([]string{first, second})
   918  	c.Assert(err, gc.IsNil)
   919  	rel, err := s.State.AddRelation(eps...)
   920  	c.Assert(err, gc.IsNil)
   921  	return rel
   922  }
   923  
   924  func (s *uniterSuite) TestRelation(c *gc.C) {
   925  	rel := s.addRelation(c, "wordpress", "mysql")
   926  	wpEp, err := rel.Endpoint("wordpress")
   927  	c.Assert(err, gc.IsNil)
   928  
   929  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
   930  		{Relation: "relation-42", Unit: "unit-foo-0"},
   931  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
   932  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
   933  		{Relation: rel.Tag(), Unit: "unit-foo-0"},
   934  		{Relation: "relation-blah", Unit: "unit-wordpress-0"},
   935  		{Relation: "service-foo", Unit: "user-admin"},
   936  		{Relation: "foo", Unit: "bar"},
   937  		{Relation: "unit-wordpress-0", Unit: rel.Tag()},
   938  	}}
   939  	result, err := s.uniter.Relation(args)
   940  	c.Assert(err, gc.IsNil)
   941  	c.Assert(result, gc.DeepEquals, params.RelationResults{
   942  		Results: []params.RelationResult{
   943  			{Error: apiservertesting.ErrUnauthorized},
   944  			{
   945  				Id:   rel.Id(),
   946  				Key:  rel.String(),
   947  				Life: params.Life(rel.Life().String()),
   948  				Endpoint: params.Endpoint{
   949  					ServiceName: wpEp.ServiceName,
   950  					Relation:    wpEp.Relation,
   951  				},
   952  			},
   953  			{Error: apiservertesting.ErrUnauthorized},
   954  			{Error: apiservertesting.ErrUnauthorized},
   955  			{Error: apiservertesting.ErrUnauthorized},
   956  			{Error: apiservertesting.ErrUnauthorized},
   957  			{Error: apiservertesting.ErrUnauthorized},
   958  			{Error: apiservertesting.ErrUnauthorized},
   959  		},
   960  	})
   961  }
   962  
   963  func (s *uniterSuite) TestRelationById(c *gc.C) {
   964  	rel := s.addRelation(c, "wordpress", "mysql")
   965  	c.Assert(rel.Id(), gc.Equals, 0)
   966  	wpEp, err := rel.Endpoint("wordpress")
   967  	c.Assert(err, gc.IsNil)
   968  
   969  	// Add another relation to mysql service, so we can see we can't
   970  	// get it.
   971  	otherRel, _, _ := s.addRelatedService(c, "mysql", "logging", s.mysqlUnit)
   972  
   973  	args := params.RelationIds{
   974  		RelationIds: []int{-1, rel.Id(), otherRel.Id(), 42, 234},
   975  	}
   976  	result, err := s.uniter.RelationById(args)
   977  	c.Assert(err, gc.IsNil)
   978  	c.Assert(result, gc.DeepEquals, params.RelationResults{
   979  		Results: []params.RelationResult{
   980  			{Error: apiservertesting.ErrUnauthorized},
   981  			{
   982  				Id:   rel.Id(),
   983  				Key:  rel.String(),
   984  				Life: params.Life(rel.Life().String()),
   985  				Endpoint: params.Endpoint{
   986  					ServiceName: wpEp.ServiceName,
   987  					Relation:    wpEp.Relation,
   988  				},
   989  			},
   990  			{Error: apiservertesting.ErrUnauthorized},
   991  			{Error: apiservertesting.ErrUnauthorized},
   992  			{Error: apiservertesting.ErrUnauthorized},
   993  		},
   994  	})
   995  }
   996  
   997  func (s *uniterSuite) TestProviderType(c *gc.C) {
   998  	cfg, err := s.State.EnvironConfig()
   999  	c.Assert(err, gc.IsNil)
  1000  
  1001  	result, err := s.uniter.ProviderType()
  1002  	c.Assert(err, gc.IsNil)
  1003  	c.Assert(result, gc.DeepEquals, params.StringResult{Result: cfg.Type()})
  1004  }
  1005  
  1006  func (s *uniterSuite) assertInScope(c *gc.C, relUnit *state.RelationUnit, inScope bool) {
  1007  	ok, err := relUnit.InScope()
  1008  	c.Assert(err, gc.IsNil)
  1009  	c.Assert(ok, gc.Equals, inScope)
  1010  }
  1011  
  1012  func (s *uniterSuite) TestEnterScope(c *gc.C) {
  1013  	// Set wordpressUnit's private address first.
  1014  	err := s.wordpressUnit.SetPrivateAddress("1.2.3.4")
  1015  	c.Assert(err, gc.IsNil)
  1016  
  1017  	rel := s.addRelation(c, "wordpress", "mysql")
  1018  	relUnit, err := rel.Unit(s.wordpressUnit)
  1019  	c.Assert(err, gc.IsNil)
  1020  	s.assertInScope(c, relUnit, false)
  1021  
  1022  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
  1023  		{Relation: "relation-42", Unit: "unit-foo-0"},
  1024  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1025  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1026  		{Relation: "relation-42", Unit: "unit-wordpress-0"},
  1027  		{Relation: "relation-foo", Unit: "unit-wordpress-0"},
  1028  		{Relation: "service-wordpress", Unit: "unit-foo-0"},
  1029  		{Relation: "foo", Unit: "bar"},
  1030  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1031  		{Relation: rel.Tag(), Unit: "service-wordpress"},
  1032  		{Relation: rel.Tag(), Unit: "service-mysql"},
  1033  		{Relation: rel.Tag(), Unit: "user-admin"},
  1034  	}}
  1035  	result, err := s.uniter.EnterScope(args)
  1036  	c.Assert(err, gc.IsNil)
  1037  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
  1038  		Results: []params.ErrorResult{
  1039  			{apiservertesting.ErrUnauthorized},
  1040  			{nil},
  1041  			{nil},
  1042  			{apiservertesting.ErrUnauthorized},
  1043  			{apiservertesting.ErrUnauthorized},
  1044  			{apiservertesting.ErrUnauthorized},
  1045  			{apiservertesting.ErrUnauthorized},
  1046  			{apiservertesting.ErrUnauthorized},
  1047  			{apiservertesting.ErrUnauthorized},
  1048  			{apiservertesting.ErrUnauthorized},
  1049  			{apiservertesting.ErrUnauthorized},
  1050  		},
  1051  	})
  1052  
  1053  	// Verify the scope changes and settings.
  1054  	s.assertInScope(c, relUnit, true)
  1055  	readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name())
  1056  	c.Assert(err, gc.IsNil)
  1057  	c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{
  1058  		"private-address": "1.2.3.4",
  1059  	})
  1060  }
  1061  
  1062  func (s *uniterSuite) TestLeaveScope(c *gc.C) {
  1063  	rel := s.addRelation(c, "wordpress", "mysql")
  1064  	relUnit, err := rel.Unit(s.wordpressUnit)
  1065  	c.Assert(err, gc.IsNil)
  1066  	settings := map[string]interface{}{
  1067  		"some": "settings",
  1068  	}
  1069  	err = relUnit.EnterScope(settings)
  1070  	c.Assert(err, gc.IsNil)
  1071  	s.assertInScope(c, relUnit, true)
  1072  
  1073  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
  1074  		{Relation: "relation-42", Unit: "unit-foo-0"},
  1075  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1076  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1077  		{Relation: "relation-42", Unit: "unit-wordpress-0"},
  1078  		{Relation: "relation-foo", Unit: "unit-wordpress-0"},
  1079  		{Relation: "service-wordpress", Unit: "unit-foo-0"},
  1080  		{Relation: "foo", Unit: "bar"},
  1081  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1082  		{Relation: rel.Tag(), Unit: "service-wordpress"},
  1083  		{Relation: rel.Tag(), Unit: "service-mysql"},
  1084  		{Relation: rel.Tag(), Unit: "user-admin"},
  1085  	}}
  1086  	result, err := s.uniter.LeaveScope(args)
  1087  	c.Assert(err, gc.IsNil)
  1088  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
  1089  		Results: []params.ErrorResult{
  1090  			{apiservertesting.ErrUnauthorized},
  1091  			{nil},
  1092  			{nil},
  1093  			{apiservertesting.ErrUnauthorized},
  1094  			{apiservertesting.ErrUnauthorized},
  1095  			{apiservertesting.ErrUnauthorized},
  1096  			{apiservertesting.ErrUnauthorized},
  1097  			{apiservertesting.ErrUnauthorized},
  1098  			{apiservertesting.ErrUnauthorized},
  1099  			{apiservertesting.ErrUnauthorized},
  1100  			{apiservertesting.ErrUnauthorized},
  1101  		},
  1102  	})
  1103  
  1104  	// Verify the scope changes.
  1105  	s.assertInScope(c, relUnit, false)
  1106  	readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name())
  1107  	c.Assert(err, gc.IsNil)
  1108  	c.Assert(readSettings, gc.DeepEquals, settings)
  1109  }
  1110  
  1111  func (s *uniterSuite) TestReadSettings(c *gc.C) {
  1112  	rel := s.addRelation(c, "wordpress", "mysql")
  1113  	relUnit, err := rel.Unit(s.wordpressUnit)
  1114  	c.Assert(err, gc.IsNil)
  1115  	settings := map[string]interface{}{
  1116  		"some": "settings",
  1117  	}
  1118  	err = relUnit.EnterScope(settings)
  1119  	c.Assert(err, gc.IsNil)
  1120  	s.assertInScope(c, relUnit, true)
  1121  
  1122  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
  1123  		{Relation: "relation-42", Unit: "unit-foo-0"},
  1124  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1125  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1126  		{Relation: "relation-42", Unit: "unit-wordpress-0"},
  1127  		{Relation: "relation-foo", Unit: ""},
  1128  		{Relation: "service-wordpress", Unit: "unit-foo-0"},
  1129  		{Relation: "foo", Unit: "bar"},
  1130  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1131  		{Relation: rel.Tag(), Unit: "service-wordpress"},
  1132  		{Relation: rel.Tag(), Unit: "service-mysql"},
  1133  		{Relation: rel.Tag(), Unit: "user-admin"},
  1134  	}}
  1135  	result, err := s.uniter.ReadSettings(args)
  1136  	c.Assert(err, gc.IsNil)
  1137  	c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{
  1138  		Results: []params.RelationSettingsResult{
  1139  			{Error: apiservertesting.ErrUnauthorized},
  1140  			{Settings: params.RelationSettings{
  1141  				"some": "settings",
  1142  			}},
  1143  			{Error: apiservertesting.ErrUnauthorized},
  1144  			{Error: apiservertesting.ErrUnauthorized},
  1145  			{Error: apiservertesting.ErrUnauthorized},
  1146  			{Error: apiservertesting.ErrUnauthorized},
  1147  			{Error: apiservertesting.ErrUnauthorized},
  1148  			{Error: apiservertesting.ErrUnauthorized},
  1149  			{Error: apiservertesting.ErrUnauthorized},
  1150  			{Error: apiservertesting.ErrUnauthorized},
  1151  			{Error: apiservertesting.ErrUnauthorized},
  1152  		},
  1153  	})
  1154  }
  1155  
  1156  func (s *uniterSuite) TestReadSettingsWithNonStringValuesFails(c *gc.C) {
  1157  	rel := s.addRelation(c, "wordpress", "mysql")
  1158  	relUnit, err := rel.Unit(s.wordpressUnit)
  1159  	c.Assert(err, gc.IsNil)
  1160  	settings := map[string]interface{}{
  1161  		"other":        "things",
  1162  		"invalid-bool": false,
  1163  	}
  1164  	err = relUnit.EnterScope(settings)
  1165  	c.Assert(err, gc.IsNil)
  1166  	s.assertInScope(c, relUnit, true)
  1167  
  1168  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
  1169  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1170  	}}
  1171  	expectErr := `unexpected relation setting "invalid-bool": expected string, got bool`
  1172  	result, err := s.uniter.ReadSettings(args)
  1173  	c.Assert(err, gc.IsNil)
  1174  	c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{
  1175  		Results: []params.RelationSettingsResult{
  1176  			{Error: &params.Error{Message: expectErr}},
  1177  		},
  1178  	})
  1179  }
  1180  
  1181  func (s *uniterSuite) TestReadRemoteSettings(c *gc.C) {
  1182  	rel := s.addRelation(c, "wordpress", "mysql")
  1183  	relUnit, err := rel.Unit(s.wordpressUnit)
  1184  	c.Assert(err, gc.IsNil)
  1185  	settings := map[string]interface{}{
  1186  		"some": "settings",
  1187  	}
  1188  	err = relUnit.EnterScope(settings)
  1189  	c.Assert(err, gc.IsNil)
  1190  	s.assertInScope(c, relUnit, true)
  1191  
  1192  	// First test most of the invalid args tests and try to read the
  1193  	// (unset) remote unit settings.
  1194  	args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{
  1195  		{Relation: "relation-42", LocalUnit: "unit-foo-0", RemoteUnit: "foo"},
  1196  		{Relation: rel.Tag(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-wordpress-0"},
  1197  		{Relation: rel.Tag(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-mysql-0"},
  1198  		{Relation: "relation-42", LocalUnit: "unit-wordpress-0", RemoteUnit: ""},
  1199  		{Relation: "relation-foo", LocalUnit: "", RemoteUnit: ""},
  1200  		{Relation: "service-wordpress", LocalUnit: "unit-foo-0", RemoteUnit: "user-admin"},
  1201  		{Relation: "foo", LocalUnit: "bar", RemoteUnit: "baz"},
  1202  		{Relation: rel.Tag(), LocalUnit: "unit-mysql-0", RemoteUnit: "unit-wordpress-0"},
  1203  		{Relation: rel.Tag(), LocalUnit: "service-wordpress", RemoteUnit: "service-mysql"},
  1204  		{Relation: rel.Tag(), LocalUnit: "service-mysql", RemoteUnit: "foo"},
  1205  		{Relation: rel.Tag(), LocalUnit: "user-admin", RemoteUnit: "unit-wordpress-0"},
  1206  	}}
  1207  	result, err := s.uniter.ReadRemoteSettings(args)
  1208  
  1209  	// We don't set the remote unit settings on purpose to test the error.
  1210  	expectErr := `cannot read settings for unit "mysql/0" in relation "wordpress:db mysql:server": settings not found`
  1211  	c.Assert(err, gc.IsNil)
  1212  	c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{
  1213  		Results: []params.RelationSettingsResult{
  1214  			{Error: apiservertesting.ErrUnauthorized},
  1215  			{Error: apiservertesting.ErrUnauthorized},
  1216  			{Error: &params.Error{Message: expectErr}},
  1217  			{Error: apiservertesting.ErrUnauthorized},
  1218  			{Error: apiservertesting.ErrUnauthorized},
  1219  			{Error: apiservertesting.ErrUnauthorized},
  1220  			{Error: apiservertesting.ErrUnauthorized},
  1221  			{Error: apiservertesting.ErrUnauthorized},
  1222  			{Error: apiservertesting.ErrUnauthorized},
  1223  			{Error: apiservertesting.ErrUnauthorized},
  1224  			{Error: apiservertesting.ErrUnauthorized},
  1225  		},
  1226  	})
  1227  
  1228  	// Now leave the mysqlUnit and re-enter with new settings.
  1229  	relUnit, err = rel.Unit(s.mysqlUnit)
  1230  	c.Assert(err, gc.IsNil)
  1231  	settings = map[string]interface{}{
  1232  		"other": "things",
  1233  	}
  1234  	err = relUnit.LeaveScope()
  1235  	c.Assert(err, gc.IsNil)
  1236  	s.assertInScope(c, relUnit, false)
  1237  	err = relUnit.EnterScope(settings)
  1238  	c.Assert(err, gc.IsNil)
  1239  	s.assertInScope(c, relUnit, true)
  1240  
  1241  	// Test the remote unit settings can be read.
  1242  	args = params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{
  1243  		Relation:   rel.Tag(),
  1244  		LocalUnit:  "unit-wordpress-0",
  1245  		RemoteUnit: "unit-mysql-0",
  1246  	}}}
  1247  	expect := params.RelationSettingsResults{
  1248  		Results: []params.RelationSettingsResult{
  1249  			{Settings: params.RelationSettings{
  1250  				"other": "things",
  1251  			}},
  1252  		},
  1253  	}
  1254  	result, err = s.uniter.ReadRemoteSettings(args)
  1255  	c.Assert(err, gc.IsNil)
  1256  	c.Assert(result, gc.DeepEquals, expect)
  1257  
  1258  	// Now destroy the remote unit, and check its settings can still be read.
  1259  	err = s.mysqlUnit.Destroy()
  1260  	c.Assert(err, gc.IsNil)
  1261  	err = s.mysqlUnit.EnsureDead()
  1262  	c.Assert(err, gc.IsNil)
  1263  	err = s.mysqlUnit.Remove()
  1264  	c.Assert(err, gc.IsNil)
  1265  	result, err = s.uniter.ReadRemoteSettings(args)
  1266  	c.Assert(err, gc.IsNil)
  1267  	c.Assert(result, gc.DeepEquals, expect)
  1268  }
  1269  
  1270  func (s *uniterSuite) TestReadRemoteSettingsWithNonStringValuesFails(c *gc.C) {
  1271  	rel := s.addRelation(c, "wordpress", "mysql")
  1272  	relUnit, err := rel.Unit(s.mysqlUnit)
  1273  	c.Assert(err, gc.IsNil)
  1274  	settings := map[string]interface{}{
  1275  		"other":        "things",
  1276  		"invalid-bool": false,
  1277  	}
  1278  	err = relUnit.EnterScope(settings)
  1279  	c.Assert(err, gc.IsNil)
  1280  	s.assertInScope(c, relUnit, true)
  1281  
  1282  	args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{
  1283  		Relation:   rel.Tag(),
  1284  		LocalUnit:  "unit-wordpress-0",
  1285  		RemoteUnit: "unit-mysql-0",
  1286  	}}}
  1287  	expectErr := `unexpected relation setting "invalid-bool": expected string, got bool`
  1288  	result, err := s.uniter.ReadRemoteSettings(args)
  1289  	c.Assert(err, gc.IsNil)
  1290  	c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{
  1291  		Results: []params.RelationSettingsResult{
  1292  			{Error: &params.Error{Message: expectErr}},
  1293  		},
  1294  	})
  1295  }
  1296  
  1297  func (s *uniterSuite) TestUpdateSettings(c *gc.C) {
  1298  	rel := s.addRelation(c, "wordpress", "mysql")
  1299  	relUnit, err := rel.Unit(s.wordpressUnit)
  1300  	c.Assert(err, gc.IsNil)
  1301  	settings := map[string]interface{}{
  1302  		"some":  "settings",
  1303  		"other": "stuff",
  1304  	}
  1305  	err = relUnit.EnterScope(settings)
  1306  	s.assertInScope(c, relUnit, true)
  1307  
  1308  	newSettings := params.RelationSettings{
  1309  		"some":  "different",
  1310  		"other": "",
  1311  	}
  1312  
  1313  	args := params.RelationUnitsSettings{RelationUnits: []params.RelationUnitSettings{
  1314  		{Relation: "relation-42", Unit: "unit-foo-0", Settings: nil},
  1315  		{Relation: rel.Tag(), Unit: "unit-wordpress-0", Settings: newSettings},
  1316  		{Relation: "relation-42", Unit: "unit-wordpress-0", Settings: nil},
  1317  		{Relation: "relation-foo", Unit: "unit-wordpress-0", Settings: nil},
  1318  		{Relation: "service-wordpress", Unit: "unit-foo-0", Settings: nil},
  1319  		{Relation: "foo", Unit: "bar", Settings: nil},
  1320  		{Relation: rel.Tag(), Unit: "unit-mysql-0", Settings: nil},
  1321  		{Relation: rel.Tag(), Unit: "service-wordpress", Settings: nil},
  1322  		{Relation: rel.Tag(), Unit: "service-mysql", Settings: nil},
  1323  		{Relation: rel.Tag(), Unit: "user-admin", Settings: nil},
  1324  	}}
  1325  	result, err := s.uniter.UpdateSettings(args)
  1326  	c.Assert(err, gc.IsNil)
  1327  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
  1328  		Results: []params.ErrorResult{
  1329  			{apiservertesting.ErrUnauthorized},
  1330  			{nil},
  1331  			{apiservertesting.ErrUnauthorized},
  1332  			{apiservertesting.ErrUnauthorized},
  1333  			{apiservertesting.ErrUnauthorized},
  1334  			{apiservertesting.ErrUnauthorized},
  1335  			{apiservertesting.ErrUnauthorized},
  1336  			{apiservertesting.ErrUnauthorized},
  1337  			{apiservertesting.ErrUnauthorized},
  1338  			{apiservertesting.ErrUnauthorized},
  1339  		},
  1340  	})
  1341  
  1342  	// Verify the settings were saved.
  1343  	s.assertInScope(c, relUnit, true)
  1344  	readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name())
  1345  	c.Assert(err, gc.IsNil)
  1346  	c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{
  1347  		"some": "different",
  1348  	})
  1349  }
  1350  
  1351  func (s *uniterSuite) TestWatchRelationUnits(c *gc.C) {
  1352  	// Add a relation between wordpress and mysql and enter scope with
  1353  	// mysqlUnit.
  1354  	rel := s.addRelation(c, "wordpress", "mysql")
  1355  	myRelUnit, err := rel.Unit(s.mysqlUnit)
  1356  	c.Assert(err, gc.IsNil)
  1357  	err = myRelUnit.EnterScope(nil)
  1358  	c.Assert(err, gc.IsNil)
  1359  	s.assertInScope(c, myRelUnit, true)
  1360  
  1361  	c.Assert(s.resources.Count(), gc.Equals, 0)
  1362  
  1363  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
  1364  		{Relation: "relation-42", Unit: "unit-foo-0"},
  1365  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1366  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1367  		{Relation: "relation-42", Unit: "unit-wordpress-0"},
  1368  		{Relation: "relation-foo", Unit: ""},
  1369  		{Relation: "service-wordpress", Unit: "unit-foo-0"},
  1370  		{Relation: "foo", Unit: "bar"},
  1371  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1372  		{Relation: rel.Tag(), Unit: "service-wordpress"},
  1373  		{Relation: rel.Tag(), Unit: "service-mysql"},
  1374  		{Relation: rel.Tag(), Unit: "user-admin"},
  1375  	}}
  1376  	result, err := s.uniter.WatchRelationUnits(args)
  1377  	c.Assert(err, gc.IsNil)
  1378  	// UnitSettings versions are volatile, so we don't check them.
  1379  	// We just make sure the keys of the Changed field are as
  1380  	// expected.
  1381  	c.Assert(result.Results, gc.HasLen, len(args.RelationUnits))
  1382  	mysqlChanges := result.Results[1].Changes
  1383  	c.Assert(mysqlChanges, gc.NotNil)
  1384  	changed, ok := mysqlChanges.Changed["mysql/0"]
  1385  	c.Assert(ok, jc.IsTrue)
  1386  	expectChanges := params.RelationUnitsChange{
  1387  		Changed: map[string]params.UnitSettings{"mysql/0": changed},
  1388  	}
  1389  	c.Assert(result, gc.DeepEquals, params.RelationUnitsWatchResults{
  1390  		Results: []params.RelationUnitsWatchResult{
  1391  			{Error: apiservertesting.ErrUnauthorized},
  1392  			{
  1393  				RelationUnitsWatcherId: "1",
  1394  				Changes:                expectChanges,
  1395  			},
  1396  			{Error: apiservertesting.ErrUnauthorized},
  1397  			{Error: apiservertesting.ErrUnauthorized},
  1398  			{Error: apiservertesting.ErrUnauthorized},
  1399  			{Error: apiservertesting.ErrUnauthorized},
  1400  			{Error: apiservertesting.ErrUnauthorized},
  1401  			{Error: apiservertesting.ErrUnauthorized},
  1402  			{Error: apiservertesting.ErrUnauthorized},
  1403  			{Error: apiservertesting.ErrUnauthorized},
  1404  			{Error: apiservertesting.ErrUnauthorized},
  1405  		},
  1406  	})
  1407  
  1408  	// Verify the resource was registered and stop when done
  1409  	c.Assert(s.resources.Count(), gc.Equals, 1)
  1410  	resource := s.resources.Get("1")
  1411  	defer statetesting.AssertStop(c, resource)
  1412  
  1413  	// Check that the Watch has consumed the initial event ("returned" in
  1414  	// the Watch call)
  1415  	wc := statetesting.NewRelationUnitsWatcherC(c, s.State, resource.(state.RelationUnitsWatcher))
  1416  	wc.AssertNoChange()
  1417  
  1418  	// Leave scope with mysqlUnit and check it's detected.
  1419  	err = myRelUnit.LeaveScope()
  1420  	c.Assert(err, gc.IsNil)
  1421  	s.assertInScope(c, myRelUnit, false)
  1422  
  1423  	wc.AssertChange(nil, []string{"mysql/0"})
  1424  }
  1425  
  1426  func (s *uniterSuite) TestAPIAddresses(c *gc.C) {
  1427  	err := s.machine0.SetAddresses([]instance.Address{
  1428  		instance.NewAddress("0.1.2.3"),
  1429  	})
  1430  	c.Assert(err, gc.IsNil)
  1431  	apiAddresses, err := s.State.APIAddresses()
  1432  	c.Assert(err, gc.IsNil)
  1433  
  1434  	result, err := s.uniter.APIAddresses()
  1435  	c.Assert(err, gc.IsNil)
  1436  	c.Assert(result, gc.DeepEquals, params.StringsResult{
  1437  		Result: apiAddresses,
  1438  	})
  1439  }
  1440  
  1441  func (s *uniterSuite) TestGetOwnerTag(c *gc.C) {
  1442  	tag := s.mysql.Tag()
  1443  	args := params.Entities{Entities: []params.Entity{
  1444  		{Tag: tag},
  1445  	}}
  1446  	result, err := s.uniter.GetOwnerTag(args)
  1447  	c.Assert(err, gc.IsNil)
  1448  	c.Assert(result, gc.DeepEquals, params.StringResult{
  1449  		Result: "user-admin",
  1450  	})
  1451  }