github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/unit_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	jc "github.com/juju/testing/checkers"
    12  	jujutxn "github.com/juju/txn"
    13  	gc "gopkg.in/check.v1"
    14  	"gopkg.in/juju/charm.v6-unstable"
    15  
    16  	"github.com/juju/juju/instance"
    17  	"github.com/juju/juju/network"
    18  	"github.com/juju/juju/state"
    19  	"github.com/juju/juju/state/testing"
    20  	"github.com/juju/juju/status"
    21  	coretesting "github.com/juju/juju/testing"
    22  )
    23  
    24  const (
    25  	contentionErr = ".*: state changing too quickly; try again soon"
    26  )
    27  
    28  type UnitSuite struct {
    29  	ConnSuite
    30  	charm   *state.Charm
    31  	service *state.Service
    32  	unit    *state.Unit
    33  }
    34  
    35  var _ = gc.Suite(&UnitSuite{})
    36  
    37  func (s *UnitSuite) SetUpTest(c *gc.C) {
    38  	s.ConnSuite.SetUpTest(c)
    39  	s.charm = s.AddTestingCharm(c, "wordpress")
    40  	var err error
    41  	s.service = s.AddTestingService(c, "wordpress", s.charm)
    42  	c.Assert(err, jc.ErrorIsNil)
    43  	s.unit, err = s.service.AddUnit()
    44  	c.Assert(err, jc.ErrorIsNil)
    45  	c.Assert(s.unit.Series(), gc.Equals, "quantal")
    46  }
    47  
    48  func (s *UnitSuite) TestUnitNotFound(c *gc.C) {
    49  	_, err := s.State.Unit("subway/0")
    50  	c.Assert(err, gc.ErrorMatches, `unit "subway/0" not found`)
    51  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
    52  }
    53  
    54  func (s *UnitSuite) TestService(c *gc.C) {
    55  	svc, err := s.unit.Service()
    56  	c.Assert(err, jc.ErrorIsNil)
    57  	c.Assert(svc.Name(), gc.Equals, s.unit.ServiceName())
    58  }
    59  
    60  func (s *UnitSuite) TestConfigSettingsNeedCharmURLSet(c *gc.C) {
    61  	_, err := s.unit.ConfigSettings()
    62  	c.Assert(err, gc.ErrorMatches, "unit charm not set")
    63  }
    64  
    65  func (s *UnitSuite) TestConfigSettingsIncludeDefaults(c *gc.C) {
    66  	err := s.unit.SetCharmURL(s.charm.URL())
    67  	c.Assert(err, jc.ErrorIsNil)
    68  	settings, err := s.unit.ConfigSettings()
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"})
    71  }
    72  
    73  func (s *UnitSuite) TestConfigSettingsReflectService(c *gc.C) {
    74  	err := s.service.UpdateConfigSettings(charm.Settings{"blog-title": "no title"})
    75  	c.Assert(err, jc.ErrorIsNil)
    76  	err = s.unit.SetCharmURL(s.charm.URL())
    77  	c.Assert(err, jc.ErrorIsNil)
    78  	settings, err := s.unit.ConfigSettings()
    79  	c.Assert(err, jc.ErrorIsNil)
    80  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "no title"})
    81  
    82  	err = s.service.UpdateConfigSettings(charm.Settings{"blog-title": "ironic title"})
    83  	c.Assert(err, jc.ErrorIsNil)
    84  	settings, err = s.unit.ConfigSettings()
    85  	c.Assert(err, jc.ErrorIsNil)
    86  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "ironic title"})
    87  }
    88  
    89  func (s *UnitSuite) TestConfigSettingsReflectCharm(c *gc.C) {
    90  	err := s.unit.SetCharmURL(s.charm.URL())
    91  	c.Assert(err, jc.ErrorIsNil)
    92  	newCharm := s.AddConfigCharm(c, "wordpress", "options: {}", 123)
    93  	cfg := state.SetCharmConfig{Charm: newCharm}
    94  	err = s.service.SetCharm(cfg)
    95  	c.Assert(err, jc.ErrorIsNil)
    96  
    97  	// Settings still reflect charm set on unit.
    98  	settings, err := s.unit.ConfigSettings()
    99  	c.Assert(err, jc.ErrorIsNil)
   100  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"})
   101  
   102  	// When the unit has the new charm set, it'll see the new config.
   103  	err = s.unit.SetCharmURL(newCharm.URL())
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	settings, err = s.unit.ConfigSettings()
   106  	c.Assert(err, jc.ErrorIsNil)
   107  	c.Assert(settings, gc.DeepEquals, charm.Settings{})
   108  }
   109  
   110  func (s *UnitSuite) TestWatchConfigSettingsNeedsCharmURL(c *gc.C) {
   111  	_, err := s.unit.WatchConfigSettings()
   112  	c.Assert(err, gc.ErrorMatches, "unit charm not set")
   113  }
   114  
   115  func (s *UnitSuite) TestWatchConfigSettings(c *gc.C) {
   116  	err := s.unit.SetCharmURL(s.charm.URL())
   117  	c.Assert(err, jc.ErrorIsNil)
   118  	w, err := s.unit.WatchConfigSettings()
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	defer testing.AssertStop(c, w)
   121  
   122  	// Initial event.
   123  	wc := testing.NewNotifyWatcherC(c, s.State, w)
   124  	wc.AssertOneChange()
   125  
   126  	// Update config a couple of times, check a single event.
   127  	err = s.service.UpdateConfigSettings(charm.Settings{
   128  		"blog-title": "superhero paparazzi",
   129  	})
   130  	c.Assert(err, jc.ErrorIsNil)
   131  	err = s.service.UpdateConfigSettings(charm.Settings{
   132  		"blog-title": "sauceror central",
   133  	})
   134  	c.Assert(err, jc.ErrorIsNil)
   135  	wc.AssertOneChange()
   136  
   137  	// Non-change is not reported.
   138  	err = s.service.UpdateConfigSettings(charm.Settings{
   139  		"blog-title": "sauceror central",
   140  	})
   141  	c.Assert(err, jc.ErrorIsNil)
   142  	wc.AssertNoChange()
   143  
   144  	// Change service's charm; nothing detected.
   145  	newCharm := s.AddConfigCharm(c, "wordpress", floatConfig, 123)
   146  	cfg := state.SetCharmConfig{Charm: newCharm}
   147  	err = s.service.SetCharm(cfg)
   148  	c.Assert(err, jc.ErrorIsNil)
   149  	wc.AssertNoChange()
   150  
   151  	// Change service config for new charm; nothing detected.
   152  	err = s.service.UpdateConfigSettings(charm.Settings{
   153  		"key": 42.0,
   154  	})
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	wc.AssertNoChange()
   157  
   158  	// NOTE: if we were to change the unit to use the new charm, we'd see
   159  	// another event, because the originally-watched document will become
   160  	// unreferenced and be removed. But I'm not testing that behaviour
   161  	// because it's not very helpful and subject to change.
   162  }
   163  
   164  func (s *UnitSuite) addSubordinateUnit(c *gc.C) *state.Unit {
   165  	subCharm := s.AddTestingCharm(c, "logging")
   166  	s.AddTestingService(c, "logging", subCharm)
   167  	eps, err := s.State.InferEndpoints("wordpress", "logging")
   168  	c.Assert(err, jc.ErrorIsNil)
   169  	rel, err := s.State.AddRelation(eps...)
   170  	c.Assert(err, jc.ErrorIsNil)
   171  	ru, err := rel.Unit(s.unit)
   172  	c.Assert(err, jc.ErrorIsNil)
   173  	err = ru.EnterScope(nil)
   174  	c.Assert(err, jc.ErrorIsNil)
   175  	subUnit, err := s.State.Unit("logging/0")
   176  	c.Assert(err, jc.ErrorIsNil)
   177  	return subUnit
   178  }
   179  
   180  func (s *UnitSuite) setAssignedMachineAddresses(c *gc.C, u *state.Unit) {
   181  	err := u.AssignToNewMachine()
   182  	c.Assert(err, jc.ErrorIsNil)
   183  	mid, err := u.AssignedMachineId()
   184  	c.Assert(err, jc.ErrorIsNil)
   185  	machine, err := s.State.Machine(mid)
   186  	c.Assert(err, jc.ErrorIsNil)
   187  	err = machine.SetProvisioned("i-exist", "fake_nonce", nil)
   188  	c.Assert(err, jc.ErrorIsNil)
   189  	err = machine.SetProviderAddresses(network.Address{
   190  		Type:  network.IPv4Address,
   191  		Scope: network.ScopeCloudLocal,
   192  		Value: "private.address.example.com",
   193  	}, network.Address{
   194  		Type:  network.IPv4Address,
   195  		Scope: network.ScopePublic,
   196  		Value: "public.address.example.com",
   197  	})
   198  	c.Assert(err, jc.ErrorIsNil)
   199  }
   200  
   201  func (s *UnitSuite) TestPublicAddressSubordinate(c *gc.C) {
   202  	subUnit := s.addSubordinateUnit(c)
   203  	address, err := subUnit.PublicAddress()
   204  	c.Assert(err, gc.Not(gc.IsNil))
   205  	c.Assert(address.Value, gc.Equals, "")
   206  
   207  	s.setAssignedMachineAddresses(c, s.unit)
   208  	address, err = subUnit.PublicAddress()
   209  	c.Assert(err, jc.ErrorIsNil)
   210  	c.Assert(address.Value, gc.Equals, "public.address.example.com")
   211  }
   212  
   213  func (s *UnitSuite) TestPublicAddress(c *gc.C) {
   214  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   215  	c.Assert(err, jc.ErrorIsNil)
   216  	err = s.unit.AssignToMachine(machine)
   217  	c.Assert(err, jc.ErrorIsNil)
   218  
   219  	_, err = s.unit.PublicAddress()
   220  	c.Assert(err, jc.Satisfies, network.IsNoAddress)
   221  
   222  	public := network.NewScopedAddress("8.8.8.8", network.ScopePublic)
   223  	private := network.NewScopedAddress("127.0.0.1", network.ScopeCloudLocal)
   224  
   225  	err = machine.SetProviderAddresses(public, private)
   226  	c.Assert(err, jc.ErrorIsNil)
   227  
   228  	address, err := s.unit.PublicAddress()
   229  	c.Assert(err, jc.ErrorIsNil)
   230  	c.Check(address.Value, gc.Equals, "8.8.8.8")
   231  }
   232  
   233  func (s *UnitSuite) TestStablePrivateAddress(c *gc.C) {
   234  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   235  	c.Assert(err, jc.ErrorIsNil)
   236  	err = s.unit.AssignToMachine(machine)
   237  	c.Assert(err, jc.ErrorIsNil)
   238  
   239  	err = machine.SetMachineAddresses(network.NewAddress("10.0.0.2"))
   240  	c.Assert(err, jc.ErrorIsNil)
   241  
   242  	// Now add an address that would previously have sorted before the
   243  	// default.
   244  	err = machine.SetMachineAddresses(network.NewAddress("10.0.0.1"), network.NewAddress("10.0.0.2"))
   245  	c.Assert(err, jc.ErrorIsNil)
   246  
   247  	// Assert the address is unchanged.
   248  	addr, err := s.unit.PrivateAddress()
   249  	c.Assert(err, jc.ErrorIsNil)
   250  	c.Assert(addr.Value, gc.Equals, "10.0.0.2")
   251  }
   252  
   253  func (s *UnitSuite) TestStablePublicAddress(c *gc.C) {
   254  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   255  	c.Assert(err, jc.ErrorIsNil)
   256  	err = s.unit.AssignToMachine(machine)
   257  	c.Assert(err, jc.ErrorIsNil)
   258  
   259  	err = machine.SetProviderAddresses(network.NewAddress("8.8.8.8"))
   260  	c.Assert(err, jc.ErrorIsNil)
   261  
   262  	// Now add an address that would previously have sorted before the
   263  	// default.
   264  	err = machine.SetProviderAddresses(network.NewAddress("8.8.4.4"), network.NewAddress("8.8.8.8"))
   265  	c.Assert(err, jc.ErrorIsNil)
   266  
   267  	// Assert the address is unchanged.
   268  	addr, err := s.unit.PublicAddress()
   269  	c.Assert(err, jc.ErrorIsNil)
   270  	c.Assert(addr.Value, gc.Equals, "8.8.8.8")
   271  }
   272  
   273  func (s *UnitSuite) TestPublicAddressMachineAddresses(c *gc.C) {
   274  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   275  	c.Assert(err, jc.ErrorIsNil)
   276  	err = s.unit.AssignToMachine(machine)
   277  	c.Assert(err, jc.ErrorIsNil)
   278  
   279  	publicProvider := network.NewScopedAddress("8.8.8.8", network.ScopePublic)
   280  	privateProvider := network.NewScopedAddress("127.0.0.1", network.ScopeCloudLocal)
   281  	privateMachine := network.NewAddress("127.0.0.2")
   282  
   283  	err = machine.SetProviderAddresses(privateProvider)
   284  	c.Assert(err, jc.ErrorIsNil)
   285  	err = machine.SetMachineAddresses(privateMachine)
   286  	c.Assert(err, jc.ErrorIsNil)
   287  	address, err := s.unit.PublicAddress()
   288  	c.Assert(err, jc.ErrorIsNil)
   289  	c.Check(address.Value, gc.Equals, "127.0.0.1")
   290  
   291  	err = machine.SetProviderAddresses(publicProvider, privateProvider)
   292  	c.Assert(err, jc.ErrorIsNil)
   293  	address, err = s.unit.PublicAddress()
   294  	c.Assert(err, jc.ErrorIsNil)
   295  	c.Check(address.Value, gc.Equals, "8.8.8.8")
   296  }
   297  
   298  func (s *UnitSuite) TestPrivateAddressSubordinate(c *gc.C) {
   299  	subUnit := s.addSubordinateUnit(c)
   300  	address, err := subUnit.PrivateAddress()
   301  	c.Assert(err, gc.Not(gc.IsNil))
   302  	c.Assert(address.Value, gc.Equals, "")
   303  
   304  	s.setAssignedMachineAddresses(c, s.unit)
   305  	address, err = subUnit.PrivateAddress()
   306  	c.Assert(err, jc.ErrorIsNil)
   307  	c.Assert(address.Value, gc.Equals, "private.address.example.com")
   308  }
   309  
   310  func (s *UnitSuite) TestPrivateAddress(c *gc.C) {
   311  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   312  	c.Assert(err, jc.ErrorIsNil)
   313  	err = s.unit.AssignToMachine(machine)
   314  	c.Assert(err, jc.ErrorIsNil)
   315  
   316  	_, err = s.unit.PrivateAddress()
   317  	c.Assert(err, jc.Satisfies, network.IsNoAddress)
   318  
   319  	public := network.NewScopedAddress("8.8.8.8", network.ScopePublic)
   320  	private := network.NewScopedAddress("127.0.0.1", network.ScopeCloudLocal)
   321  
   322  	err = machine.SetProviderAddresses(public, private)
   323  	c.Assert(err, jc.ErrorIsNil)
   324  
   325  	address, err := s.unit.PrivateAddress()
   326  	c.Assert(err, jc.ErrorIsNil)
   327  	c.Check(address.Value, gc.Equals, "127.0.0.1")
   328  }
   329  
   330  type destroyMachineTestCase struct {
   331  	target    *state.Unit
   332  	host      *state.Machine
   333  	desc      string
   334  	flipHook  []jujutxn.TestHook
   335  	destroyed bool
   336  }
   337  
   338  func (s *UnitSuite) destroyMachineTestCases(c *gc.C) []destroyMachineTestCase {
   339  	var result []destroyMachineTestCase
   340  	var err error
   341  
   342  	{
   343  		tc := destroyMachineTestCase{desc: "standalone principal", destroyed: true}
   344  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   345  		c.Assert(err, jc.ErrorIsNil)
   346  		tc.target, err = s.service.AddUnit()
   347  		c.Assert(err, jc.ErrorIsNil)
   348  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   349  		result = append(result, tc)
   350  	}
   351  	{
   352  		tc := destroyMachineTestCase{desc: "co-located principals", destroyed: false}
   353  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   354  		c.Assert(err, jc.ErrorIsNil)
   355  		tc.target, err = s.service.AddUnit()
   356  		c.Assert(err, jc.ErrorIsNil)
   357  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   358  		colocated, err := s.service.AddUnit()
   359  		c.Assert(err, jc.ErrorIsNil)
   360  		c.Assert(colocated.AssignToMachine(tc.host), gc.IsNil)
   361  
   362  		result = append(result, tc)
   363  	}
   364  	{
   365  		tc := destroyMachineTestCase{desc: "host has container", destroyed: false}
   366  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   367  		c.Assert(err, jc.ErrorIsNil)
   368  		_, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
   369  			Series: "quantal",
   370  			Jobs:   []state.MachineJob{state.JobHostUnits},
   371  		}, tc.host.Id(), instance.LXC)
   372  		c.Assert(err, jc.ErrorIsNil)
   373  		tc.target, err = s.service.AddUnit()
   374  		c.Assert(err, jc.ErrorIsNil)
   375  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   376  
   377  		result = append(result, tc)
   378  	}
   379  	{
   380  		tc := destroyMachineTestCase{desc: "host has vote", destroyed: false}
   381  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   382  		c.Assert(err, jc.ErrorIsNil)
   383  		c.Assert(tc.host.SetHasVote(true), gc.IsNil)
   384  		tc.target, err = s.service.AddUnit()
   385  		c.Assert(err, jc.ErrorIsNil)
   386  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   387  
   388  		result = append(result, tc)
   389  	}
   390  	{
   391  		tc := destroyMachineTestCase{desc: "unassigned unit", destroyed: true}
   392  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   393  		c.Assert(err, jc.ErrorIsNil)
   394  		tc.target, err = s.service.AddUnit()
   395  		c.Assert(err, jc.ErrorIsNil)
   396  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   397  		result = append(result, tc)
   398  	}
   399  
   400  	return result
   401  }
   402  
   403  func (s *UnitSuite) TestRemoveUnitMachineFastForwardDestroy(c *gc.C) {
   404  	for _, tc := range s.destroyMachineTestCases(c) {
   405  		c.Log(tc.desc)
   406  		c.Assert(tc.target.Destroy(), gc.IsNil)
   407  		if tc.destroyed {
   408  			assertLife(c, tc.host, state.Dying)
   409  			c.Assert(tc.host.EnsureDead(), gc.IsNil)
   410  		} else {
   411  			assertLife(c, tc.host, state.Alive)
   412  			c.Assert(tc.host.Destroy(), gc.NotNil)
   413  		}
   414  	}
   415  }
   416  
   417  func (s *UnitSuite) TestRemoveUnitMachineNoFastForwardDestroy(c *gc.C) {
   418  	for _, tc := range s.destroyMachineTestCases(c) {
   419  		c.Log(tc.desc)
   420  		preventUnitDestroyRemove(c, tc.target)
   421  		c.Assert(tc.target.Destroy(), gc.IsNil)
   422  		c.Assert(tc.target.EnsureDead(), gc.IsNil)
   423  		assertLife(c, tc.host, state.Alive)
   424  		c.Assert(tc.target.Remove(), gc.IsNil)
   425  		if tc.destroyed {
   426  			assertLife(c, tc.host, state.Dying)
   427  		} else {
   428  			assertLife(c, tc.host, state.Alive)
   429  			c.Assert(tc.host.Destroy(), gc.NotNil)
   430  		}
   431  	}
   432  }
   433  
   434  func (s *UnitSuite) setMachineVote(c *gc.C, id string, hasVote bool) {
   435  	m, err := s.State.Machine(id)
   436  	c.Assert(err, jc.ErrorIsNil)
   437  	c.Assert(m.SetHasVote(hasVote), gc.IsNil)
   438  }
   439  
   440  func (s *UnitSuite) TestRemoveUnitMachineThrashed(c *gc.C) {
   441  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   442  	c.Assert(err, jc.ErrorIsNil)
   443  	target, err := s.service.AddUnit()
   444  	c.Assert(err, jc.ErrorIsNil)
   445  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   446  	flip := jujutxn.TestHook{
   447  		Before: func() {
   448  			s.setMachineVote(c, host.Id(), true)
   449  		},
   450  	}
   451  	flop := jujutxn.TestHook{
   452  		Before: func() {
   453  			s.setMachineVote(c, host.Id(), false)
   454  		},
   455  	}
   456  	// You'll need to adjust the flip-flops to match the number of transaction
   457  	// retries.
   458  	defer state.SetTestHooks(c, s.State, flip, flop, flip).Check()
   459  
   460  	c.Assert(target.Destroy(), gc.ErrorMatches, "state changing too quickly; try again soon")
   461  }
   462  
   463  func (s *UnitSuite) TestRemoveUnitMachineRetryVoter(c *gc.C) {
   464  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   465  	c.Assert(err, jc.ErrorIsNil)
   466  	target, err := s.service.AddUnit()
   467  	c.Assert(err, jc.ErrorIsNil)
   468  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   469  
   470  	defer state.SetBeforeHooks(c, s.State, func() {
   471  		s.setMachineVote(c, host.Id(), true)
   472  	}, nil).Check()
   473  
   474  	c.Assert(target.Destroy(), gc.IsNil)
   475  	assertLife(c, host, state.Alive)
   476  }
   477  
   478  func (s *UnitSuite) TestRemoveUnitMachineRetryNoVoter(c *gc.C) {
   479  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   480  	c.Assert(err, jc.ErrorIsNil)
   481  	target, err := s.service.AddUnit()
   482  	c.Assert(err, jc.ErrorIsNil)
   483  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   484  	c.Assert(host.SetHasVote(true), gc.IsNil)
   485  
   486  	defer state.SetBeforeHooks(c, s.State, func() {
   487  		s.setMachineVote(c, host.Id(), false)
   488  	}, nil).Check()
   489  
   490  	c.Assert(target.Destroy(), gc.IsNil)
   491  	assertLife(c, host, state.Dying)
   492  }
   493  
   494  func (s *UnitSuite) TestRemoveUnitMachineRetryContainer(c *gc.C) {
   495  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   496  	c.Assert(err, jc.ErrorIsNil)
   497  	target, err := s.service.AddUnit()
   498  	c.Assert(err, jc.ErrorIsNil)
   499  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   500  	defer state.SetTestHooks(c, s.State, jujutxn.TestHook{
   501  		Before: func() {
   502  			machine, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
   503  				Series: "quantal",
   504  				Jobs:   []state.MachineJob{state.JobHostUnits},
   505  			}, host.Id(), instance.LXC)
   506  			c.Assert(err, jc.ErrorIsNil)
   507  			assertLife(c, machine, state.Alive)
   508  
   509  			// test-setup verification for the disqualifying machine.
   510  			hostHandle, err := s.State.Machine(host.Id())
   511  			c.Assert(err, jc.ErrorIsNil)
   512  			containers, err := hostHandle.Containers()
   513  			c.Assert(err, jc.ErrorIsNil)
   514  			c.Assert(containers, gc.HasLen, 1)
   515  		},
   516  	}).Check()
   517  
   518  	c.Assert(target.Destroy(), gc.IsNil)
   519  	assertLife(c, host, state.Alive)
   520  }
   521  
   522  func (s *UnitSuite) TestRemoveUnitMachineRetryOrCond(c *gc.C) {
   523  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   524  	c.Assert(err, jc.ErrorIsNil)
   525  	target, err := s.service.AddUnit()
   526  	c.Assert(err, jc.ErrorIsNil)
   527  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   528  
   529  	// This unit will be colocated in the transaction hook to cause a retry.
   530  	colocated, err := s.service.AddUnit()
   531  	c.Assert(err, jc.ErrorIsNil)
   532  
   533  	c.Assert(host.SetHasVote(true), gc.IsNil)
   534  
   535  	defer state.SetTestHooks(c, s.State, jujutxn.TestHook{
   536  		Before: func() {
   537  			hostHandle, err := s.State.Machine(host.Id())
   538  			c.Assert(err, jc.ErrorIsNil)
   539  
   540  			// Original assertion preventing host removal is no longer valid
   541  			c.Assert(hostHandle.SetHasVote(false), gc.IsNil)
   542  
   543  			// But now the host gets a colocated unit, a different condition preventing removal
   544  			c.Assert(colocated.AssignToMachine(hostHandle), gc.IsNil)
   545  		},
   546  	}).Check()
   547  
   548  	c.Assert(target.Destroy(), gc.IsNil)
   549  	assertLife(c, host, state.Alive)
   550  }
   551  
   552  func (s *UnitSuite) TestRefresh(c *gc.C) {
   553  	unit1, err := s.State.Unit(s.unit.Name())
   554  	c.Assert(err, jc.ErrorIsNil)
   555  
   556  	err = s.unit.SetPassword("arble-farble-dying-yarble")
   557  	c.Assert(err, jc.ErrorIsNil)
   558  	valid := unit1.PasswordValid("arble-farble-dying-yarble")
   559  	c.Assert(valid, jc.IsFalse)
   560  	err = unit1.Refresh()
   561  	c.Assert(err, jc.ErrorIsNil)
   562  	valid = unit1.PasswordValid("arble-farble-dying-yarble")
   563  	c.Assert(valid, jc.IsTrue)
   564  
   565  	err = unit1.EnsureDead()
   566  	c.Assert(err, jc.ErrorIsNil)
   567  	err = unit1.Remove()
   568  	c.Assert(err, jc.ErrorIsNil)
   569  	err = unit1.Refresh()
   570  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   571  }
   572  
   573  func (s *UnitSuite) TestSetCharmURLSuccess(c *gc.C) {
   574  	preventUnitDestroyRemove(c, s.unit)
   575  	curl, ok := s.unit.CharmURL()
   576  	c.Assert(ok, jc.IsFalse)
   577  	c.Assert(curl, gc.IsNil)
   578  
   579  	err := s.unit.SetCharmURL(s.charm.URL())
   580  	c.Assert(err, jc.ErrorIsNil)
   581  
   582  	curl, ok = s.unit.CharmURL()
   583  	c.Assert(ok, jc.IsTrue)
   584  	c.Assert(curl, gc.DeepEquals, s.charm.URL())
   585  }
   586  
   587  func (s *UnitSuite) TestSetCharmURLFailures(c *gc.C) {
   588  	preventUnitDestroyRemove(c, s.unit)
   589  	curl, ok := s.unit.CharmURL()
   590  	c.Assert(ok, jc.IsFalse)
   591  	c.Assert(curl, gc.IsNil)
   592  
   593  	err := s.unit.SetCharmURL(nil)
   594  	c.Assert(err, gc.ErrorMatches, "cannot set nil charm url")
   595  
   596  	err = s.unit.SetCharmURL(charm.MustParseURL("cs:missing/one-1"))
   597  	c.Assert(err, gc.ErrorMatches, `unknown charm url "cs:missing/one-1"`)
   598  
   599  	err = s.unit.EnsureDead()
   600  	c.Assert(err, jc.ErrorIsNil)
   601  	err = s.unit.SetCharmURL(s.charm.URL())
   602  	c.Assert(err, gc.Equals, state.ErrDead)
   603  }
   604  
   605  func (s *UnitSuite) TestSetCharmURLWithRemovedUnit(c *gc.C) {
   606  	err := s.unit.Destroy()
   607  	c.Assert(err, jc.ErrorIsNil)
   608  	assertRemoved(c, s.unit)
   609  
   610  	err = s.unit.SetCharmURL(s.charm.URL())
   611  	c.Assert(err, gc.Equals, state.ErrDead)
   612  }
   613  
   614  func (s *UnitSuite) TestSetCharmURLWithDyingUnit(c *gc.C) {
   615  	preventUnitDestroyRemove(c, s.unit)
   616  	err := s.unit.Destroy()
   617  	c.Assert(err, jc.ErrorIsNil)
   618  	assertLife(c, s.unit, state.Dying)
   619  
   620  	err = s.unit.SetCharmURL(s.charm.URL())
   621  	c.Assert(err, jc.ErrorIsNil)
   622  
   623  	curl, ok := s.unit.CharmURL()
   624  	c.Assert(ok, jc.IsTrue)
   625  	c.Assert(curl, gc.DeepEquals, s.charm.URL())
   626  }
   627  
   628  func (s *UnitSuite) TestSetCharmURLRetriesWithDeadUnit(c *gc.C) {
   629  	preventUnitDestroyRemove(c, s.unit)
   630  
   631  	defer state.SetBeforeHooks(c, s.State, func() {
   632  		err := s.unit.Destroy()
   633  		c.Assert(err, jc.ErrorIsNil)
   634  		err = s.unit.EnsureDead()
   635  		c.Assert(err, jc.ErrorIsNil)
   636  		assertLife(c, s.unit, state.Dead)
   637  	}).Check()
   638  
   639  	err := s.unit.SetCharmURL(s.charm.URL())
   640  	c.Assert(err, gc.Equals, state.ErrDead)
   641  }
   642  
   643  func (s *UnitSuite) TestSetCharmURLRetriesWithDifferentURL(c *gc.C) {
   644  	sch := s.AddConfigCharm(c, "wordpress", emptyConfig, 2)
   645  
   646  	defer state.SetTestHooks(c, s.State,
   647  		jujutxn.TestHook{
   648  			Before: func() {
   649  				// Set a different charm to force a retry: first on
   650  				// the service, so the settings are created, then on
   651  				// the unit.
   652  				cfg := state.SetCharmConfig{Charm: sch}
   653  				err := s.service.SetCharm(cfg)
   654  				c.Assert(err, jc.ErrorIsNil)
   655  				err = s.unit.SetCharmURL(sch.URL())
   656  				c.Assert(err, jc.ErrorIsNil)
   657  			},
   658  			After: func() {
   659  				// Set back the same charm on the service, so the
   660  				// settings refcount is correct..
   661  				cfg := state.SetCharmConfig{Charm: s.charm}
   662  				err := s.service.SetCharm(cfg)
   663  				c.Assert(err, jc.ErrorIsNil)
   664  			},
   665  		},
   666  		jujutxn.TestHook{
   667  			Before: nil, // Ensure there will be a retry.
   668  			After: func() {
   669  				// Verify it worked after the second attempt.
   670  				err := s.unit.Refresh()
   671  				c.Assert(err, jc.ErrorIsNil)
   672  				currentURL, hasURL := s.unit.CharmURL()
   673  				c.Assert(currentURL, jc.DeepEquals, s.charm.URL())
   674  				c.Assert(hasURL, jc.IsTrue)
   675  			},
   676  		},
   677  	).Check()
   678  
   679  	err := s.unit.SetCharmURL(s.charm.URL())
   680  	c.Assert(err, jc.ErrorIsNil)
   681  }
   682  
   683  func (s *UnitSuite) TestDestroySetStatusRetry(c *gc.C) {
   684  	defer state.SetRetryHooks(c, s.State, func() {
   685  		err := s.unit.SetAgentStatus(status.StatusIdle, "", nil)
   686  		c.Assert(err, jc.ErrorIsNil)
   687  	}, func() {
   688  		assertLife(c, s.unit, state.Dying)
   689  	}).Check()
   690  
   691  	err := s.unit.Destroy()
   692  	c.Assert(err, jc.ErrorIsNil)
   693  }
   694  
   695  func (s *UnitSuite) TestDestroySetCharmRetry(c *gc.C) {
   696  	defer state.SetRetryHooks(c, s.State, func() {
   697  		err := s.unit.SetCharmURL(s.charm.URL())
   698  		c.Assert(err, jc.ErrorIsNil)
   699  	}, func() {
   700  		assertRemoved(c, s.unit)
   701  	}).Check()
   702  
   703  	err := s.unit.Destroy()
   704  	c.Assert(err, jc.ErrorIsNil)
   705  }
   706  
   707  func (s *UnitSuite) TestDestroyChangeCharmRetry(c *gc.C) {
   708  	err := s.unit.SetCharmURL(s.charm.URL())
   709  	c.Assert(err, jc.ErrorIsNil)
   710  	newCharm := s.AddConfigCharm(c, "mysql", "options: {}", 99)
   711  	cfg := state.SetCharmConfig{Charm: newCharm}
   712  	err = s.service.SetCharm(cfg)
   713  	c.Assert(err, jc.ErrorIsNil)
   714  
   715  	defer state.SetRetryHooks(c, s.State, func() {
   716  		err := s.unit.SetCharmURL(newCharm.URL())
   717  		c.Assert(err, jc.ErrorIsNil)
   718  	}, func() {
   719  		assertRemoved(c, s.unit)
   720  	}).Check()
   721  
   722  	err = s.unit.Destroy()
   723  	c.Assert(err, jc.ErrorIsNil)
   724  }
   725  
   726  func (s *UnitSuite) TestDestroyAssignRetry(c *gc.C) {
   727  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   728  	c.Assert(err, jc.ErrorIsNil)
   729  
   730  	defer state.SetRetryHooks(c, s.State, func() {
   731  		err := s.unit.AssignToMachine(machine)
   732  		c.Assert(err, jc.ErrorIsNil)
   733  	}, func() {
   734  		assertRemoved(c, s.unit)
   735  		// Also check the unit ref was properly removed from the machine doc --
   736  		// if it weren't, we wouldn't be able to make the machine Dead.
   737  		err := machine.EnsureDead()
   738  		c.Assert(err, jc.ErrorIsNil)
   739  	}).Check()
   740  
   741  	err = s.unit.Destroy()
   742  	c.Assert(err, jc.ErrorIsNil)
   743  }
   744  
   745  func (s *UnitSuite) TestDestroyUnassignRetry(c *gc.C) {
   746  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   747  	c.Assert(err, jc.ErrorIsNil)
   748  	err = s.unit.AssignToMachine(machine)
   749  	c.Assert(err, jc.ErrorIsNil)
   750  
   751  	defer state.SetRetryHooks(c, s.State, func() {
   752  		err := s.unit.UnassignFromMachine()
   753  		c.Assert(err, jc.ErrorIsNil)
   754  	}, func() {
   755  		assertRemoved(c, s.unit)
   756  	}).Check()
   757  
   758  	err = s.unit.Destroy()
   759  	c.Assert(err, jc.ErrorIsNil)
   760  }
   761  
   762  func (s *UnitSuite) TestShortCircuitDestroyUnit(c *gc.C) {
   763  	// A unit that has not set any status is removed directly.
   764  	err := s.unit.Destroy()
   765  	c.Assert(err, jc.ErrorIsNil)
   766  	c.Assert(s.unit.Life(), gc.Equals, state.Dying)
   767  	assertRemoved(c, s.unit)
   768  }
   769  
   770  func (s *UnitSuite) TestCannotShortCircuitDestroyWithSubordinates(c *gc.C) {
   771  	// A unit with subordinates is just set to Dying.
   772  	s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
   773  	eps, err := s.State.InferEndpoints("logging", "wordpress")
   774  	c.Assert(err, jc.ErrorIsNil)
   775  	rel, err := s.State.AddRelation(eps...)
   776  	c.Assert(err, jc.ErrorIsNil)
   777  	ru, err := rel.Unit(s.unit)
   778  	c.Assert(err, jc.ErrorIsNil)
   779  	err = ru.EnterScope(nil)
   780  	c.Assert(err, jc.ErrorIsNil)
   781  	err = s.unit.Destroy()
   782  	c.Assert(err, jc.ErrorIsNil)
   783  	c.Assert(s.unit.Life(), gc.Equals, state.Dying)
   784  	assertLife(c, s.unit, state.Dying)
   785  }
   786  
   787  func (s *UnitSuite) TestCannotShortCircuitDestroyWithAgentStatus(c *gc.C) {
   788  	for i, test := range []struct {
   789  		status status.Status
   790  		info   string
   791  	}{{
   792  		status.StatusExecuting, "blah",
   793  	}, {
   794  		status.StatusIdle, "blah",
   795  	}, {
   796  		status.StatusFailed, "blah",
   797  	}, {
   798  		status.StatusRebooting, "blah",
   799  	}} {
   800  		c.Logf("test %d: %s", i, test.status)
   801  		unit, err := s.service.AddUnit()
   802  		c.Assert(err, jc.ErrorIsNil)
   803  		err = unit.SetAgentStatus(test.status, test.info, nil)
   804  		c.Assert(err, jc.ErrorIsNil)
   805  		err = unit.Destroy()
   806  		c.Assert(err, jc.ErrorIsNil)
   807  		c.Assert(unit.Life(), gc.Equals, state.Dying)
   808  		assertLife(c, unit, state.Dying)
   809  	}
   810  }
   811  
   812  func (s *UnitSuite) TestShortCircuitDestroyWithProvisionedMachine(c *gc.C) {
   813  	// A unit assigned to a provisioned machine is still removed directly so
   814  	// long as it has not set status.
   815  	err := s.unit.AssignToNewMachine()
   816  	c.Assert(err, jc.ErrorIsNil)
   817  	mid, err := s.unit.AssignedMachineId()
   818  	c.Assert(err, jc.ErrorIsNil)
   819  	machine, err := s.State.Machine(mid)
   820  	c.Assert(err, jc.ErrorIsNil)
   821  	err = machine.SetProvisioned("i-malive", "fake_nonce", nil)
   822  	c.Assert(err, jc.ErrorIsNil)
   823  	err = s.unit.Destroy()
   824  	c.Assert(err, jc.ErrorIsNil)
   825  	c.Assert(s.unit.Life(), gc.Equals, state.Dying)
   826  	assertRemoved(c, s.unit)
   827  }
   828  
   829  func assertLife(c *gc.C, entity state.Living, life state.Life) {
   830  	c.Assert(entity.Refresh(), gc.IsNil)
   831  	c.Assert(entity.Life(), gc.Equals, life)
   832  }
   833  
   834  func assertRemoved(c *gc.C, entity state.Living) {
   835  	err := entity.Refresh()
   836  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   837  	err = entity.Destroy()
   838  	c.Assert(err, jc.ErrorIsNil)
   839  	if entity, ok := entity.(state.AgentLiving); ok {
   840  		err = entity.EnsureDead()
   841  		c.Assert(err, jc.ErrorIsNil)
   842  		err = entity.Remove()
   843  		c.Assert(err, jc.ErrorIsNil)
   844  	}
   845  }
   846  
   847  func (s *UnitSuite) TestTag(c *gc.C) {
   848  	c.Assert(s.unit.Tag().String(), gc.Equals, "unit-wordpress-0")
   849  }
   850  
   851  func (s *UnitSuite) TestSetPassword(c *gc.C) {
   852  	preventUnitDestroyRemove(c, s.unit)
   853  	testSetPassword(c, func() (state.Authenticator, error) {
   854  		return s.State.Unit(s.unit.Name())
   855  	})
   856  }
   857  
   858  func (s *UnitSuite) TestUnitSetAgentPresence(c *gc.C) {
   859  	alive, err := s.unit.AgentPresence()
   860  	c.Assert(err, jc.ErrorIsNil)
   861  	c.Assert(alive, jc.IsFalse)
   862  
   863  	pinger, err := s.unit.SetAgentPresence()
   864  	c.Assert(err, jc.ErrorIsNil)
   865  	c.Assert(pinger, gc.NotNil)
   866  	defer pinger.Stop()
   867  
   868  	s.State.StartSync()
   869  	alive, err = s.unit.AgentPresence()
   870  	c.Assert(err, jc.ErrorIsNil)
   871  	c.Assert(alive, jc.IsTrue)
   872  }
   873  
   874  func (s *UnitSuite) TestUnitWaitAgentPresence(c *gc.C) {
   875  	alive, err := s.unit.AgentPresence()
   876  	c.Assert(err, jc.ErrorIsNil)
   877  	c.Assert(alive, jc.IsFalse)
   878  
   879  	err = s.unit.WaitAgentPresence(coretesting.ShortWait)
   880  	c.Assert(err, gc.ErrorMatches, `waiting for agent of unit "wordpress/0": still not alive after timeout`)
   881  
   882  	pinger, err := s.unit.SetAgentPresence()
   883  	c.Assert(err, jc.ErrorIsNil)
   884  
   885  	s.State.StartSync()
   886  	err = s.unit.WaitAgentPresence(coretesting.LongWait)
   887  	c.Assert(err, jc.ErrorIsNil)
   888  
   889  	alive, err = s.unit.AgentPresence()
   890  	c.Assert(err, jc.ErrorIsNil)
   891  	c.Assert(alive, jc.IsTrue)
   892  
   893  	err = pinger.KillForTesting()
   894  	c.Assert(err, jc.ErrorIsNil)
   895  
   896  	s.State.StartSync()
   897  
   898  	alive, err = s.unit.AgentPresence()
   899  	c.Assert(err, jc.ErrorIsNil)
   900  	c.Assert(alive, jc.IsFalse)
   901  }
   902  
   903  func (s *UnitSuite) TestResolve(c *gc.C) {
   904  	err := s.unit.Resolve(false)
   905  	c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" is not in an error state`)
   906  	err = s.unit.Resolve(true)
   907  	c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" is not in an error state`)
   908  
   909  	err = s.unit.SetAgentStatus(status.StatusError, "gaaah", nil)
   910  	c.Assert(err, jc.ErrorIsNil)
   911  	err = s.unit.Resolve(false)
   912  	c.Assert(err, jc.ErrorIsNil)
   913  	err = s.unit.Resolve(true)
   914  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": already resolved`)
   915  	c.Assert(s.unit.Resolved(), gc.Equals, state.ResolvedNoHooks)
   916  
   917  	err = s.unit.ClearResolved()
   918  	c.Assert(err, jc.ErrorIsNil)
   919  	err = s.unit.Resolve(true)
   920  	c.Assert(err, jc.ErrorIsNil)
   921  	err = s.unit.Resolve(false)
   922  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": already resolved`)
   923  	c.Assert(s.unit.Resolved(), gc.Equals, state.ResolvedRetryHooks)
   924  }
   925  
   926  func (s *UnitSuite) TestGetSetClearResolved(c *gc.C) {
   927  	mode := s.unit.Resolved()
   928  	c.Assert(mode, gc.Equals, state.ResolvedNone)
   929  
   930  	err := s.unit.SetResolved(state.ResolvedNoHooks)
   931  	c.Assert(err, jc.ErrorIsNil)
   932  	err = s.unit.SetResolved(state.ResolvedNoHooks)
   933  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": already resolved`)
   934  
   935  	mode = s.unit.Resolved()
   936  	c.Assert(mode, gc.Equals, state.ResolvedNoHooks)
   937  	err = s.unit.Refresh()
   938  	c.Assert(err, jc.ErrorIsNil)
   939  	mode = s.unit.Resolved()
   940  	c.Assert(mode, gc.Equals, state.ResolvedNoHooks)
   941  
   942  	err = s.unit.ClearResolved()
   943  	c.Assert(err, jc.ErrorIsNil)
   944  	mode = s.unit.Resolved()
   945  	c.Assert(mode, gc.Equals, state.ResolvedNone)
   946  	err = s.unit.Refresh()
   947  	c.Assert(err, jc.ErrorIsNil)
   948  	mode = s.unit.Resolved()
   949  	c.Assert(mode, gc.Equals, state.ResolvedNone)
   950  	err = s.unit.ClearResolved()
   951  	c.Assert(err, jc.ErrorIsNil)
   952  
   953  	err = s.unit.SetResolved(state.ResolvedNone)
   954  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": invalid error resolution mode: ""`)
   955  	err = s.unit.SetResolved(state.ResolvedMode("foo"))
   956  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": invalid error resolution mode: "foo"`)
   957  }
   958  
   959  func (s *UnitSuite) TestOpenedPortsOnInvalidSubnet(c *gc.C) {
   960  	s.testOpenedPorts(c, "bad CIDR", `invalid subnet ID "bad CIDR"`)
   961  }
   962  
   963  func (s *UnitSuite) TestOpenedPortsOnUnknownSubnet(c *gc.C) {
   964  	// We're not adding the 127.0.0.0/8 subnet to test the "not found" case.
   965  	s.testOpenedPorts(c, "127.0.0.0/8", `subnet "127.0.0.0/8" not found or not alive`)
   966  }
   967  
   968  func (s *UnitSuite) TestOpenedPortsOnDeadSubnet(c *gc.C) {
   969  	// We're adding the 0.1.2.0/24 subnet first and then setting it to Dead to
   970  	// check the "not alive" case.
   971  	subnet, err := s.State.AddSubnet(state.SubnetInfo{CIDR: "0.1.2.0/24"})
   972  	c.Assert(err, jc.ErrorIsNil)
   973  	err = subnet.EnsureDead()
   974  	c.Assert(err, jc.ErrorIsNil)
   975  
   976  	s.testOpenedPorts(c, "0.1.2.0/24", `subnet "0.1.2.0/24" not found or not alive`)
   977  }
   978  
   979  func (s *UnitSuite) TestOpenedPortsOnAliveIPv4Subnet(c *gc.C) {
   980  	_, err := s.State.AddSubnet(state.SubnetInfo{CIDR: "192.168.0.0/16"})
   981  	c.Assert(err, jc.ErrorIsNil)
   982  
   983  	s.testOpenedPorts(c, "192.168.0.0/16", "")
   984  }
   985  
   986  func (s *UnitSuite) TestOpenedPortsOnAliveIPv6Subnet(c *gc.C) {
   987  	_, err := s.State.AddSubnet(state.SubnetInfo{CIDR: "2001:db8::/64"})
   988  	c.Assert(err, jc.ErrorIsNil)
   989  
   990  	s.testOpenedPorts(c, "2001:db8::/64", "")
   991  }
   992  
   993  func (s *UnitSuite) TestOpenedPortsOnEmptySubnet(c *gc.C) {
   994  	// TODO(dimitern): This should go away and become an error once we always
   995  	// explicitly pass subnet IDs when handling unit ports.
   996  	s.testOpenedPorts(c, "", "")
   997  }
   998  
   999  func (s *UnitSuite) testOpenedPorts(c *gc.C, subnetID, expectedErrorCauseMatches string) {
  1000  
  1001  	checkExpectedError := func(err error) bool {
  1002  		if expectedErrorCauseMatches == "" {
  1003  			c.Check(err, jc.ErrorIsNil)
  1004  			return true
  1005  		}
  1006  		c.Check(errors.Cause(err), gc.ErrorMatches, expectedErrorCauseMatches)
  1007  		return false
  1008  	}
  1009  
  1010  	// Verify ports can be opened and closed only when the unit has
  1011  	// assigned machine.
  1012  	err := s.unit.OpenPortOnSubnet(subnetID, "tcp", 10)
  1013  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1014  	err = s.unit.OpenPortsOnSubnet(subnetID, "tcp", 10, 20)
  1015  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1016  	err = s.unit.ClosePortOnSubnet(subnetID, "tcp", 10)
  1017  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1018  	err = s.unit.ClosePortsOnSubnet(subnetID, "tcp", 10, 20)
  1019  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1020  	open, err := s.unit.OpenedPortsOnSubnet(subnetID)
  1021  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1022  	c.Check(open, gc.HasLen, 0)
  1023  
  1024  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
  1025  	c.Check(err, jc.ErrorIsNil)
  1026  	err = s.unit.AssignToMachine(machine)
  1027  	c.Check(err, jc.ErrorIsNil)
  1028  
  1029  	// Verify no open ports before activity.
  1030  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1031  	if checkExpectedError(err) {
  1032  		c.Check(open, gc.HasLen, 0)
  1033  	}
  1034  
  1035  	// Now open and close ports and ranges and check.
  1036  
  1037  	err = s.unit.OpenPortOnSubnet(subnetID, "tcp", 80)
  1038  	checkExpectedError(err)
  1039  	err = s.unit.OpenPortsOnSubnet(subnetID, "udp", 100, 200)
  1040  	checkExpectedError(err)
  1041  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1042  	if checkExpectedError(err) {
  1043  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1044  			{80, 80, "tcp"},
  1045  			{100, 200, "udp"},
  1046  		})
  1047  	}
  1048  
  1049  	err = s.unit.OpenPortOnSubnet(subnetID, "udp", 53)
  1050  	checkExpectedError(err)
  1051  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1052  	if checkExpectedError(err) {
  1053  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1054  			{80, 80, "tcp"},
  1055  			{53, 53, "udp"},
  1056  			{100, 200, "udp"},
  1057  		})
  1058  	}
  1059  
  1060  	err = s.unit.OpenPortsOnSubnet(subnetID, "tcp", 53, 55)
  1061  	checkExpectedError(err)
  1062  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1063  	if checkExpectedError(err) {
  1064  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1065  			{53, 55, "tcp"},
  1066  			{80, 80, "tcp"},
  1067  			{53, 53, "udp"},
  1068  			{100, 200, "udp"},
  1069  		})
  1070  	}
  1071  
  1072  	err = s.unit.OpenPortOnSubnet(subnetID, "tcp", 443)
  1073  	checkExpectedError(err)
  1074  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1075  	if checkExpectedError(err) {
  1076  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1077  			{53, 55, "tcp"},
  1078  			{80, 80, "tcp"},
  1079  			{443, 443, "tcp"},
  1080  			{53, 53, "udp"},
  1081  			{100, 200, "udp"},
  1082  		})
  1083  	}
  1084  
  1085  	err = s.unit.ClosePortOnSubnet(subnetID, "tcp", 80)
  1086  	checkExpectedError(err)
  1087  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1088  	if checkExpectedError(err) {
  1089  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1090  			{53, 55, "tcp"},
  1091  			{443, 443, "tcp"},
  1092  			{53, 53, "udp"},
  1093  			{100, 200, "udp"},
  1094  		})
  1095  	}
  1096  
  1097  	err = s.unit.ClosePortsOnSubnet(subnetID, "udp", 100, 200)
  1098  	checkExpectedError(err)
  1099  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1100  	if checkExpectedError(err) {
  1101  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1102  			{53, 55, "tcp"},
  1103  			{443, 443, "tcp"},
  1104  			{53, 53, "udp"},
  1105  		})
  1106  	}
  1107  }
  1108  
  1109  func (s *UnitSuite) TestOpenClosePortWhenDying(c *gc.C) {
  1110  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
  1111  	c.Assert(err, jc.ErrorIsNil)
  1112  	err = s.unit.AssignToMachine(machine)
  1113  	c.Assert(err, jc.ErrorIsNil)
  1114  
  1115  	preventUnitDestroyRemove(c, s.unit)
  1116  	testWhenDying(c, s.unit, noErr, contentionErr, func() error {
  1117  		err := s.unit.OpenPort("tcp", 20)
  1118  		if err != nil {
  1119  			return err
  1120  		}
  1121  		err = s.unit.OpenPorts("tcp", 10, 15)
  1122  		if err != nil {
  1123  			return err
  1124  		}
  1125  		err = s.unit.Refresh()
  1126  		if err != nil {
  1127  			return err
  1128  		}
  1129  		err = s.unit.ClosePort("tcp", 20)
  1130  		if err != nil {
  1131  			return err
  1132  		}
  1133  		return s.unit.ClosePorts("tcp", 10, 15)
  1134  	})
  1135  }
  1136  
  1137  func (s *UnitSuite) TestRemoveLastUnitOnMachineRemovesAllPorts(c *gc.C) {
  1138  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
  1139  	c.Assert(err, jc.ErrorIsNil)
  1140  	err = s.unit.AssignToMachine(machine)
  1141  	c.Assert(err, jc.ErrorIsNil)
  1142  
  1143  	ports, err := machine.AllPorts()
  1144  	c.Assert(err, jc.ErrorIsNil)
  1145  	c.Assert(ports, gc.HasLen, 0)
  1146  
  1147  	err = s.unit.OpenPorts("tcp", 100, 200)
  1148  	c.Assert(err, jc.ErrorIsNil)
  1149  
  1150  	ports, err = machine.AllPorts()
  1151  	c.Assert(err, jc.ErrorIsNil)
  1152  	c.Assert(ports, gc.HasLen, 1)
  1153  	c.Assert(ports[0].PortsForUnit(s.unit.Name()), jc.DeepEquals, []state.PortRange{
  1154  		{s.unit.Name(), 100, 200, "tcp"},
  1155  	})
  1156  
  1157  	// Now remove the unit and check again.
  1158  	err = s.unit.EnsureDead()
  1159  	c.Assert(err, jc.ErrorIsNil)
  1160  	err = s.unit.Remove()
  1161  	c.Assert(err, jc.ErrorIsNil)
  1162  	err = s.unit.Refresh()
  1163  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1164  
  1165  	// Because that was the only range open, the ports doc will be
  1166  	// removed as well.
  1167  	ports, err = machine.AllPorts()
  1168  	c.Assert(err, jc.ErrorIsNil)
  1169  	c.Assert(ports, gc.HasLen, 0)
  1170  }
  1171  
  1172  func (s *UnitSuite) TestRemoveUnitRemovesItsPortsOnly(c *gc.C) {
  1173  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
  1174  	c.Assert(err, jc.ErrorIsNil)
  1175  	err = s.unit.AssignToMachine(machine)
  1176  	c.Assert(err, jc.ErrorIsNil)
  1177  
  1178  	otherUnit, err := s.service.AddUnit()
  1179  	c.Assert(err, jc.ErrorIsNil)
  1180  	err = otherUnit.AssignToMachine(machine)
  1181  	c.Assert(err, jc.ErrorIsNil)
  1182  
  1183  	ports, err := machine.AllPorts()
  1184  	c.Assert(err, jc.ErrorIsNil)
  1185  	c.Assert(ports, gc.HasLen, 0)
  1186  
  1187  	err = s.unit.OpenPorts("tcp", 100, 200)
  1188  	c.Assert(err, jc.ErrorIsNil)
  1189  	err = otherUnit.OpenPorts("udp", 300, 400)
  1190  	c.Assert(err, jc.ErrorIsNil)
  1191  
  1192  	ports, err = machine.AllPorts()
  1193  	c.Assert(err, jc.ErrorIsNil)
  1194  	c.Assert(ports, gc.HasLen, 1)
  1195  	c.Assert(ports[0].PortsForUnit(s.unit.Name()), jc.DeepEquals, []state.PortRange{
  1196  		{s.unit.Name(), 100, 200, "tcp"},
  1197  	})
  1198  	c.Assert(ports[0].PortsForUnit(otherUnit.Name()), jc.DeepEquals, []state.PortRange{
  1199  		{otherUnit.Name(), 300, 400, "udp"},
  1200  	})
  1201  
  1202  	// Now remove the first unit and check again.
  1203  	err = s.unit.EnsureDead()
  1204  	c.Assert(err, jc.ErrorIsNil)
  1205  	err = s.unit.Remove()
  1206  	c.Assert(err, jc.ErrorIsNil)
  1207  	err = s.unit.Refresh()
  1208  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1209  
  1210  	// Verify only otherUnit still has open ports.
  1211  	ports, err = machine.AllPorts()
  1212  	c.Assert(err, jc.ErrorIsNil)
  1213  	c.Assert(ports, gc.HasLen, 1)
  1214  	c.Assert(ports[0].PortsForUnit(s.unit.Name()), gc.HasLen, 0)
  1215  	c.Assert(ports[0].PortsForUnit(otherUnit.Name()), jc.DeepEquals, []state.PortRange{
  1216  		{otherUnit.Name(), 300, 400, "udp"},
  1217  	})
  1218  }
  1219  
  1220  func (s *UnitSuite) TestSetClearResolvedWhenNotAlive(c *gc.C) {
  1221  	preventUnitDestroyRemove(c, s.unit)
  1222  	err := s.unit.Destroy()
  1223  	c.Assert(err, jc.ErrorIsNil)
  1224  	err = s.unit.SetResolved(state.ResolvedNoHooks)
  1225  	c.Assert(err, jc.ErrorIsNil)
  1226  	err = s.unit.Refresh()
  1227  	c.Assert(err, jc.ErrorIsNil)
  1228  	c.Assert(s.unit.Resolved(), gc.Equals, state.ResolvedNoHooks)
  1229  	err = s.unit.ClearResolved()
  1230  	c.Assert(err, jc.ErrorIsNil)
  1231  
  1232  	err = s.unit.EnsureDead()
  1233  	c.Assert(err, jc.ErrorIsNil)
  1234  	err = s.unit.SetResolved(state.ResolvedRetryHooks)
  1235  	c.Assert(err, gc.ErrorMatches, deadErr)
  1236  	err = s.unit.ClearResolved()
  1237  	c.Assert(err, jc.ErrorIsNil)
  1238  }
  1239  
  1240  func (s *UnitSuite) TestSubordinateChangeInPrincipal(c *gc.C) {
  1241  	subCharm := s.AddTestingCharm(c, "logging")
  1242  	for i := 0; i < 2; i++ {
  1243  		// Note: subordinate units can only be created as a side effect of a
  1244  		// principal entering scope; and a given principal can only have a
  1245  		// single subordinate unit of each service.
  1246  		name := "logging" + strconv.Itoa(i)
  1247  		s.AddTestingService(c, name, subCharm)
  1248  		eps, err := s.State.InferEndpoints(name, "wordpress")
  1249  		c.Assert(err, jc.ErrorIsNil)
  1250  		rel, err := s.State.AddRelation(eps...)
  1251  		c.Assert(err, jc.ErrorIsNil)
  1252  		ru, err := rel.Unit(s.unit)
  1253  		c.Assert(err, jc.ErrorIsNil)
  1254  		err = ru.EnterScope(nil)
  1255  		c.Assert(err, jc.ErrorIsNil)
  1256  	}
  1257  
  1258  	err := s.unit.Refresh()
  1259  	c.Assert(err, jc.ErrorIsNil)
  1260  	subordinates := s.unit.SubordinateNames()
  1261  	c.Assert(subordinates, gc.DeepEquals, []string{"logging0/0", "logging1/0"})
  1262  
  1263  	su1, err := s.State.Unit("logging1/0")
  1264  	c.Assert(err, jc.ErrorIsNil)
  1265  	err = su1.EnsureDead()
  1266  	c.Assert(err, jc.ErrorIsNil)
  1267  	err = su1.Remove()
  1268  	c.Assert(err, jc.ErrorIsNil)
  1269  	err = s.unit.Refresh()
  1270  	c.Assert(err, jc.ErrorIsNil)
  1271  	subordinates = s.unit.SubordinateNames()
  1272  	c.Assert(subordinates, gc.DeepEquals, []string{"logging0/0"})
  1273  }
  1274  
  1275  func (s *UnitSuite) TestDeathWithSubordinates(c *gc.C) {
  1276  	// Check that units can become dead when they've never had subordinates.
  1277  	u, err := s.service.AddUnit()
  1278  	c.Assert(err, jc.ErrorIsNil)
  1279  	err = u.EnsureDead()
  1280  	c.Assert(err, jc.ErrorIsNil)
  1281  
  1282  	// Create a new unit and add a subordinate.
  1283  	u, err = s.service.AddUnit()
  1284  	c.Assert(err, jc.ErrorIsNil)
  1285  	s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
  1286  	c.Assert(err, jc.ErrorIsNil)
  1287  	eps, err := s.State.InferEndpoints("logging", "wordpress")
  1288  	c.Assert(err, jc.ErrorIsNil)
  1289  	rel, err := s.State.AddRelation(eps...)
  1290  	c.Assert(err, jc.ErrorIsNil)
  1291  	ru, err := rel.Unit(u)
  1292  	c.Assert(err, jc.ErrorIsNil)
  1293  	err = ru.EnterScope(nil)
  1294  	c.Assert(err, jc.ErrorIsNil)
  1295  
  1296  	// Check the unit cannot become Dead, but can become Dying...
  1297  	err = u.EnsureDead()
  1298  	c.Assert(err, gc.Equals, state.ErrUnitHasSubordinates)
  1299  	err = u.Destroy()
  1300  	c.Assert(err, jc.ErrorIsNil)
  1301  
  1302  	// ...and that it still can't become Dead now it's Dying.
  1303  	err = u.EnsureDead()
  1304  	c.Assert(err, gc.Equals, state.ErrUnitHasSubordinates)
  1305  
  1306  	// Make the subordinate Dead and check the principal still cannot be removed.
  1307  	sub, err := s.State.Unit("logging/0")
  1308  	c.Assert(err, jc.ErrorIsNil)
  1309  	err = sub.EnsureDead()
  1310  	c.Assert(err, jc.ErrorIsNil)
  1311  	err = u.EnsureDead()
  1312  	c.Assert(err, gc.Equals, state.ErrUnitHasSubordinates)
  1313  
  1314  	// remove the subordinate and check the principal can finally become Dead.
  1315  	err = sub.Remove()
  1316  	c.Assert(err, jc.ErrorIsNil)
  1317  	err = u.EnsureDead()
  1318  	c.Assert(err, jc.ErrorIsNil)
  1319  }
  1320  
  1321  func (s *UnitSuite) TestPrincipalName(c *gc.C) {
  1322  	subCharm := s.AddTestingCharm(c, "logging")
  1323  	s.AddTestingService(c, "logging", subCharm)
  1324  	eps, err := s.State.InferEndpoints("logging", "wordpress")
  1325  	c.Assert(err, jc.ErrorIsNil)
  1326  	rel, err := s.State.AddRelation(eps...)
  1327  	c.Assert(err, jc.ErrorIsNil)
  1328  	ru, err := rel.Unit(s.unit)
  1329  	c.Assert(err, jc.ErrorIsNil)
  1330  	err = ru.EnterScope(nil)
  1331  	c.Assert(err, jc.ErrorIsNil)
  1332  
  1333  	err = s.unit.Refresh()
  1334  	c.Assert(err, jc.ErrorIsNil)
  1335  	subordinates := s.unit.SubordinateNames()
  1336  	c.Assert(subordinates, gc.DeepEquals, []string{"logging/0"})
  1337  
  1338  	su, err := s.State.Unit("logging/0")
  1339  	c.Assert(err, jc.ErrorIsNil)
  1340  	principal, valid := su.PrincipalName()
  1341  	c.Assert(valid, jc.IsTrue)
  1342  	c.Assert(principal, gc.Equals, s.unit.Name())
  1343  
  1344  	// Calling PrincipalName on a principal unit yields "", false.
  1345  	principal, valid = s.unit.PrincipalName()
  1346  	c.Assert(valid, jc.IsFalse)
  1347  	c.Assert(principal, gc.Equals, "")
  1348  }
  1349  
  1350  func (s *UnitSuite) TestRelations(c *gc.C) {
  1351  	wordpress0 := s.unit
  1352  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1353  	mysql0, err := mysql.AddUnit()
  1354  	c.Assert(err, jc.ErrorIsNil)
  1355  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
  1356  	c.Assert(err, jc.ErrorIsNil)
  1357  	rel, err := s.State.AddRelation(eps...)
  1358  	c.Assert(err, jc.ErrorIsNil)
  1359  
  1360  	assertEquals := func(actual, expect []*state.Relation) {
  1361  		c.Assert(actual, gc.HasLen, len(expect))
  1362  		for i, a := range actual {
  1363  			c.Assert(a.Id(), gc.Equals, expect[i].Id())
  1364  		}
  1365  	}
  1366  	assertRelationsJoined := func(unit *state.Unit, expect ...*state.Relation) {
  1367  		actual, err := unit.RelationsJoined()
  1368  		c.Assert(err, jc.ErrorIsNil)
  1369  		assertEquals(actual, expect)
  1370  	}
  1371  	assertRelationsInScope := func(unit *state.Unit, expect ...*state.Relation) {
  1372  		actual, err := unit.RelationsInScope()
  1373  		c.Assert(err, jc.ErrorIsNil)
  1374  		assertEquals(actual, expect)
  1375  	}
  1376  	assertRelations := func(unit *state.Unit, expect ...*state.Relation) {
  1377  		assertRelationsInScope(unit, expect...)
  1378  		assertRelationsJoined(unit, expect...)
  1379  	}
  1380  	assertRelations(wordpress0)
  1381  	assertRelations(mysql0)
  1382  
  1383  	mysql0ru, err := rel.Unit(mysql0)
  1384  	c.Assert(err, jc.ErrorIsNil)
  1385  	err = mysql0ru.EnterScope(nil)
  1386  	c.Assert(err, jc.ErrorIsNil)
  1387  	assertRelations(wordpress0)
  1388  	assertRelations(mysql0, rel)
  1389  
  1390  	wordpress0ru, err := rel.Unit(wordpress0)
  1391  	c.Assert(err, jc.ErrorIsNil)
  1392  	err = wordpress0ru.EnterScope(nil)
  1393  	c.Assert(err, jc.ErrorIsNil)
  1394  	assertRelations(wordpress0, rel)
  1395  	assertRelations(mysql0, rel)
  1396  
  1397  	err = mysql0ru.PrepareLeaveScope()
  1398  	c.Assert(err, jc.ErrorIsNil)
  1399  	assertRelations(wordpress0, rel)
  1400  	assertRelationsInScope(mysql0, rel)
  1401  	assertRelationsJoined(mysql0)
  1402  }
  1403  
  1404  func (s *UnitSuite) TestRemove(c *gc.C) {
  1405  	err := s.unit.Remove()
  1406  	c.Assert(err, gc.ErrorMatches, `cannot remove unit "wordpress/0": unit is not dead`)
  1407  	err = s.unit.EnsureDead()
  1408  	c.Assert(err, jc.ErrorIsNil)
  1409  	err = s.unit.Remove()
  1410  	c.Assert(err, jc.ErrorIsNil)
  1411  	err = s.unit.Refresh()
  1412  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1413  	units, err := s.service.AllUnits()
  1414  	c.Assert(err, jc.ErrorIsNil)
  1415  	c.Assert(units, gc.HasLen, 0)
  1416  	err = s.unit.Remove()
  1417  	c.Assert(err, jc.ErrorIsNil)
  1418  }
  1419  
  1420  func (s *UnitSuite) TestRemovePathological(c *gc.C) {
  1421  	// Add a relation between wordpress and mysql...
  1422  	wordpress := s.service
  1423  	wordpress0 := s.unit
  1424  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1425  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
  1426  	c.Assert(err, jc.ErrorIsNil)
  1427  	rel, err := s.State.AddRelation(eps...)
  1428  	c.Assert(err, jc.ErrorIsNil)
  1429  
  1430  	// The relation holds a reference to wordpress, but that can't keep
  1431  	// wordpress from being removed -- because the relation will be removed
  1432  	// if we destroy wordpress.
  1433  	// However, if a unit of the *other* service joins the relation, that
  1434  	// will add an additional reference and prevent the relation -- and
  1435  	// thus wordpress itself -- from being removed when its last unit is.
  1436  	mysql0, err := mysql.AddUnit()
  1437  	c.Assert(err, jc.ErrorIsNil)
  1438  	mysql0ru, err := rel.Unit(mysql0)
  1439  	c.Assert(err, jc.ErrorIsNil)
  1440  	err = mysql0ru.EnterScope(nil)
  1441  	c.Assert(err, jc.ErrorIsNil)
  1442  
  1443  	// Destroy wordpress, and remove its last unit.
  1444  	err = wordpress.Destroy()
  1445  	c.Assert(err, jc.ErrorIsNil)
  1446  	err = wordpress0.EnsureDead()
  1447  	c.Assert(err, jc.ErrorIsNil)
  1448  	err = wordpress0.Remove()
  1449  	c.Assert(err, jc.ErrorIsNil)
  1450  
  1451  	// Check this didn't kill the service or relation yet...
  1452  	err = wordpress.Refresh()
  1453  	c.Assert(err, jc.ErrorIsNil)
  1454  	err = rel.Refresh()
  1455  	c.Assert(err, jc.ErrorIsNil)
  1456  
  1457  	// ...but when the unit on the other side departs the relation, the
  1458  	// relation and the other service are cleaned up.
  1459  	err = mysql0ru.LeaveScope()
  1460  	c.Assert(err, jc.ErrorIsNil)
  1461  	err = wordpress.Refresh()
  1462  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1463  	err = rel.Refresh()
  1464  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1465  }
  1466  
  1467  func (s *UnitSuite) TestRemovePathologicalWithBuggyUniter(c *gc.C) {
  1468  	// Add a relation between wordpress and mysql...
  1469  	wordpress := s.service
  1470  	wordpress0 := s.unit
  1471  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1472  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
  1473  	c.Assert(err, jc.ErrorIsNil)
  1474  	rel, err := s.State.AddRelation(eps...)
  1475  	c.Assert(err, jc.ErrorIsNil)
  1476  
  1477  	// The relation holds a reference to wordpress, but that can't keep
  1478  	// wordpress from being removed -- because the relation will be removed
  1479  	// if we destroy wordpress.
  1480  	// However, if a unit of the *other* service joins the relation, that
  1481  	// will add an additional reference and prevent the relation -- and
  1482  	// thus wordpress itself -- from being removed when its last unit is.
  1483  	mysql0, err := mysql.AddUnit()
  1484  	c.Assert(err, jc.ErrorIsNil)
  1485  	mysql0ru, err := rel.Unit(mysql0)
  1486  	c.Assert(err, jc.ErrorIsNil)
  1487  	err = mysql0ru.EnterScope(nil)
  1488  	c.Assert(err, jc.ErrorIsNil)
  1489  
  1490  	// Destroy wordpress, and remove its last unit.
  1491  	err = wordpress.Destroy()
  1492  	c.Assert(err, jc.ErrorIsNil)
  1493  	err = wordpress0.EnsureDead()
  1494  	c.Assert(err, jc.ErrorIsNil)
  1495  	err = wordpress0.Remove()
  1496  	c.Assert(err, jc.ErrorIsNil)
  1497  
  1498  	// Check this didn't kill the service or relation yet...
  1499  	err = wordpress.Refresh()
  1500  	c.Assert(err, jc.ErrorIsNil)
  1501  	err = rel.Refresh()
  1502  	c.Assert(err, jc.ErrorIsNil)
  1503  
  1504  	// ...and that when the malfunctioning unit agent on the other side
  1505  	// sets itself to dead *without* departing the relation, the unit's
  1506  	// removal causes the relation and the other service to be cleaned up.
  1507  	err = mysql0.EnsureDead()
  1508  	c.Assert(err, jc.ErrorIsNil)
  1509  	err = mysql0.Remove()
  1510  	c.Assert(err, jc.ErrorIsNil)
  1511  	err = wordpress.Refresh()
  1512  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1513  	err = rel.Refresh()
  1514  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1515  }
  1516  
  1517  func (s *UnitSuite) TestWatchSubordinates(c *gc.C) {
  1518  	// TODO(mjs) - ModelUUID - test with multiple models with
  1519  	// identically named units and ensure there's no leakage.
  1520  	w := s.unit.WatchSubordinateUnits()
  1521  	defer testing.AssertStop(c, w)
  1522  	wc := testing.NewStringsWatcherC(c, s.State, w)
  1523  	wc.AssertChange()
  1524  	wc.AssertNoChange()
  1525  
  1526  	// Add a couple of subordinates, check change.
  1527  	subCharm := s.AddTestingCharm(c, "logging")
  1528  	var subUnits []*state.Unit
  1529  	for i := 0; i < 2; i++ {
  1530  		// Note: subordinate units can only be created as a side effect of a
  1531  		// principal entering scope; and a given principal can only have a
  1532  		// single subordinate unit of each service.
  1533  		name := "logging" + strconv.Itoa(i)
  1534  		subSvc := s.AddTestingService(c, name, subCharm)
  1535  		eps, err := s.State.InferEndpoints(name, "wordpress")
  1536  		c.Assert(err, jc.ErrorIsNil)
  1537  		rel, err := s.State.AddRelation(eps...)
  1538  		c.Assert(err, jc.ErrorIsNil)
  1539  		ru, err := rel.Unit(s.unit)
  1540  		c.Assert(err, jc.ErrorIsNil)
  1541  		err = ru.EnterScope(nil)
  1542  		c.Assert(err, jc.ErrorIsNil)
  1543  		units, err := subSvc.AllUnits()
  1544  		c.Assert(err, jc.ErrorIsNil)
  1545  		c.Assert(units, gc.HasLen, 1)
  1546  		subUnits = append(subUnits, units[0])
  1547  	}
  1548  	wc.AssertChange(subUnits[0].Name(), subUnits[1].Name())
  1549  	wc.AssertNoChange()
  1550  
  1551  	// Set one to Dying, check change.
  1552  	err := subUnits[0].Destroy()
  1553  	c.Assert(err, jc.ErrorIsNil)
  1554  	wc.AssertChange(subUnits[0].Name())
  1555  	wc.AssertNoChange()
  1556  
  1557  	// Set both to Dead, and remove one; check change.
  1558  	err = subUnits[0].EnsureDead()
  1559  	c.Assert(err, jc.ErrorIsNil)
  1560  	err = subUnits[1].EnsureDead()
  1561  	c.Assert(err, jc.ErrorIsNil)
  1562  	err = subUnits[1].Remove()
  1563  	c.Assert(err, jc.ErrorIsNil)
  1564  	wc.AssertChange(subUnits[0].Name(), subUnits[1].Name())
  1565  	wc.AssertNoChange()
  1566  
  1567  	// Stop watcher, check closed.
  1568  	testing.AssertStop(c, w)
  1569  	wc.AssertClosed()
  1570  
  1571  	// Start a new watch, check Dead unit is reported.
  1572  	w = s.unit.WatchSubordinateUnits()
  1573  	defer testing.AssertStop(c, w)
  1574  	wc = testing.NewStringsWatcherC(c, s.State, w)
  1575  	wc.AssertChange(subUnits[0].Name())
  1576  	wc.AssertNoChange()
  1577  
  1578  	// Remove the leftover, check no change.
  1579  	err = subUnits[0].Remove()
  1580  	c.Assert(err, jc.ErrorIsNil)
  1581  	wc.AssertNoChange()
  1582  }
  1583  
  1584  func (s *UnitSuite) TestWatchUnit(c *gc.C) {
  1585  	preventUnitDestroyRemove(c, s.unit)
  1586  	w := s.unit.Watch()
  1587  	defer testing.AssertStop(c, w)
  1588  
  1589  	// Initial event.
  1590  	wc := testing.NewNotifyWatcherC(c, s.State, w)
  1591  	wc.AssertOneChange()
  1592  
  1593  	// Make one change (to a separate instance), check one event.
  1594  	unit, err := s.State.Unit(s.unit.Name())
  1595  	c.Assert(err, jc.ErrorIsNil)
  1596  	s.setAssignedMachineAddresses(c, unit)
  1597  	wc.AssertOneChange()
  1598  
  1599  	// Make two changes, check one event.
  1600  	err = unit.SetPassword("arble-farble-dying-yarble")
  1601  	c.Assert(err, jc.ErrorIsNil)
  1602  	err = unit.Destroy()
  1603  	c.Assert(err, jc.ErrorIsNil)
  1604  	wc.AssertOneChange()
  1605  
  1606  	// Stop, check closed.
  1607  	testing.AssertStop(c, w)
  1608  	wc.AssertClosed()
  1609  
  1610  	// Remove unit, start new watch, check single event.
  1611  	err = unit.EnsureDead()
  1612  	c.Assert(err, jc.ErrorIsNil)
  1613  	err = unit.Remove()
  1614  	c.Assert(err, jc.ErrorIsNil)
  1615  	w = s.unit.Watch()
  1616  	defer testing.AssertStop(c, w)
  1617  	testing.NewNotifyWatcherC(c, s.State, w).AssertOneChange()
  1618  }
  1619  
  1620  func (s *UnitSuite) TestUnitAgentTools(c *gc.C) {
  1621  	preventUnitDestroyRemove(c, s.unit)
  1622  	testAgentTools(c, s.unit, `unit "wordpress/0"`)
  1623  }
  1624  
  1625  func (s *UnitSuite) TestValidActionsAndSpecs(c *gc.C) {
  1626  	basicActions := `
  1627  snapshot:
  1628    params:
  1629      outfile:
  1630        type: string
  1631        default: "abcd"
  1632  `[1:]
  1633  
  1634  	wordpress := s.AddTestingService(c, "wordpress-actions", s.AddActionsCharm(c, "wordpress", basicActions, 1))
  1635  	unit1, err := wordpress.AddUnit()
  1636  	c.Assert(err, jc.ErrorIsNil)
  1637  	specs, err := unit1.ActionSpecs()
  1638  	c.Assert(err, jc.ErrorIsNil)
  1639  	c.Check(specs, jc.DeepEquals, state.ActionSpecsByName{
  1640  		"snapshot": charm.ActionSpec{
  1641  			Description: "No description",
  1642  			Params: map[string]interface{}{
  1643  				"type":        "object",
  1644  				"title":       "snapshot",
  1645  				"description": "No description",
  1646  				"properties": map[string]interface{}{
  1647  					"outfile": map[string]interface{}{
  1648  						"type":    "string",
  1649  						"default": "abcd",
  1650  					},
  1651  				},
  1652  			},
  1653  		},
  1654  	})
  1655  
  1656  	var tests = []struct {
  1657  		actionName      string
  1658  		errString       string
  1659  		givenPayload    map[string]interface{}
  1660  		expectedPayload map[string]interface{}
  1661  	}{
  1662  		{
  1663  			actionName:      "snapshot",
  1664  			expectedPayload: map[string]interface{}{"outfile": "abcd"},
  1665  		},
  1666  		{
  1667  			actionName: "juju-run",
  1668  			errString:  `validation failed: (root) : "command" property is missing and required, given {}; (root) : "timeout" property is missing and required, given {}`,
  1669  		},
  1670  		{
  1671  			actionName:   "juju-run",
  1672  			givenPayload: map[string]interface{}{"command": "allyourbasearebelongtous"},
  1673  			errString:    `validation failed: (root) : "timeout" property is missing and required, given {"command":"allyourbasearebelongtous"}`,
  1674  		},
  1675  		{
  1676  			actionName:   "juju-run",
  1677  			givenPayload: map[string]interface{}{"timeout": 5 * time.Second},
  1678  			errString:    `validation failed: (root) : "command" property is missing and required, given {"timeout":5e+09}`,
  1679  		},
  1680  		{
  1681  			actionName:      "juju-run",
  1682  			givenPayload:    map[string]interface{}{"command": "allyourbasearebelongtous", "timeout": 5.0},
  1683  			expectedPayload: map[string]interface{}{"command": "allyourbasearebelongtous", "timeout": 5.0},
  1684  		},
  1685  		{
  1686  			actionName: "baiku",
  1687  			errString:  `action "baiku" not defined on unit "wordpress-actions/0"`,
  1688  		},
  1689  	}
  1690  
  1691  	for i, t := range tests {
  1692  		c.Logf("running test %d", i)
  1693  		action, err := unit1.AddAction(t.actionName, t.givenPayload)
  1694  		if t.errString != "" {
  1695  			c.Assert(err.Error(), gc.Equals, t.errString)
  1696  			continue
  1697  		} else {
  1698  			c.Assert(err, jc.ErrorIsNil)
  1699  			c.Assert(action.Parameters(), jc.DeepEquals, t.expectedPayload)
  1700  		}
  1701  	}
  1702  }
  1703  
  1704  func (s *UnitSuite) TestUnitActionsFindsRightActions(c *gc.C) {
  1705  	// An actions.yaml which permits actions by the following names
  1706  	basicActions := `
  1707  action-a-a:
  1708  action-a-b:
  1709  action-a-c:
  1710  action-b-a:
  1711  action-b-b:
  1712  `[1:]
  1713  
  1714  	// Add simple service and two units
  1715  	dummy := s.AddTestingService(c, "dummy", s.AddActionsCharm(c, "dummy", basicActions, 1))
  1716  
  1717  	unit1, err := dummy.AddUnit()
  1718  	c.Assert(err, jc.ErrorIsNil)
  1719  
  1720  	unit2, err := dummy.AddUnit()
  1721  	c.Assert(err, jc.ErrorIsNil)
  1722  
  1723  	// Add 3 actions to first unit, and 2 to the second unit
  1724  	_, err = unit1.AddAction("action-a-a", nil)
  1725  	c.Assert(err, jc.ErrorIsNil)
  1726  	_, err = unit1.AddAction("action-a-b", nil)
  1727  	c.Assert(err, jc.ErrorIsNil)
  1728  	_, err = unit1.AddAction("action-a-c", nil)
  1729  	c.Assert(err, jc.ErrorIsNil)
  1730  
  1731  	_, err = unit2.AddAction("action-b-a", nil)
  1732  	c.Assert(err, jc.ErrorIsNil)
  1733  	_, err = unit2.AddAction("action-b-b", nil)
  1734  	c.Assert(err, jc.ErrorIsNil)
  1735  
  1736  	// Verify that calling Actions on unit1 returns only
  1737  	// the three actions added to unit1
  1738  	actions1, err := unit1.Actions()
  1739  	c.Assert(err, jc.ErrorIsNil)
  1740  	c.Assert(len(actions1), gc.Equals, 3)
  1741  	for _, action := range actions1 {
  1742  		c.Assert(action.Name(), gc.Matches, "^action-a-.")
  1743  	}
  1744  
  1745  	// Verify that calling Actions on unit2 returns only
  1746  	// the two actions added to unit2
  1747  	actions2, err := unit2.Actions()
  1748  	c.Assert(err, jc.ErrorIsNil)
  1749  	c.Assert(len(actions2), gc.Equals, 2)
  1750  	for _, action := range actions2 {
  1751  		c.Assert(action.Name(), gc.Matches, "^action-b-.")
  1752  	}
  1753  }