launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/cleanup_test.go (about)

     1  package state_test
     2  
     3  import (
     4  	"fmt"
     5  	gc "launchpad.net/gocheck"
     6  
     7  	"launchpad.net/juju-core/charm"
     8  	"launchpad.net/juju-core/errors"
     9  	"launchpad.net/juju-core/instance"
    10  	"launchpad.net/juju-core/state"
    11  	jc "launchpad.net/juju-core/testing/checkers"
    12  )
    13  
    14  type CleanupSuite struct {
    15  	ConnSuite
    16  }
    17  
    18  var _ = gc.Suite(&CleanupSuite{})
    19  
    20  func (s *CleanupSuite) TestCleanupDyingServiceUnits(c *gc.C) {
    21  	s.assertDoesNotNeedCleanup(c)
    22  
    23  	// Create a service with some units.
    24  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
    25  	units := make([]*state.Unit, 3)
    26  	for i := range units {
    27  		unit, err := mysql.AddUnit()
    28  		c.Assert(err, gc.IsNil)
    29  		units[i] = unit
    30  	}
    31  	preventUnitDestroyRemove(c, units[0])
    32  	s.assertDoesNotNeedCleanup(c)
    33  
    34  	// Destroy the service and check the units are unaffected, but a cleanup
    35  	// has been scheduled.
    36  	err := mysql.Destroy()
    37  	c.Assert(err, gc.IsNil)
    38  	for _, unit := range units {
    39  		err := unit.Refresh()
    40  		c.Assert(err, gc.IsNil)
    41  	}
    42  	s.assertNeedsCleanup(c)
    43  
    44  	// Run the cleanup, and check that units are all destroyed as appropriate.
    45  	s.assertCleanupRuns(c)
    46  	s.assertDoesNotNeedCleanup(c)
    47  	err = units[0].Refresh()
    48  	c.Assert(err, gc.IsNil)
    49  	c.Assert(units[0].Life(), gc.Equals, state.Dying)
    50  	err = units[1].Refresh()
    51  	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
    52  	err = units[2].Refresh()
    53  	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
    54  }
    55  
    56  func (s *CleanupSuite) TestCleanupEnvironmentServices(c *gc.C) {
    57  	s.assertDoesNotNeedCleanup(c)
    58  
    59  	// Create a service with some units.
    60  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
    61  	units := make([]*state.Unit, 3)
    62  	for i := range units {
    63  		unit, err := mysql.AddUnit()
    64  		c.Assert(err, gc.IsNil)
    65  		units[i] = unit
    66  	}
    67  	s.assertDoesNotNeedCleanup(c)
    68  
    69  	// Destroy the environment and check the service and units are
    70  	// unaffected, but a cleanup for the service has been scheduled.
    71  	env, err := s.State.Environment()
    72  	c.Assert(err, gc.IsNil)
    73  	err = env.Destroy()
    74  	c.Assert(err, gc.IsNil)
    75  	s.assertNeedsCleanup(c)
    76  	s.assertCleanupRuns(c)
    77  	err = mysql.Refresh()
    78  	c.Assert(err, gc.IsNil)
    79  	c.Assert(mysql.Life(), gc.Equals, state.Dying)
    80  	for _, unit := range units {
    81  		err = unit.Refresh()
    82  		c.Assert(err, gc.IsNil)
    83  		c.Assert(unit.Life(), gc.Equals, state.Alive)
    84  	}
    85  
    86  	// The first cleanup Destroys the service, which
    87  	// schedules another cleanup to destroy the units.
    88  	s.assertNeedsCleanup(c)
    89  	s.assertCleanupRuns(c)
    90  	for _, unit := range units {
    91  		err = unit.Refresh()
    92  		c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
    93  	}
    94  	s.assertDoesNotNeedCleanup(c)
    95  }
    96  
    97  func (s *CleanupSuite) TestCleanupRelationSettings(c *gc.C) {
    98  	s.assertDoesNotNeedCleanup(c)
    99  
   100  	// Create a relation with a unit in scope.
   101  	pr := NewPeerRelation(c, s.State)
   102  	rel := pr.ru0.Relation()
   103  	err := pr.ru0.EnterScope(map[string]interface{}{"some": "settings"})
   104  	c.Assert(err, gc.IsNil)
   105  	s.assertDoesNotNeedCleanup(c)
   106  
   107  	// Destroy the service, check the relation's still around.
   108  	err = pr.svc.Destroy()
   109  	c.Assert(err, gc.IsNil)
   110  	s.assertNeedsCleanup(c)
   111  	s.assertCleanupRuns(c)
   112  	err = rel.Refresh()
   113  	c.Assert(err, gc.IsNil)
   114  	c.Assert(rel.Life(), gc.Equals, state.Dying)
   115  	s.assertDoesNotNeedCleanup(c)
   116  
   117  	// The unit leaves scope, triggering relation removal.
   118  	err = pr.ru0.LeaveScope()
   119  	c.Assert(err, gc.IsNil)
   120  	s.assertNeedsCleanup(c)
   121  
   122  	// Settings are not destroyed yet...
   123  	settings, err := pr.ru1.ReadSettings("riak/0")
   124  	c.Assert(err, gc.IsNil)
   125  	c.Assert(settings, gc.DeepEquals, map[string]interface{}{"some": "settings"})
   126  
   127  	// ...but they are on cleanup.
   128  	s.assertCleanupRuns(c)
   129  	s.assertDoesNotNeedCleanup(c)
   130  	_, err = pr.ru1.ReadSettings("riak/0")
   131  	c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/0" in relation "riak:ring": settings not found`)
   132  }
   133  
   134  func (s *CleanupSuite) TestForceDestroyMachineErrors(c *gc.C) {
   135  	manager, err := s.State.AddMachine("quantal", state.JobManageEnviron)
   136  	c.Assert(err, gc.IsNil)
   137  	s.assertDoesNotNeedCleanup(c)
   138  	err = manager.ForceDestroy()
   139  	expect := fmt.Sprintf("machine %s is required by the environment", manager.Id())
   140  	c.Assert(err, gc.ErrorMatches, expect)
   141  	s.assertDoesNotNeedCleanup(c)
   142  	assertLife(c, manager, state.Alive)
   143  }
   144  
   145  func (s *CleanupSuite) TestCleanupForceDestroyedMachineUnit(c *gc.C) {
   146  	s.assertDoesNotNeedCleanup(c)
   147  
   148  	// Create a machine.
   149  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   150  	c.Assert(err, gc.IsNil)
   151  
   152  	// Create a relation with a unit in scope and assigned to the machine.
   153  	pr := NewPeerRelation(c, s.State)
   154  	err = pr.u0.AssignToMachine(machine)
   155  	c.Assert(err, gc.IsNil)
   156  	err = pr.ru0.EnterScope(nil)
   157  	c.Assert(err, gc.IsNil)
   158  	s.assertDoesNotNeedCleanup(c)
   159  
   160  	// Force machine destruction, check cleanup queued.
   161  	err = machine.ForceDestroy()
   162  	c.Assert(err, gc.IsNil)
   163  	s.assertNeedsCleanup(c)
   164  
   165  	// Clean up, and check that the unit has been removed...
   166  	s.assertCleanupRuns(c)
   167  	s.assertDoesNotNeedCleanup(c)
   168  	assertRemoved(c, pr.u0)
   169  
   170  	// ...and the unit has departed relation scope...
   171  	assertNotInScope(c, pr.ru0)
   172  
   173  	// ...but that the machine remains, and is Dead, ready for removal by the
   174  	// provisioner.
   175  	assertLife(c, machine, state.Dead)
   176  }
   177  
   178  func (s *CleanupSuite) TestCleanupForceDestroyedMachineWithContainer(c *gc.C) {
   179  	s.assertDoesNotNeedCleanup(c)
   180  
   181  	// Create a machine with a container.
   182  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   183  	c.Assert(err, gc.IsNil)
   184  	container, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
   185  		Series: "quantal",
   186  		Jobs:   []state.MachineJob{state.JobHostUnits},
   187  	}, machine.Id(), instance.LXC)
   188  	c.Assert(err, gc.IsNil)
   189  
   190  	// Create active units (in relation scope, with subordinates).
   191  	prr := NewProReqRelation(c, &s.ConnSuite, charm.ScopeContainer)
   192  	err = prr.pru0.EnterScope(nil)
   193  	c.Assert(err, gc.IsNil)
   194  	err = prr.pru1.EnterScope(nil)
   195  	c.Assert(err, gc.IsNil)
   196  	err = prr.rru0.EnterScope(nil)
   197  	c.Assert(err, gc.IsNil)
   198  	err = prr.rru1.EnterScope(nil)
   199  	c.Assert(err, gc.IsNil)
   200  
   201  	// Assign the various units to machines.
   202  	err = prr.pu0.AssignToMachine(machine)
   203  	c.Assert(err, gc.IsNil)
   204  	err = prr.pu1.AssignToMachine(container)
   205  	c.Assert(err, gc.IsNil)
   206  	s.assertDoesNotNeedCleanup(c)
   207  
   208  	// Force removal of the top-level machine.
   209  	err = machine.ForceDestroy()
   210  	c.Assert(err, gc.IsNil)
   211  	s.assertNeedsCleanup(c)
   212  
   213  	// And do it again, just to check that the second cleanup doc for the same
   214  	// machine doesn't cause problems down the line.
   215  	err = machine.ForceDestroy()
   216  	c.Assert(err, gc.IsNil)
   217  	s.assertNeedsCleanup(c)
   218  
   219  	// Clean up, and check that the container has been removed...
   220  	s.assertCleanupRuns(c)
   221  	s.assertDoesNotNeedCleanup(c)
   222  	err = container.Refresh()
   223  	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
   224  
   225  	// ...and so have all the units...
   226  	assertRemoved(c, prr.pu0)
   227  	assertRemoved(c, prr.pu1)
   228  	assertRemoved(c, prr.ru0)
   229  	assertRemoved(c, prr.ru1)
   230  
   231  	// ...and none of the units have left relation scopes occupied...
   232  	assertNotInScope(c, prr.pru0)
   233  	assertNotInScope(c, prr.pru1)
   234  	assertNotInScope(c, prr.rru0)
   235  	assertNotInScope(c, prr.rru1)
   236  
   237  	// ...but that the machine remains, and is Dead, ready for removal by the
   238  	// provisioner.
   239  	assertLife(c, machine, state.Dead)
   240  }
   241  
   242  func (s *CleanupSuite) TestNothingToCleanup(c *gc.C) {
   243  	s.assertDoesNotNeedCleanup(c)
   244  	s.assertCleanupRuns(c)
   245  	s.assertDoesNotNeedCleanup(c)
   246  }
   247  
   248  func (s *CleanupSuite) assertCleanupRuns(c *gc.C) {
   249  	err := s.State.Cleanup()
   250  	c.Assert(err, gc.IsNil)
   251  }
   252  
   253  func (s *CleanupSuite) assertNeedsCleanup(c *gc.C) {
   254  	actual, err := s.State.NeedsCleanup()
   255  	c.Assert(err, gc.IsNil)
   256  	c.Assert(actual, jc.IsTrue)
   257  }
   258  
   259  func (s *CleanupSuite) assertDoesNotNeedCleanup(c *gc.C) {
   260  	actual, err := s.State.NeedsCleanup()
   261  	c.Assert(err, gc.IsNil)
   262  	c.Assert(actual, jc.IsFalse)
   263  }