github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/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  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "launchpad.net/gocheck"
    12  
    13  	"github.com/juju/juju/charm"
    14  	envtesting "github.com/juju/juju/environs/testing"
    15  	"github.com/juju/juju/instance"
    16  	"github.com/juju/juju/juju/testing"
    17  	"github.com/juju/juju/state"
    18  	"github.com/juju/juju/state/api/params"
    19  	"github.com/juju/juju/state/apiserver/common"
    20  	commontesting "github.com/juju/juju/state/apiserver/common/testing"
    21  	apiservertesting "github.com/juju/juju/state/apiserver/testing"
    22  	"github.com/juju/juju/state/apiserver/uniter"
    23  	statetesting "github.com/juju/juju/state/testing"
    24  	coretesting "github.com/juju/juju/testing"
    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.EntityStatus{
   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.machine0.SetAddresses(instance.NewAddress("1.2.3.4", instance.NetworkPublic))
   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) TestPrivateAddress(c *gc.C) {
   341  	args := params.Entities{Entities: []params.Entity{
   342  		{Tag: "unit-mysql-0"},
   343  		{Tag: "unit-wordpress-0"},
   344  		{Tag: "unit-foo-42"},
   345  	}}
   346  	expectErr := &params.Error{
   347  		Code:    params.CodeNoAddressSet,
   348  		Message: `"unit-wordpress-0" has no private address set`,
   349  	}
   350  	result, err := s.uniter.PrivateAddress(args)
   351  	c.Assert(err, gc.IsNil)
   352  	c.Assert(result, gc.DeepEquals, params.StringResults{
   353  		Results: []params.StringResult{
   354  			{Error: apiservertesting.ErrUnauthorized},
   355  			{Error: expectErr},
   356  			{Error: apiservertesting.ErrUnauthorized},
   357  		},
   358  	})
   359  
   360  	// Now set it and try again.
   361  	err = s.machine0.SetAddresses(instance.NewAddress("1.2.3.4", instance.NetworkCloudLocal))
   362  	c.Assert(err, gc.IsNil)
   363  	address, ok := s.wordpressUnit.PrivateAddress()
   364  	c.Assert(address, gc.Equals, "1.2.3.4")
   365  	c.Assert(ok, jc.IsTrue)
   366  
   367  	result, err = s.uniter.PrivateAddress(args)
   368  	c.Assert(err, gc.IsNil)
   369  	c.Assert(result, gc.DeepEquals, params.StringResults{
   370  		Results: []params.StringResult{
   371  			{Error: apiservertesting.ErrUnauthorized},
   372  			{Result: "1.2.3.4"},
   373  			{Error: apiservertesting.ErrUnauthorized},
   374  		},
   375  	})
   376  }
   377  
   378  func (s *uniterSuite) TestResolved(c *gc.C) {
   379  	err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks)
   380  	c.Assert(err, gc.IsNil)
   381  	mode := s.wordpressUnit.Resolved()
   382  	c.Assert(mode, gc.Equals, state.ResolvedRetryHooks)
   383  
   384  	args := params.Entities{Entities: []params.Entity{
   385  		{Tag: "unit-mysql-0"},
   386  		{Tag: "unit-wordpress-0"},
   387  		{Tag: "unit-foo-42"},
   388  	}}
   389  	result, err := s.uniter.Resolved(args)
   390  	c.Assert(err, gc.IsNil)
   391  	c.Assert(result, gc.DeepEquals, params.ResolvedModeResults{
   392  		Results: []params.ResolvedModeResult{
   393  			{Error: apiservertesting.ErrUnauthorized},
   394  			{Mode: params.ResolvedMode(mode)},
   395  			{Error: apiservertesting.ErrUnauthorized},
   396  		},
   397  	})
   398  }
   399  
   400  func (s *uniterSuite) TestClearResolved(c *gc.C) {
   401  	err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks)
   402  	c.Assert(err, gc.IsNil)
   403  	mode := s.wordpressUnit.Resolved()
   404  	c.Assert(mode, gc.Equals, state.ResolvedRetryHooks)
   405  
   406  	args := params.Entities{Entities: []params.Entity{
   407  		{Tag: "unit-mysql-0"},
   408  		{Tag: "unit-wordpress-0"},
   409  		{Tag: "unit-foo-42"},
   410  	}}
   411  	result, err := s.uniter.ClearResolved(args)
   412  	c.Assert(err, gc.IsNil)
   413  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   414  		Results: []params.ErrorResult{
   415  			{apiservertesting.ErrUnauthorized},
   416  			{nil},
   417  			{apiservertesting.ErrUnauthorized},
   418  		},
   419  	})
   420  
   421  	// Verify wordpressUnit's resolved mode has changed.
   422  	err = s.wordpressUnit.Refresh()
   423  	c.Assert(err, gc.IsNil)
   424  	mode = s.wordpressUnit.Resolved()
   425  	c.Assert(mode, gc.Equals, state.ResolvedNone)
   426  }
   427  
   428  func (s *uniterSuite) TestGetPrincipal(c *gc.C) {
   429  	// Add a subordinate to wordpressUnit.
   430  	_, _, subordinate := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   431  
   432  	principal, ok := subordinate.PrincipalName()
   433  	c.Assert(principal, gc.Equals, s.wordpressUnit.Name())
   434  	c.Assert(ok, jc.IsTrue)
   435  
   436  	// First try it as wordpressUnit's agent.
   437  	args := params.Entities{Entities: []params.Entity{
   438  		{Tag: "unit-mysql-0"},
   439  		{Tag: "unit-wordpress-0"},
   440  		{Tag: subordinate.Tag()},
   441  		{Tag: "unit-foo-42"},
   442  	}}
   443  	result, err := s.uniter.GetPrincipal(args)
   444  	c.Assert(err, gc.IsNil)
   445  	c.Assert(result, gc.DeepEquals, params.StringBoolResults{
   446  		Results: []params.StringBoolResult{
   447  			{Error: apiservertesting.ErrUnauthorized},
   448  			{Result: "", Ok: false, Error: nil},
   449  			{Error: apiservertesting.ErrUnauthorized},
   450  			{Error: apiservertesting.ErrUnauthorized},
   451  		},
   452  	})
   453  
   454  	// Now try as subordinate's agent.
   455  	subAuthorizer := s.authorizer
   456  	subAuthorizer.Tag = subordinate.Tag()
   457  	subUniter, err := uniter.NewUniterAPI(s.State, s.resources, subAuthorizer)
   458  	c.Assert(err, gc.IsNil)
   459  
   460  	result, err = subUniter.GetPrincipal(args)
   461  	c.Assert(err, gc.IsNil)
   462  	c.Assert(result, gc.DeepEquals, params.StringBoolResults{
   463  		Results: []params.StringBoolResult{
   464  			{Error: apiservertesting.ErrUnauthorized},
   465  			{Error: apiservertesting.ErrUnauthorized},
   466  			{Result: "unit-wordpress-0", Ok: true, Error: nil},
   467  			{Error: apiservertesting.ErrUnauthorized},
   468  		},
   469  	})
   470  }
   471  
   472  func (s *uniterSuite) addRelatedService(c *gc.C, firstSvc, relatedSvc string, unit *state.Unit) (*state.Relation, *state.Service, *state.Unit) {
   473  	relatedService := s.AddTestingService(c, relatedSvc, s.AddTestingCharm(c, relatedSvc))
   474  	rel := s.addRelation(c, firstSvc, relatedSvc)
   475  	relUnit, err := rel.Unit(unit)
   476  	c.Assert(err, gc.IsNil)
   477  	err = relUnit.EnterScope(nil)
   478  	c.Assert(err, gc.IsNil)
   479  	relatedUnit, err := relatedService.Unit(relatedSvc + "/0")
   480  	c.Assert(err, gc.IsNil)
   481  	return rel, relatedService, relatedUnit
   482  }
   483  
   484  func (s *uniterSuite) TestHasSubordinates(c *gc.C) {
   485  	// Try first without any subordinates for wordpressUnit.
   486  	args := params.Entities{Entities: []params.Entity{
   487  		{Tag: "unit-mysql-0"},
   488  		{Tag: "unit-wordpress-0"},
   489  		{Tag: "unit-logging-0"},
   490  		{Tag: "unit-foo-42"},
   491  	}}
   492  	result, err := s.uniter.HasSubordinates(args)
   493  	c.Assert(err, gc.IsNil)
   494  	c.Assert(result, gc.DeepEquals, params.BoolResults{
   495  		Results: []params.BoolResult{
   496  			{Error: apiservertesting.ErrUnauthorized},
   497  			{Result: false},
   498  			{Error: apiservertesting.ErrUnauthorized},
   499  			{Error: apiservertesting.ErrUnauthorized},
   500  		},
   501  	})
   502  
   503  	// Add two subordinates to wordpressUnit and try again.
   504  	s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   505  	s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit)
   506  
   507  	result, err = s.uniter.HasSubordinates(args)
   508  	c.Assert(err, gc.IsNil)
   509  	c.Assert(result, gc.DeepEquals, params.BoolResults{
   510  		Results: []params.BoolResult{
   511  			{Error: apiservertesting.ErrUnauthorized},
   512  			{Result: true},
   513  			{Error: apiservertesting.ErrUnauthorized},
   514  			{Error: apiservertesting.ErrUnauthorized},
   515  		},
   516  	})
   517  }
   518  
   519  func (s *uniterSuite) TestDestroy(c *gc.C) {
   520  	c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive)
   521  
   522  	args := params.Entities{Entities: []params.Entity{
   523  		{Tag: "unit-mysql-0"},
   524  		{Tag: "unit-wordpress-0"},
   525  		{Tag: "unit-foo-42"},
   526  	}}
   527  	result, err := s.uniter.Destroy(args)
   528  	c.Assert(err, gc.IsNil)
   529  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   530  		Results: []params.ErrorResult{
   531  			{apiservertesting.ErrUnauthorized},
   532  			{nil},
   533  			{apiservertesting.ErrUnauthorized},
   534  		},
   535  	})
   536  
   537  	// Verify wordpressUnit is destroyed and removed.
   538  	err = s.wordpressUnit.Refresh()
   539  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   540  }
   541  
   542  func (s *uniterSuite) TestDestroyAllSubordinates(c *gc.C) {
   543  	// Add two subordinates to wordpressUnit.
   544  	_, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit)
   545  	_, _, monitoringSub := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit)
   546  	c.Assert(loggingSub.Life(), gc.Equals, state.Alive)
   547  	c.Assert(monitoringSub.Life(), gc.Equals, state.Alive)
   548  
   549  	err := s.wordpressUnit.Refresh()
   550  	c.Assert(err, gc.IsNil)
   551  	subordinates := s.wordpressUnit.SubordinateNames()
   552  	c.Assert(subordinates, gc.DeepEquals, []string{"logging/0", "monitoring/0"})
   553  
   554  	args := params.Entities{Entities: []params.Entity{
   555  		{Tag: "unit-mysql-0"},
   556  		{Tag: "unit-wordpress-0"},
   557  		{Tag: "unit-foo-42"},
   558  	}}
   559  	result, err := s.uniter.DestroyAllSubordinates(args)
   560  	c.Assert(err, gc.IsNil)
   561  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   562  		Results: []params.ErrorResult{
   563  			{apiservertesting.ErrUnauthorized},
   564  			{nil},
   565  			{apiservertesting.ErrUnauthorized},
   566  		},
   567  	})
   568  
   569  	// Verify wordpressUnit's subordinates were destroyed.
   570  	err = loggingSub.Refresh()
   571  	c.Assert(err, gc.IsNil)
   572  	c.Assert(loggingSub.Life(), gc.Equals, state.Dying)
   573  	err = monitoringSub.Refresh()
   574  	c.Assert(err, gc.IsNil)
   575  	c.Assert(monitoringSub.Life(), gc.Equals, state.Dying)
   576  }
   577  
   578  func (s *uniterSuite) TestCharmURL(c *gc.C) {
   579  	// Set wordpressUnit's charm URL first.
   580  	err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL())
   581  	c.Assert(err, gc.IsNil)
   582  	curl, ok := s.wordpressUnit.CharmURL()
   583  	c.Assert(curl, gc.DeepEquals, s.wpCharm.URL())
   584  	c.Assert(ok, jc.IsTrue)
   585  
   586  	// Make sure wordpress service's charm is what we expect.
   587  	curl, force := s.wordpress.CharmURL()
   588  	c.Assert(curl, gc.DeepEquals, s.wpCharm.URL())
   589  	c.Assert(force, jc.IsFalse)
   590  
   591  	args := params.Entities{Entities: []params.Entity{
   592  		{Tag: "unit-mysql-0"},
   593  		{Tag: "unit-wordpress-0"},
   594  		{Tag: "unit-foo-42"},
   595  		{Tag: "service-mysql"},
   596  		{Tag: "service-wordpress"},
   597  		{Tag: "service-foo"},
   598  		{Tag: "just-foo"},
   599  	}}
   600  	result, err := s.uniter.CharmURL(args)
   601  	c.Assert(err, gc.IsNil)
   602  	c.Assert(result, gc.DeepEquals, params.StringBoolResults{
   603  		Results: []params.StringBoolResult{
   604  			{Error: apiservertesting.ErrUnauthorized},
   605  			{Result: s.wpCharm.String(), Ok: ok},
   606  			{Error: apiservertesting.ErrUnauthorized},
   607  			{Error: apiservertesting.ErrUnauthorized},
   608  			{Result: s.wpCharm.String(), Ok: force},
   609  			{Error: apiservertesting.ErrUnauthorized},
   610  			{Error: apiservertesting.ErrUnauthorized},
   611  		},
   612  	})
   613  }
   614  
   615  func (s *uniterSuite) TestSetCharmURL(c *gc.C) {
   616  	charmUrl, ok := s.wordpressUnit.CharmURL()
   617  	c.Assert(charmUrl, gc.IsNil)
   618  	c.Assert(ok, jc.IsFalse)
   619  
   620  	args := params.EntitiesCharmURL{Entities: []params.EntityCharmURL{
   621  		{Tag: "unit-mysql-0", CharmURL: "cs:quantal/service-42"},
   622  		{Tag: "unit-wordpress-0", CharmURL: s.wpCharm.String()},
   623  		{Tag: "unit-foo-42", CharmURL: "cs:quantal/foo-321"},
   624  	}}
   625  	result, err := s.uniter.SetCharmURL(args)
   626  	c.Assert(err, gc.IsNil)
   627  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   628  		Results: []params.ErrorResult{
   629  			{apiservertesting.ErrUnauthorized},
   630  			{nil},
   631  			{apiservertesting.ErrUnauthorized},
   632  		},
   633  	})
   634  
   635  	// Verify the charm URL was set.
   636  	err = s.wordpressUnit.Refresh()
   637  	c.Assert(err, gc.IsNil)
   638  	charmUrl, ok = s.wordpressUnit.CharmURL()
   639  	c.Assert(charmUrl, gc.NotNil)
   640  	c.Assert(charmUrl.String(), gc.Equals, s.wpCharm.String())
   641  	c.Assert(ok, jc.IsTrue)
   642  }
   643  
   644  func (s *uniterSuite) TestOpenPort(c *gc.C) {
   645  	openedPorts := s.wordpressUnit.OpenedPorts()
   646  	c.Assert(openedPorts, gc.HasLen, 0)
   647  
   648  	args := params.EntitiesPorts{Entities: []params.EntityPort{
   649  		{Tag: "unit-mysql-0", Protocol: "tcp", Port: 1234},
   650  		{Tag: "unit-wordpress-0", Protocol: "udp", Port: 4321},
   651  		{Tag: "unit-foo-42", Protocol: "tcp", Port: 42},
   652  	}}
   653  	result, err := s.uniter.OpenPort(args)
   654  	c.Assert(err, gc.IsNil)
   655  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   656  		Results: []params.ErrorResult{
   657  			{apiservertesting.ErrUnauthorized},
   658  			{nil},
   659  			{apiservertesting.ErrUnauthorized},
   660  		},
   661  	})
   662  
   663  	// Verify the wordpressUnit's port is opened.
   664  	err = s.wordpressUnit.Refresh()
   665  	c.Assert(err, gc.IsNil)
   666  	openedPorts = s.wordpressUnit.OpenedPorts()
   667  	c.Assert(openedPorts, gc.DeepEquals, []instance.Port{
   668  		{Protocol: "udp", Number: 4321},
   669  	})
   670  }
   671  
   672  func (s *uniterSuite) TestClosePort(c *gc.C) {
   673  	// Open port udp:4321 in advance on wordpressUnit.
   674  	err := s.wordpressUnit.OpenPort("udp", 4321)
   675  	c.Assert(err, gc.IsNil)
   676  	err = s.wordpressUnit.Refresh()
   677  	c.Assert(err, gc.IsNil)
   678  	openedPorts := s.wordpressUnit.OpenedPorts()
   679  	c.Assert(openedPorts, gc.DeepEquals, []instance.Port{
   680  		{Protocol: "udp", Number: 4321},
   681  	})
   682  
   683  	args := params.EntitiesPorts{Entities: []params.EntityPort{
   684  		{Tag: "unit-mysql-0", Protocol: "tcp", Port: 1234},
   685  		{Tag: "unit-wordpress-0", Protocol: "udp", Port: 4321},
   686  		{Tag: "unit-foo-42", Protocol: "tcp", Port: 42},
   687  	}}
   688  	result, err := s.uniter.ClosePort(args)
   689  	c.Assert(err, gc.IsNil)
   690  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   691  		Results: []params.ErrorResult{
   692  			{apiservertesting.ErrUnauthorized},
   693  			{nil},
   694  			{apiservertesting.ErrUnauthorized},
   695  		},
   696  	})
   697  
   698  	// Verify the wordpressUnit's port is closed.
   699  	err = s.wordpressUnit.Refresh()
   700  	c.Assert(err, gc.IsNil)
   701  	openedPorts = s.wordpressUnit.OpenedPorts()
   702  	c.Assert(openedPorts, gc.HasLen, 0)
   703  }
   704  
   705  func (s *uniterSuite) TestWatchConfigSettings(c *gc.C) {
   706  	err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL())
   707  	c.Assert(err, gc.IsNil)
   708  
   709  	c.Assert(s.resources.Count(), gc.Equals, 0)
   710  
   711  	args := params.Entities{Entities: []params.Entity{
   712  		{Tag: "unit-mysql-0"},
   713  		{Tag: "unit-wordpress-0"},
   714  		{Tag: "unit-foo-42"},
   715  	}}
   716  	result, err := s.uniter.WatchConfigSettings(args)
   717  	c.Assert(err, gc.IsNil)
   718  	c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{
   719  		Results: []params.NotifyWatchResult{
   720  			{Error: apiservertesting.ErrUnauthorized},
   721  			{NotifyWatcherId: "1"},
   722  			{Error: apiservertesting.ErrUnauthorized},
   723  		},
   724  	})
   725  
   726  	// Verify the resource was registered and stop when done
   727  	c.Assert(s.resources.Count(), gc.Equals, 1)
   728  	resource := s.resources.Get("1")
   729  	defer statetesting.AssertStop(c, resource)
   730  
   731  	// Check that the Watch has consumed the initial event ("returned" in
   732  	// the Watch call)
   733  	wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher))
   734  	wc.AssertNoChange()
   735  }
   736  
   737  func (s *uniterSuite) TestConfigSettings(c *gc.C) {
   738  	err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL())
   739  	c.Assert(err, gc.IsNil)
   740  	settings, err := s.wordpressUnit.ConfigSettings()
   741  	c.Assert(err, gc.IsNil)
   742  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"})
   743  
   744  	args := params.Entities{Entities: []params.Entity{
   745  		{Tag: "unit-mysql-0"},
   746  		{Tag: "unit-wordpress-0"},
   747  		{Tag: "unit-foo-42"},
   748  	}}
   749  	result, err := s.uniter.ConfigSettings(args)
   750  	c.Assert(err, gc.IsNil)
   751  	c.Assert(result, gc.DeepEquals, params.ConfigSettingsResults{
   752  		Results: []params.ConfigSettingsResult{
   753  			{Error: apiservertesting.ErrUnauthorized},
   754  			{Settings: params.ConfigSettings{"blog-title": "My Title"}},
   755  			{Error: apiservertesting.ErrUnauthorized},
   756  		},
   757  	})
   758  }
   759  
   760  func (s *uniterSuite) TestWatchServiceRelations(c *gc.C) {
   761  	c.Assert(s.resources.Count(), gc.Equals, 0)
   762  
   763  	args := params.Entities{Entities: []params.Entity{
   764  		{Tag: "service-mysql"},
   765  		{Tag: "service-wordpress"},
   766  		{Tag: "service-foo"},
   767  	}}
   768  	result, err := s.uniter.WatchServiceRelations(args)
   769  	s.assertOneStringsWatcher(c, result, err)
   770  }
   771  
   772  func (s *uniterSuite) TestCharmArchiveURL(c *gc.C) {
   773  	dummyCharm := s.AddTestingCharm(c, "dummy")
   774  
   775  	args := params.CharmURLs{URLs: []params.CharmURL{
   776  		{URL: "something-invalid"},
   777  		{URL: s.wpCharm.String()},
   778  		{URL: dummyCharm.String()},
   779  	}}
   780  	result, err := s.uniter.CharmArchiveURL(args)
   781  	c.Assert(err, gc.IsNil)
   782  	c.Assert(result, gc.DeepEquals, params.CharmArchiveURLResults{
   783  		Results: []params.CharmArchiveURLResult{
   784  			{Error: apiservertesting.ErrUnauthorized},
   785  			{
   786  				Result: s.wpCharm.BundleURL().String(),
   787  				DisableSSLHostnameVerification: false,
   788  			},
   789  			{
   790  				Result: dummyCharm.BundleURL().String(),
   791  				DisableSSLHostnameVerification: false,
   792  			},
   793  		},
   794  	})
   795  
   796  	envtesting.SetSSLHostnameVerification(c, s.State, false)
   797  
   798  	result, err = s.uniter.CharmArchiveURL(args)
   799  	c.Assert(err, gc.IsNil)
   800  	c.Assert(result, gc.DeepEquals, params.CharmArchiveURLResults{
   801  		Results: []params.CharmArchiveURLResult{
   802  			{Error: apiservertesting.ErrUnauthorized},
   803  			{
   804  				Result: s.wpCharm.BundleURL().String(),
   805  				DisableSSLHostnameVerification: true,
   806  			},
   807  			{
   808  				Result: dummyCharm.BundleURL().String(),
   809  				DisableSSLHostnameVerification: true,
   810  			},
   811  		},
   812  	})
   813  }
   814  
   815  func (s *uniterSuite) TestCharmArchiveSha256(c *gc.C) {
   816  	dummyCharm := s.AddTestingCharm(c, "dummy")
   817  
   818  	args := params.CharmURLs{URLs: []params.CharmURL{
   819  		{URL: "something-invalid"},
   820  		{URL: s.wpCharm.String()},
   821  		{URL: dummyCharm.String()},
   822  	}}
   823  	result, err := s.uniter.CharmArchiveSha256(args)
   824  	c.Assert(err, gc.IsNil)
   825  	c.Assert(result, gc.DeepEquals, params.StringResults{
   826  		Results: []params.StringResult{
   827  			{Error: apiservertesting.ErrUnauthorized},
   828  			{Result: s.wpCharm.BundleSha256()},
   829  			{Result: dummyCharm.BundleSha256()},
   830  		},
   831  	})
   832  }
   833  
   834  func (s *uniterSuite) TestCurrentEnvironUUID(c *gc.C) {
   835  	env, err := s.State.Environment()
   836  	c.Assert(err, gc.IsNil)
   837  
   838  	result, err := s.uniter.CurrentEnvironUUID()
   839  	c.Assert(err, gc.IsNil)
   840  	c.Assert(result, gc.DeepEquals, params.StringResult{Result: env.UUID()})
   841  }
   842  
   843  func (s *uniterSuite) TestCurrentEnvironment(c *gc.C) {
   844  	env, err := s.State.Environment()
   845  	c.Assert(err, gc.IsNil)
   846  
   847  	result, err := s.uniter.CurrentEnvironment()
   848  	c.Assert(err, gc.IsNil)
   849  	expected := params.EnvironmentResult{
   850  		Name: env.Name(),
   851  		UUID: env.UUID(),
   852  	}
   853  	c.Assert(result, gc.DeepEquals, expected)
   854  }
   855  
   856  func (s *uniterSuite) addRelation(c *gc.C, first, second string) *state.Relation {
   857  	eps, err := s.State.InferEndpoints([]string{first, second})
   858  	c.Assert(err, gc.IsNil)
   859  	rel, err := s.State.AddRelation(eps...)
   860  	c.Assert(err, gc.IsNil)
   861  	return rel
   862  }
   863  
   864  func (s *uniterSuite) TestRelation(c *gc.C) {
   865  	rel := s.addRelation(c, "wordpress", "mysql")
   866  	wpEp, err := rel.Endpoint("wordpress")
   867  	c.Assert(err, gc.IsNil)
   868  
   869  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
   870  		{Relation: "relation-42", Unit: "unit-foo-0"},
   871  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
   872  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
   873  		{Relation: rel.Tag(), Unit: "unit-foo-0"},
   874  		{Relation: "relation-blah", Unit: "unit-wordpress-0"},
   875  		{Relation: "service-foo", Unit: "user-admin"},
   876  		{Relation: "foo", Unit: "bar"},
   877  		{Relation: "unit-wordpress-0", Unit: rel.Tag()},
   878  	}}
   879  	result, err := s.uniter.Relation(args)
   880  	c.Assert(err, gc.IsNil)
   881  	c.Assert(result, gc.DeepEquals, params.RelationResults{
   882  		Results: []params.RelationResult{
   883  			{Error: apiservertesting.ErrUnauthorized},
   884  			{
   885  				Id:   rel.Id(),
   886  				Key:  rel.String(),
   887  				Life: params.Life(rel.Life().String()),
   888  				Endpoint: params.Endpoint{
   889  					ServiceName: wpEp.ServiceName,
   890  					Relation:    wpEp.Relation,
   891  				},
   892  			},
   893  			{Error: apiservertesting.ErrUnauthorized},
   894  			{Error: apiservertesting.ErrUnauthorized},
   895  			{Error: apiservertesting.ErrUnauthorized},
   896  			{Error: apiservertesting.ErrUnauthorized},
   897  			{Error: apiservertesting.ErrUnauthorized},
   898  			{Error: apiservertesting.ErrUnauthorized},
   899  		},
   900  	})
   901  }
   902  
   903  func (s *uniterSuite) TestRelationById(c *gc.C) {
   904  	rel := s.addRelation(c, "wordpress", "mysql")
   905  	c.Assert(rel.Id(), gc.Equals, 0)
   906  	wpEp, err := rel.Endpoint("wordpress")
   907  	c.Assert(err, gc.IsNil)
   908  
   909  	// Add another relation to mysql service, so we can see we can't
   910  	// get it.
   911  	otherRel, _, _ := s.addRelatedService(c, "mysql", "logging", s.mysqlUnit)
   912  
   913  	args := params.RelationIds{
   914  		RelationIds: []int{-1, rel.Id(), otherRel.Id(), 42, 234},
   915  	}
   916  	result, err := s.uniter.RelationById(args)
   917  	c.Assert(err, gc.IsNil)
   918  	c.Assert(result, gc.DeepEquals, params.RelationResults{
   919  		Results: []params.RelationResult{
   920  			{Error: apiservertesting.ErrUnauthorized},
   921  			{
   922  				Id:   rel.Id(),
   923  				Key:  rel.String(),
   924  				Life: params.Life(rel.Life().String()),
   925  				Endpoint: params.Endpoint{
   926  					ServiceName: wpEp.ServiceName,
   927  					Relation:    wpEp.Relation,
   928  				},
   929  			},
   930  			{Error: apiservertesting.ErrUnauthorized},
   931  			{Error: apiservertesting.ErrUnauthorized},
   932  			{Error: apiservertesting.ErrUnauthorized},
   933  		},
   934  	})
   935  }
   936  
   937  func (s *uniterSuite) TestProviderType(c *gc.C) {
   938  	cfg, err := s.State.EnvironConfig()
   939  	c.Assert(err, gc.IsNil)
   940  
   941  	result, err := s.uniter.ProviderType()
   942  	c.Assert(err, gc.IsNil)
   943  	c.Assert(result, gc.DeepEquals, params.StringResult{Result: cfg.Type()})
   944  }
   945  
   946  func (s *uniterSuite) assertInScope(c *gc.C, relUnit *state.RelationUnit, inScope bool) {
   947  	ok, err := relUnit.InScope()
   948  	c.Assert(err, gc.IsNil)
   949  	c.Assert(ok, gc.Equals, inScope)
   950  }
   951  
   952  func (s *uniterSuite) TestEnterScope(c *gc.C) {
   953  	// Set wordpressUnit's private address first.
   954  	err := s.machine0.SetAddresses(instance.NewAddress("1.2.3.4", instance.NetworkCloudLocal))
   955  	c.Assert(err, gc.IsNil)
   956  
   957  	rel := s.addRelation(c, "wordpress", "mysql")
   958  	relUnit, err := rel.Unit(s.wordpressUnit)
   959  	c.Assert(err, gc.IsNil)
   960  	s.assertInScope(c, relUnit, false)
   961  
   962  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
   963  		{Relation: "relation-42", Unit: "unit-foo-0"},
   964  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
   965  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
   966  		{Relation: "relation-42", Unit: "unit-wordpress-0"},
   967  		{Relation: "relation-foo", Unit: "unit-wordpress-0"},
   968  		{Relation: "service-wordpress", Unit: "unit-foo-0"},
   969  		{Relation: "foo", Unit: "bar"},
   970  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
   971  		{Relation: rel.Tag(), Unit: "service-wordpress"},
   972  		{Relation: rel.Tag(), Unit: "service-mysql"},
   973  		{Relation: rel.Tag(), Unit: "user-admin"},
   974  	}}
   975  	result, err := s.uniter.EnterScope(args)
   976  	c.Assert(err, gc.IsNil)
   977  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
   978  		Results: []params.ErrorResult{
   979  			{apiservertesting.ErrUnauthorized},
   980  			{nil},
   981  			{nil},
   982  			{apiservertesting.ErrUnauthorized},
   983  			{apiservertesting.ErrUnauthorized},
   984  			{apiservertesting.ErrUnauthorized},
   985  			{apiservertesting.ErrUnauthorized},
   986  			{apiservertesting.ErrUnauthorized},
   987  			{apiservertesting.ErrUnauthorized},
   988  			{apiservertesting.ErrUnauthorized},
   989  			{apiservertesting.ErrUnauthorized},
   990  		},
   991  	})
   992  
   993  	// Verify the scope changes and settings.
   994  	s.assertInScope(c, relUnit, true)
   995  	readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name())
   996  	c.Assert(err, gc.IsNil)
   997  	c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{
   998  		"private-address": "1.2.3.4",
   999  	})
  1000  }
  1001  
  1002  func (s *uniterSuite) TestLeaveScope(c *gc.C) {
  1003  	rel := s.addRelation(c, "wordpress", "mysql")
  1004  	relUnit, err := rel.Unit(s.wordpressUnit)
  1005  	c.Assert(err, gc.IsNil)
  1006  	settings := map[string]interface{}{
  1007  		"some": "settings",
  1008  	}
  1009  	err = relUnit.EnterScope(settings)
  1010  	c.Assert(err, gc.IsNil)
  1011  	s.assertInScope(c, relUnit, true)
  1012  
  1013  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
  1014  		{Relation: "relation-42", Unit: "unit-foo-0"},
  1015  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1016  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1017  		{Relation: "relation-42", Unit: "unit-wordpress-0"},
  1018  		{Relation: "relation-foo", Unit: "unit-wordpress-0"},
  1019  		{Relation: "service-wordpress", Unit: "unit-foo-0"},
  1020  		{Relation: "foo", Unit: "bar"},
  1021  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1022  		{Relation: rel.Tag(), Unit: "service-wordpress"},
  1023  		{Relation: rel.Tag(), Unit: "service-mysql"},
  1024  		{Relation: rel.Tag(), Unit: "user-admin"},
  1025  	}}
  1026  	result, err := s.uniter.LeaveScope(args)
  1027  	c.Assert(err, gc.IsNil)
  1028  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
  1029  		Results: []params.ErrorResult{
  1030  			{apiservertesting.ErrUnauthorized},
  1031  			{nil},
  1032  			{nil},
  1033  			{apiservertesting.ErrUnauthorized},
  1034  			{apiservertesting.ErrUnauthorized},
  1035  			{apiservertesting.ErrUnauthorized},
  1036  			{apiservertesting.ErrUnauthorized},
  1037  			{apiservertesting.ErrUnauthorized},
  1038  			{apiservertesting.ErrUnauthorized},
  1039  			{apiservertesting.ErrUnauthorized},
  1040  			{apiservertesting.ErrUnauthorized},
  1041  		},
  1042  	})
  1043  
  1044  	// Verify the scope changes.
  1045  	s.assertInScope(c, relUnit, false)
  1046  	readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name())
  1047  	c.Assert(err, gc.IsNil)
  1048  	c.Assert(readSettings, gc.DeepEquals, settings)
  1049  }
  1050  
  1051  func (s *uniterSuite) TestJoinedRelations(c *gc.C) {
  1052  	rel := s.addRelation(c, "wordpress", "mysql")
  1053  	relUnit, err := rel.Unit(s.wordpressUnit)
  1054  	c.Assert(err, gc.IsNil)
  1055  	err = relUnit.EnterScope(nil)
  1056  	c.Assert(err, gc.IsNil)
  1057  
  1058  	args := params.Entities{
  1059  		Entities: []params.Entity{
  1060  			{s.wordpressUnit.Tag()},
  1061  			{s.mysqlUnit.Tag()},
  1062  			{"unit-unknown-1"},
  1063  			{"service-wordpress"},
  1064  			{"machine-0"},
  1065  			{rel.Tag()},
  1066  		},
  1067  	}
  1068  	expect := params.StringsResults{
  1069  		Results: []params.StringsResult{
  1070  			{Result: []string{rel.Tag()}},
  1071  			{Error: apiservertesting.ErrUnauthorized},
  1072  			{Error: apiservertesting.ErrUnauthorized},
  1073  			{Error: apiservertesting.ErrUnauthorized},
  1074  			{Error: apiservertesting.ErrUnauthorized},
  1075  			{Error: apiservertesting.ErrUnauthorized},
  1076  		},
  1077  	}
  1078  	check := func() {
  1079  		result, err := s.uniter.JoinedRelations(args)
  1080  		c.Assert(err, gc.IsNil)
  1081  		c.Assert(result, gc.DeepEquals, expect)
  1082  	}
  1083  	check()
  1084  	err = relUnit.PrepareLeaveScope()
  1085  	c.Assert(err, gc.IsNil)
  1086  	check()
  1087  }
  1088  
  1089  func (s *uniterSuite) TestReadSettings(c *gc.C) {
  1090  	rel := s.addRelation(c, "wordpress", "mysql")
  1091  	relUnit, err := rel.Unit(s.wordpressUnit)
  1092  	c.Assert(err, gc.IsNil)
  1093  	settings := map[string]interface{}{
  1094  		"some": "settings",
  1095  	}
  1096  	err = relUnit.EnterScope(settings)
  1097  	c.Assert(err, gc.IsNil)
  1098  	s.assertInScope(c, relUnit, true)
  1099  
  1100  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
  1101  		{Relation: "relation-42", Unit: "unit-foo-0"},
  1102  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1103  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1104  		{Relation: "relation-42", Unit: "unit-wordpress-0"},
  1105  		{Relation: "relation-foo", Unit: ""},
  1106  		{Relation: "service-wordpress", Unit: "unit-foo-0"},
  1107  		{Relation: "foo", Unit: "bar"},
  1108  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1109  		{Relation: rel.Tag(), Unit: "service-wordpress"},
  1110  		{Relation: rel.Tag(), Unit: "service-mysql"},
  1111  		{Relation: rel.Tag(), Unit: "user-admin"},
  1112  	}}
  1113  	result, err := s.uniter.ReadSettings(args)
  1114  	c.Assert(err, gc.IsNil)
  1115  	c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{
  1116  		Results: []params.RelationSettingsResult{
  1117  			{Error: apiservertesting.ErrUnauthorized},
  1118  			{Settings: params.RelationSettings{
  1119  				"some": "settings",
  1120  			}},
  1121  			{Error: apiservertesting.ErrUnauthorized},
  1122  			{Error: apiservertesting.ErrUnauthorized},
  1123  			{Error: apiservertesting.ErrUnauthorized},
  1124  			{Error: apiservertesting.ErrUnauthorized},
  1125  			{Error: apiservertesting.ErrUnauthorized},
  1126  			{Error: apiservertesting.ErrUnauthorized},
  1127  			{Error: apiservertesting.ErrUnauthorized},
  1128  			{Error: apiservertesting.ErrUnauthorized},
  1129  			{Error: apiservertesting.ErrUnauthorized},
  1130  		},
  1131  	})
  1132  }
  1133  
  1134  func (s *uniterSuite) TestReadSettingsWithNonStringValuesFails(c *gc.C) {
  1135  	rel := s.addRelation(c, "wordpress", "mysql")
  1136  	relUnit, err := rel.Unit(s.wordpressUnit)
  1137  	c.Assert(err, gc.IsNil)
  1138  	settings := map[string]interface{}{
  1139  		"other":        "things",
  1140  		"invalid-bool": false,
  1141  	}
  1142  	err = relUnit.EnterScope(settings)
  1143  	c.Assert(err, gc.IsNil)
  1144  	s.assertInScope(c, relUnit, true)
  1145  
  1146  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
  1147  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1148  	}}
  1149  	expectErr := `unexpected relation setting "invalid-bool": expected string, got bool`
  1150  	result, err := s.uniter.ReadSettings(args)
  1151  	c.Assert(err, gc.IsNil)
  1152  	c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{
  1153  		Results: []params.RelationSettingsResult{
  1154  			{Error: &params.Error{Message: expectErr}},
  1155  		},
  1156  	})
  1157  }
  1158  
  1159  func (s *uniterSuite) TestReadRemoteSettings(c *gc.C) {
  1160  	rel := s.addRelation(c, "wordpress", "mysql")
  1161  	relUnit, err := rel.Unit(s.wordpressUnit)
  1162  	c.Assert(err, gc.IsNil)
  1163  	settings := map[string]interface{}{
  1164  		"some": "settings",
  1165  	}
  1166  	err = relUnit.EnterScope(settings)
  1167  	c.Assert(err, gc.IsNil)
  1168  	s.assertInScope(c, relUnit, true)
  1169  
  1170  	// First test most of the invalid args tests and try to read the
  1171  	// (unset) remote unit settings.
  1172  	args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{
  1173  		{Relation: "relation-42", LocalUnit: "unit-foo-0", RemoteUnit: "foo"},
  1174  		{Relation: rel.Tag(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-wordpress-0"},
  1175  		{Relation: rel.Tag(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-mysql-0"},
  1176  		{Relation: "relation-42", LocalUnit: "unit-wordpress-0", RemoteUnit: ""},
  1177  		{Relation: "relation-foo", LocalUnit: "", RemoteUnit: ""},
  1178  		{Relation: "service-wordpress", LocalUnit: "unit-foo-0", RemoteUnit: "user-admin"},
  1179  		{Relation: "foo", LocalUnit: "bar", RemoteUnit: "baz"},
  1180  		{Relation: rel.Tag(), LocalUnit: "unit-mysql-0", RemoteUnit: "unit-wordpress-0"},
  1181  		{Relation: rel.Tag(), LocalUnit: "service-wordpress", RemoteUnit: "service-mysql"},
  1182  		{Relation: rel.Tag(), LocalUnit: "service-mysql", RemoteUnit: "foo"},
  1183  		{Relation: rel.Tag(), LocalUnit: "user-admin", RemoteUnit: "unit-wordpress-0"},
  1184  	}}
  1185  	result, err := s.uniter.ReadRemoteSettings(args)
  1186  
  1187  	// We don't set the remote unit settings on purpose to test the error.
  1188  	expectErr := `cannot read settings for unit "mysql/0" in relation "wordpress:db mysql:server": settings not found`
  1189  	c.Assert(err, gc.IsNil)
  1190  	c.Assert(result, jc.DeepEquals, params.RelationSettingsResults{
  1191  		Results: []params.RelationSettingsResult{
  1192  			{Error: apiservertesting.ErrUnauthorized},
  1193  			{Error: apiservertesting.ErrUnauthorized},
  1194  			{Error: apiservertesting.ServerError(expectErr)},
  1195  			{Error: apiservertesting.ErrUnauthorized},
  1196  			{Error: apiservertesting.ErrUnauthorized},
  1197  			{Error: apiservertesting.ErrUnauthorized},
  1198  			{Error: apiservertesting.ErrUnauthorized},
  1199  			{Error: apiservertesting.ErrUnauthorized},
  1200  			{Error: apiservertesting.ErrUnauthorized},
  1201  			{Error: apiservertesting.ErrUnauthorized},
  1202  			{Error: apiservertesting.ErrUnauthorized},
  1203  		},
  1204  	})
  1205  
  1206  	// Now leave the mysqlUnit and re-enter with new settings.
  1207  	relUnit, err = rel.Unit(s.mysqlUnit)
  1208  	c.Assert(err, gc.IsNil)
  1209  	settings = map[string]interface{}{
  1210  		"other": "things",
  1211  	}
  1212  	err = relUnit.LeaveScope()
  1213  	c.Assert(err, gc.IsNil)
  1214  	s.assertInScope(c, relUnit, false)
  1215  	err = relUnit.EnterScope(settings)
  1216  	c.Assert(err, gc.IsNil)
  1217  	s.assertInScope(c, relUnit, true)
  1218  
  1219  	// Test the remote unit settings can be read.
  1220  	args = params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{
  1221  		Relation:   rel.Tag(),
  1222  		LocalUnit:  "unit-wordpress-0",
  1223  		RemoteUnit: "unit-mysql-0",
  1224  	}}}
  1225  	expect := params.RelationSettingsResults{
  1226  		Results: []params.RelationSettingsResult{
  1227  			{Settings: params.RelationSettings{
  1228  				"other": "things",
  1229  			}},
  1230  		},
  1231  	}
  1232  	result, err = s.uniter.ReadRemoteSettings(args)
  1233  	c.Assert(err, gc.IsNil)
  1234  	c.Assert(result, gc.DeepEquals, expect)
  1235  
  1236  	// Now destroy the remote unit, and check its settings can still be read.
  1237  	err = s.mysqlUnit.Destroy()
  1238  	c.Assert(err, gc.IsNil)
  1239  	err = s.mysqlUnit.EnsureDead()
  1240  	c.Assert(err, gc.IsNil)
  1241  	err = s.mysqlUnit.Remove()
  1242  	c.Assert(err, gc.IsNil)
  1243  	result, err = s.uniter.ReadRemoteSettings(args)
  1244  	c.Assert(err, gc.IsNil)
  1245  	c.Assert(result, gc.DeepEquals, expect)
  1246  }
  1247  
  1248  func (s *uniterSuite) TestReadRemoteSettingsWithNonStringValuesFails(c *gc.C) {
  1249  	rel := s.addRelation(c, "wordpress", "mysql")
  1250  	relUnit, err := rel.Unit(s.mysqlUnit)
  1251  	c.Assert(err, gc.IsNil)
  1252  	settings := map[string]interface{}{
  1253  		"other":        "things",
  1254  		"invalid-bool": false,
  1255  	}
  1256  	err = relUnit.EnterScope(settings)
  1257  	c.Assert(err, gc.IsNil)
  1258  	s.assertInScope(c, relUnit, true)
  1259  
  1260  	args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{
  1261  		Relation:   rel.Tag(),
  1262  		LocalUnit:  "unit-wordpress-0",
  1263  		RemoteUnit: "unit-mysql-0",
  1264  	}}}
  1265  	expectErr := `unexpected relation setting "invalid-bool": expected string, got bool`
  1266  	result, err := s.uniter.ReadRemoteSettings(args)
  1267  	c.Assert(err, gc.IsNil)
  1268  	c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{
  1269  		Results: []params.RelationSettingsResult{
  1270  			{Error: &params.Error{Message: expectErr}},
  1271  		},
  1272  	})
  1273  }
  1274  
  1275  func (s *uniterSuite) TestUpdateSettings(c *gc.C) {
  1276  	rel := s.addRelation(c, "wordpress", "mysql")
  1277  	relUnit, err := rel.Unit(s.wordpressUnit)
  1278  	c.Assert(err, gc.IsNil)
  1279  	settings := map[string]interface{}{
  1280  		"some":  "settings",
  1281  		"other": "stuff",
  1282  	}
  1283  	err = relUnit.EnterScope(settings)
  1284  	s.assertInScope(c, relUnit, true)
  1285  
  1286  	newSettings := params.RelationSettings{
  1287  		"some":  "different",
  1288  		"other": "",
  1289  	}
  1290  
  1291  	args := params.RelationUnitsSettings{RelationUnits: []params.RelationUnitSettings{
  1292  		{Relation: "relation-42", Unit: "unit-foo-0", Settings: nil},
  1293  		{Relation: rel.Tag(), Unit: "unit-wordpress-0", Settings: newSettings},
  1294  		{Relation: "relation-42", Unit: "unit-wordpress-0", Settings: nil},
  1295  		{Relation: "relation-foo", Unit: "unit-wordpress-0", Settings: nil},
  1296  		{Relation: "service-wordpress", Unit: "unit-foo-0", Settings: nil},
  1297  		{Relation: "foo", Unit: "bar", Settings: nil},
  1298  		{Relation: rel.Tag(), Unit: "unit-mysql-0", Settings: nil},
  1299  		{Relation: rel.Tag(), Unit: "service-wordpress", Settings: nil},
  1300  		{Relation: rel.Tag(), Unit: "service-mysql", Settings: nil},
  1301  		{Relation: rel.Tag(), Unit: "user-admin", Settings: nil},
  1302  	}}
  1303  	result, err := s.uniter.UpdateSettings(args)
  1304  	c.Assert(err, gc.IsNil)
  1305  	c.Assert(result, gc.DeepEquals, params.ErrorResults{
  1306  		Results: []params.ErrorResult{
  1307  			{apiservertesting.ErrUnauthorized},
  1308  			{nil},
  1309  			{apiservertesting.ErrUnauthorized},
  1310  			{apiservertesting.ErrUnauthorized},
  1311  			{apiservertesting.ErrUnauthorized},
  1312  			{apiservertesting.ErrUnauthorized},
  1313  			{apiservertesting.ErrUnauthorized},
  1314  			{apiservertesting.ErrUnauthorized},
  1315  			{apiservertesting.ErrUnauthorized},
  1316  			{apiservertesting.ErrUnauthorized},
  1317  		},
  1318  	})
  1319  
  1320  	// Verify the settings were saved.
  1321  	s.assertInScope(c, relUnit, true)
  1322  	readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name())
  1323  	c.Assert(err, gc.IsNil)
  1324  	c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{
  1325  		"some": "different",
  1326  	})
  1327  }
  1328  
  1329  func (s *uniterSuite) TestWatchRelationUnits(c *gc.C) {
  1330  	// Add a relation between wordpress and mysql and enter scope with
  1331  	// mysqlUnit.
  1332  	rel := s.addRelation(c, "wordpress", "mysql")
  1333  	myRelUnit, err := rel.Unit(s.mysqlUnit)
  1334  	c.Assert(err, gc.IsNil)
  1335  	err = myRelUnit.EnterScope(nil)
  1336  	c.Assert(err, gc.IsNil)
  1337  	s.assertInScope(c, myRelUnit, true)
  1338  
  1339  	c.Assert(s.resources.Count(), gc.Equals, 0)
  1340  
  1341  	args := params.RelationUnits{RelationUnits: []params.RelationUnit{
  1342  		{Relation: "relation-42", Unit: "unit-foo-0"},
  1343  		{Relation: rel.Tag(), Unit: "unit-wordpress-0"},
  1344  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1345  		{Relation: "relation-42", Unit: "unit-wordpress-0"},
  1346  		{Relation: "relation-foo", Unit: ""},
  1347  		{Relation: "service-wordpress", Unit: "unit-foo-0"},
  1348  		{Relation: "foo", Unit: "bar"},
  1349  		{Relation: rel.Tag(), Unit: "unit-mysql-0"},
  1350  		{Relation: rel.Tag(), Unit: "service-wordpress"},
  1351  		{Relation: rel.Tag(), Unit: "service-mysql"},
  1352  		{Relation: rel.Tag(), Unit: "user-admin"},
  1353  	}}
  1354  	result, err := s.uniter.WatchRelationUnits(args)
  1355  	c.Assert(err, gc.IsNil)
  1356  	// UnitSettings versions are volatile, so we don't check them.
  1357  	// We just make sure the keys of the Changed field are as
  1358  	// expected.
  1359  	c.Assert(result.Results, gc.HasLen, len(args.RelationUnits))
  1360  	mysqlChanges := result.Results[1].Changes
  1361  	c.Assert(mysqlChanges, gc.NotNil)
  1362  	changed, ok := mysqlChanges.Changed["mysql/0"]
  1363  	c.Assert(ok, jc.IsTrue)
  1364  	expectChanges := params.RelationUnitsChange{
  1365  		Changed: map[string]params.UnitSettings{"mysql/0": changed},
  1366  	}
  1367  	c.Assert(result, gc.DeepEquals, params.RelationUnitsWatchResults{
  1368  		Results: []params.RelationUnitsWatchResult{
  1369  			{Error: apiservertesting.ErrUnauthorized},
  1370  			{
  1371  				RelationUnitsWatcherId: "1",
  1372  				Changes:                expectChanges,
  1373  			},
  1374  			{Error: apiservertesting.ErrUnauthorized},
  1375  			{Error: apiservertesting.ErrUnauthorized},
  1376  			{Error: apiservertesting.ErrUnauthorized},
  1377  			{Error: apiservertesting.ErrUnauthorized},
  1378  			{Error: apiservertesting.ErrUnauthorized},
  1379  			{Error: apiservertesting.ErrUnauthorized},
  1380  			{Error: apiservertesting.ErrUnauthorized},
  1381  			{Error: apiservertesting.ErrUnauthorized},
  1382  			{Error: apiservertesting.ErrUnauthorized},
  1383  		},
  1384  	})
  1385  
  1386  	// Verify the resource was registered and stop when done
  1387  	c.Assert(s.resources.Count(), gc.Equals, 1)
  1388  	resource := s.resources.Get("1")
  1389  	defer statetesting.AssertStop(c, resource)
  1390  
  1391  	// Check that the Watch has consumed the initial event ("returned" in
  1392  	// the Watch call)
  1393  	wc := statetesting.NewRelationUnitsWatcherC(c, s.State, resource.(state.RelationUnitsWatcher))
  1394  	wc.AssertNoChange()
  1395  
  1396  	// Leave scope with mysqlUnit and check it's detected.
  1397  	err = myRelUnit.LeaveScope()
  1398  	c.Assert(err, gc.IsNil)
  1399  	s.assertInScope(c, myRelUnit, false)
  1400  
  1401  	wc.AssertChange(nil, []string{"mysql/0"})
  1402  }
  1403  
  1404  func (s *uniterSuite) TestAPIAddresses(c *gc.C) {
  1405  	hostPorts := [][]instance.HostPort{{{
  1406  		Address: instance.NewAddress("0.1.2.3", instance.NetworkUnknown),
  1407  		Port:    1234,
  1408  	}}}
  1409  
  1410  	err := s.State.SetAPIHostPorts(hostPorts)
  1411  	c.Assert(err, gc.IsNil)
  1412  
  1413  	result, err := s.uniter.APIAddresses()
  1414  	c.Assert(err, gc.IsNil)
  1415  	c.Assert(result, gc.DeepEquals, params.StringsResult{
  1416  		Result: []string{"0.1.2.3:1234"},
  1417  	})
  1418  }
  1419  
  1420  func (s *uniterSuite) TestGetOwnerTag(c *gc.C) {
  1421  	tag := s.mysql.Tag()
  1422  	args := params.Entities{Entities: []params.Entity{
  1423  		{Tag: tag},
  1424  	}}
  1425  	result, err := s.uniter.GetOwnerTag(args)
  1426  	c.Assert(err, gc.IsNil)
  1427  	c.Assert(result, gc.DeepEquals, params.StringResult{
  1428  		Result: "user-admin",
  1429  	})
  1430  }