github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/state/life_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	jc "github.com/juju/testing/checkers"
     8  	gc "gopkg.in/check.v1"
     9  	"gopkg.in/mgo.v2/bson"
    10  
    11  	"github.com/juju/juju/state"
    12  )
    13  
    14  type LifeSuite struct {
    15  	ConnSuite
    16  	charm *state.Charm
    17  	svc   *state.Service
    18  }
    19  
    20  func (s *LifeSuite) SetUpTest(c *gc.C) {
    21  	s.ConnSuite.SetUpTest(c)
    22  	s.charm = s.AddTestingCharm(c, "dummy")
    23  	s.svc = s.AddTestingService(c, "dummysvc", s.charm)
    24  }
    25  
    26  var _ = gc.Suite(&LifeSuite{})
    27  
    28  var stateChanges = []struct {
    29  	cached, desired    state.Life
    30  	dbinitial, dbfinal state.Life
    31  }{
    32  	{
    33  		state.Alive, state.Dying,
    34  		state.Alive, state.Dying,
    35  	},
    36  	{
    37  		state.Alive, state.Dying,
    38  		state.Dying, state.Dying,
    39  	},
    40  	{
    41  		state.Alive, state.Dying,
    42  		state.Dead, state.Dead,
    43  	},
    44  	{
    45  		state.Alive, state.Dead,
    46  		state.Alive, state.Dead,
    47  	},
    48  	{
    49  		state.Alive, state.Dead,
    50  		state.Dying, state.Dead,
    51  	},
    52  	{
    53  		state.Alive, state.Dead,
    54  		state.Dead, state.Dead,
    55  	},
    56  	{
    57  		state.Dying, state.Dying,
    58  		state.Dying, state.Dying,
    59  	},
    60  	{
    61  		state.Dying, state.Dying,
    62  		state.Dead, state.Dead,
    63  	},
    64  	{
    65  		state.Dying, state.Dead,
    66  		state.Dying, state.Dead,
    67  	},
    68  	{
    69  		state.Dying, state.Dead,
    70  		state.Dead, state.Dead,
    71  	},
    72  	{
    73  		state.Dead, state.Dying,
    74  		state.Dead, state.Dead,
    75  	},
    76  	{
    77  		state.Dead, state.Dead,
    78  		state.Dead, state.Dead,
    79  	},
    80  }
    81  
    82  type lifeFixture interface {
    83  	id() (coll string, id interface{})
    84  	setup(s *LifeSuite, c *gc.C) state.AgentLiving
    85  }
    86  
    87  type unitLife struct {
    88  	unit *state.Unit
    89  	st   *state.State
    90  }
    91  
    92  func (l *unitLife) id() (coll string, id interface{}) {
    93  	return "units", state.DocID(l.st, l.unit.Name())
    94  }
    95  
    96  func (l *unitLife) setup(s *LifeSuite, c *gc.C) state.AgentLiving {
    97  	unit, err := s.svc.AddUnit()
    98  	c.Assert(err, jc.ErrorIsNil)
    99  	preventUnitDestroyRemove(c, unit)
   100  	l.unit = unit
   101  	return l.unit
   102  }
   103  
   104  type machineLife struct {
   105  	machine *state.Machine
   106  	st      *state.State
   107  }
   108  
   109  func (l *machineLife) id() (coll string, id interface{}) {
   110  	return "machines", state.DocID(l.st, l.machine.Id())
   111  }
   112  
   113  func (l *machineLife) setup(s *LifeSuite, c *gc.C) state.AgentLiving {
   114  	var err error
   115  	l.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)
   116  	c.Assert(err, jc.ErrorIsNil)
   117  	return l.machine
   118  }
   119  
   120  func (s *LifeSuite) prepareFixture(living state.Living, lfix lifeFixture, cached, dbinitial state.Life, c *gc.C) {
   121  	collName, id := lfix.id()
   122  	coll := s.MgoSuite.Session.DB("juju").C(collName)
   123  
   124  	err := coll.UpdateId(id, bson.D{{"$set", bson.D{
   125  		{"life", cached},
   126  	}}})
   127  	c.Assert(err, jc.ErrorIsNil)
   128  	err = living.Refresh()
   129  	c.Assert(err, jc.ErrorIsNil)
   130  
   131  	err = coll.UpdateId(id, bson.D{{"$set", bson.D{
   132  		{"life", dbinitial},
   133  	}}})
   134  	c.Assert(err, jc.ErrorIsNil)
   135  }
   136  
   137  func (s *LifeSuite) TestLifecycleStateChanges(c *gc.C) {
   138  	for i, lfix := range []lifeFixture{&unitLife{st: s.State}, &machineLife{st: s.State}} {
   139  		c.Logf("fixture %d", i)
   140  		for j, v := range stateChanges {
   141  			c.Logf("sequence %d", j)
   142  			living := lfix.setup(s, c)
   143  			s.prepareFixture(living, lfix, v.cached, v.dbinitial, c)
   144  			switch v.desired {
   145  			case state.Dying:
   146  				err := living.Destroy()
   147  				c.Assert(err, jc.ErrorIsNil)
   148  			case state.Dead:
   149  				err := living.EnsureDead()
   150  				c.Assert(err, jc.ErrorIsNil)
   151  			default:
   152  				panic("desired lifecycle can only be dying or dead")
   153  			}
   154  			err := living.Refresh()
   155  			c.Assert(err, jc.ErrorIsNil)
   156  			c.Assert(living.Life(), gc.Equals, v.dbfinal)
   157  			err = living.EnsureDead()
   158  			c.Assert(err, jc.ErrorIsNil)
   159  			err = living.Remove()
   160  			c.Assert(err, jc.ErrorIsNil)
   161  		}
   162  	}
   163  }
   164  
   165  func (s *LifeSuite) TestLifeString(c *gc.C) {
   166  	var tests = []struct {
   167  		life state.Life
   168  		want string
   169  	}{
   170  		{state.Alive, "alive"},
   171  		{state.Dying, "dying"},
   172  		{state.Dead, "dead"},
   173  		{42, "unknown"},
   174  	}
   175  	for _, test := range tests {
   176  		got := test.life.String()
   177  		c.Assert(got, gc.Equals, test.want)
   178  	}
   179  }
   180  
   181  const (
   182  	notAliveErr = ".*: not found or not alive"
   183  	deadErr     = ".*: not found or dead"
   184  	noErr       = ""
   185  )
   186  
   187  type lifer interface {
   188  	EnsureDead() error
   189  	Destroy() error
   190  	Life() state.Life
   191  }
   192  
   193  func runLifeChecks(c *gc.C, obj lifer, expectErr string, checks []func() error) {
   194  	for i, check := range checks {
   195  		c.Logf("check %d when %v", i, obj.Life())
   196  		err := check()
   197  		if expectErr == noErr {
   198  			c.Assert(err, jc.ErrorIsNil)
   199  		} else {
   200  			c.Assert(err, gc.ErrorMatches, expectErr)
   201  		}
   202  	}
   203  }
   204  
   205  // testWhenDying sets obj to Dying and Dead in turn, and asserts
   206  // that the errors from the given checks match aliveErr, dyingErr and deadErr
   207  // in each respective life state.
   208  func testWhenDying(c *gc.C, obj lifer, dyingErr, deadErr string, checks ...func() error) {
   209  	c.Logf("checking life of %v (%T)", obj, obj)
   210  	err := obj.Destroy()
   211  	c.Assert(err, jc.ErrorIsNil)
   212  	runLifeChecks(c, obj, dyingErr, checks)
   213  	err = obj.EnsureDead()
   214  	c.Assert(err, jc.ErrorIsNil)
   215  	runLifeChecks(c, obj, deadErr, checks)
   216  }