github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/deployer/deployer_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package deployer_test
     5  
     6  import (
     7  	"runtime"
     8  	"sort"
     9  	"strings"
    10  	stdtesting "testing"
    11  	"time"
    12  
    13  	"github.com/juju/errors"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/api"
    18  	apideployer "github.com/juju/juju/api/deployer"
    19  	jujutesting "github.com/juju/juju/juju/testing"
    20  	"github.com/juju/juju/state"
    21  	coretesting "github.com/juju/juju/testing"
    22  	"github.com/juju/juju/worker"
    23  	"github.com/juju/juju/worker/deployer"
    24  )
    25  
    26  func TestPackage(t *stdtesting.T) {
    27  	//TODO(bogdanteleaga): Fix this on windows
    28  	if runtime.GOOS == "windows" {
    29  		t.Skip("bug 1403084: Currently does not work under windows")
    30  	}
    31  	coretesting.MgoTestPackage(t)
    32  }
    33  
    34  type deployerSuite struct {
    35  	jujutesting.JujuConnSuite
    36  	SimpleToolsFixture
    37  
    38  	machine       *state.Machine
    39  	stateAPI      api.Connection
    40  	deployerState *apideployer.State
    41  }
    42  
    43  var _ = gc.Suite(&deployerSuite{})
    44  
    45  var _ worker.StringsWatchHandler = (*deployer.Deployer)(nil)
    46  
    47  func (s *deployerSuite) SetUpTest(c *gc.C) {
    48  	s.JujuConnSuite.SetUpTest(c)
    49  	s.SimpleToolsFixture.SetUp(c, s.DataDir())
    50  	s.stateAPI, s.machine = s.OpenAPIAsNewMachine(c)
    51  	// Create the deployer facade.
    52  	s.deployerState = s.stateAPI.Deployer()
    53  	c.Assert(s.deployerState, gc.NotNil)
    54  }
    55  
    56  func (s *deployerSuite) TearDownTest(c *gc.C) {
    57  	s.SimpleToolsFixture.TearDown(c)
    58  	s.JujuConnSuite.TearDownTest(c)
    59  }
    60  
    61  func (s *deployerSuite) makeDeployerAndContext(c *gc.C) (worker.Worker, deployer.Context) {
    62  	// Create a deployer acting on behalf of the machine.
    63  	ctx := s.getContextForMachine(c, s.machine.Tag())
    64  	return deployer.NewDeployer(s.deployerState, ctx), ctx
    65  }
    66  
    67  func (s *deployerSuite) TestDeployRecallRemovePrincipals(c *gc.C) {
    68  	// Create a machine, and a couple of units.
    69  	svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
    70  	u0, err := svc.AddUnit()
    71  	c.Assert(err, jc.ErrorIsNil)
    72  	u1, err := svc.AddUnit()
    73  	c.Assert(err, jc.ErrorIsNil)
    74  
    75  	dep, ctx := s.makeDeployerAndContext(c)
    76  	defer stop(c, dep)
    77  
    78  	// Assign one unit, and wait for it to be deployed.
    79  	err = u0.AssignToMachine(s.machine)
    80  	c.Assert(err, jc.ErrorIsNil)
    81  	s.waitFor(c, isDeployed(ctx, u0.Name()))
    82  
    83  	// Assign another unit, and wait for that to be deployed.
    84  	err = u1.AssignToMachine(s.machine)
    85  	c.Assert(err, jc.ErrorIsNil)
    86  	s.waitFor(c, isDeployed(ctx, u0.Name(), u1.Name()))
    87  
    88  	// Cause a unit to become Dying, and check no change.
    89  	err = u1.SetAgentStatus(state.StatusIdle, "", nil)
    90  	c.Assert(err, jc.ErrorIsNil)
    91  	err = u1.Destroy()
    92  	c.Assert(err, jc.ErrorIsNil)
    93  	s.waitFor(c, isDeployed(ctx, u0.Name(), u1.Name()))
    94  
    95  	// Cause a unit to become Dead, and check that it is both recalled and
    96  	// removed from state.
    97  	err = u0.EnsureDead()
    98  	c.Assert(err, jc.ErrorIsNil)
    99  	s.waitFor(c, isRemoved(s.State, u0.Name()))
   100  	s.waitFor(c, isDeployed(ctx, u1.Name()))
   101  
   102  	// Remove the Dying unit from the machine, and check that it is recalled...
   103  	err = u1.UnassignFromMachine()
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	s.waitFor(c, isDeployed(ctx))
   106  
   107  	// ...and that the deployer, no longer bearing any responsibility for the
   108  	// Dying unit, does nothing further to it.
   109  	err = u1.Refresh()
   110  	c.Assert(err, jc.ErrorIsNil)
   111  	c.Assert(u1.Life(), gc.Equals, state.Dying)
   112  }
   113  
   114  func (s *deployerSuite) TestRemoveNonAlivePrincipals(c *gc.C) {
   115  	// Create a service, and a couple of units.
   116  	svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   117  	u0, err := svc.AddUnit()
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	u1, err := svc.AddUnit()
   120  	c.Assert(err, jc.ErrorIsNil)
   121  
   122  	// Assign the units to the machine, and set them to Dying/Dead.
   123  	err = u0.AssignToMachine(s.machine)
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	err = u0.EnsureDead()
   126  	c.Assert(err, jc.ErrorIsNil)
   127  	err = u1.AssignToMachine(s.machine)
   128  	c.Assert(err, jc.ErrorIsNil)
   129  	// note: this is not a sane state; for the unit to have a status it must
   130  	// have been deployed. But it's instructive to check that the right thing
   131  	// would happen if it were possible to have a dying unit in this situation.
   132  	err = u1.SetAgentStatus(state.StatusIdle, "", nil)
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	err = u1.Destroy()
   135  	c.Assert(err, jc.ErrorIsNil)
   136  
   137  	// When the deployer is started, in each case (1) no unit agent is deployed
   138  	// and (2) the non-Alive unit is been removed from state.
   139  	dep, ctx := s.makeDeployerAndContext(c)
   140  	defer stop(c, dep)
   141  	s.waitFor(c, isRemoved(s.State, u0.Name()))
   142  	s.waitFor(c, isRemoved(s.State, u1.Name()))
   143  	s.waitFor(c, isDeployed(ctx))
   144  }
   145  
   146  func (s *deployerSuite) prepareSubordinates(c *gc.C) (*state.Unit, []*state.RelationUnit) {
   147  	svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   148  	u, err := svc.AddUnit()
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	err = u.AssignToMachine(s.machine)
   151  	c.Assert(err, jc.ErrorIsNil)
   152  	rus := []*state.RelationUnit{}
   153  	logging := s.AddTestingCharm(c, "logging")
   154  	for _, name := range []string{"subsvc0", "subsvc1"} {
   155  		s.AddTestingService(c, name, logging)
   156  		eps, err := s.State.InferEndpoints("wordpress", name)
   157  		c.Assert(err, jc.ErrorIsNil)
   158  		rel, err := s.State.AddRelation(eps...)
   159  		c.Assert(err, jc.ErrorIsNil)
   160  		ru, err := rel.Unit(u)
   161  		c.Assert(err, jc.ErrorIsNil)
   162  		rus = append(rus, ru)
   163  	}
   164  	return u, rus
   165  }
   166  
   167  func (s *deployerSuite) TestDeployRecallRemoveSubordinates(c *gc.C) {
   168  	// Create a deployer acting on behalf of the principal.
   169  	u, rus := s.prepareSubordinates(c)
   170  	dep, ctx := s.makeDeployerAndContext(c)
   171  	defer stop(c, dep)
   172  
   173  	// Add a subordinate, and wait for it to be deployed.
   174  	err := rus[0].EnterScope(nil)
   175  	c.Assert(err, jc.ErrorIsNil)
   176  	sub0, err := s.State.Unit("subsvc0/0")
   177  	c.Assert(err, jc.ErrorIsNil)
   178  	// Make sure the principal is deployed first, then the subordinate
   179  	s.waitFor(c, isDeployed(ctx, u.Name(), sub0.Name()))
   180  
   181  	// And another.
   182  	err = rus[1].EnterScope(nil)
   183  	c.Assert(err, jc.ErrorIsNil)
   184  	sub1, err := s.State.Unit("subsvc1/0")
   185  	c.Assert(err, jc.ErrorIsNil)
   186  	s.waitFor(c, isDeployed(ctx, u.Name(), sub0.Name(), sub1.Name()))
   187  
   188  	// Set one to Dying; check nothing happens.
   189  	err = sub1.Destroy()
   190  	c.Assert(err, jc.ErrorIsNil)
   191  	s.State.StartSync()
   192  	c.Assert(isRemoved(s.State, sub1.Name())(c), jc.IsFalse)
   193  	s.waitFor(c, isDeployed(ctx, u.Name(), sub0.Name(), sub1.Name()))
   194  
   195  	// Set the other to Dead; check it's recalled and removed.
   196  	err = sub0.EnsureDead()
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	s.waitFor(c, isDeployed(ctx, u.Name(), sub1.Name()))
   199  	s.waitFor(c, isRemoved(s.State, sub0.Name()))
   200  }
   201  
   202  func (s *deployerSuite) TestNonAliveSubordinates(c *gc.C) {
   203  	// Add two subordinate units and set them to Dead/Dying respectively.
   204  	_, rus := s.prepareSubordinates(c)
   205  	err := rus[0].EnterScope(nil)
   206  	c.Assert(err, jc.ErrorIsNil)
   207  	sub0, err := s.State.Unit("subsvc0/0")
   208  	c.Assert(err, jc.ErrorIsNil)
   209  	err = sub0.EnsureDead()
   210  	c.Assert(err, jc.ErrorIsNil)
   211  	err = rus[1].EnterScope(nil)
   212  	c.Assert(err, jc.ErrorIsNil)
   213  	sub1, err := s.State.Unit("subsvc1/0")
   214  	c.Assert(err, jc.ErrorIsNil)
   215  	err = sub1.Destroy()
   216  	c.Assert(err, jc.ErrorIsNil)
   217  
   218  	// When we start a new deployer, neither unit will be deployed and
   219  	// both will be removed.
   220  	dep, _ := s.makeDeployerAndContext(c)
   221  	defer stop(c, dep)
   222  	s.waitFor(c, isRemoved(s.State, sub0.Name()))
   223  	s.waitFor(c, isRemoved(s.State, sub1.Name()))
   224  }
   225  
   226  func (s *deployerSuite) waitFor(c *gc.C, t func(c *gc.C) bool) {
   227  	s.BackingState.StartSync()
   228  	if t(c) {
   229  		return
   230  	}
   231  	timeout := time.After(coretesting.LongWait)
   232  	for {
   233  		select {
   234  		case <-timeout:
   235  			c.Fatalf("timeout")
   236  		case <-time.After(coretesting.ShortWait):
   237  			if t(c) {
   238  				return
   239  			}
   240  		}
   241  	}
   242  }
   243  
   244  func isDeployed(ctx deployer.Context, expected ...string) func(*gc.C) bool {
   245  	return func(c *gc.C) bool {
   246  		sort.Strings(expected)
   247  		current, err := ctx.DeployedUnits()
   248  		c.Assert(err, jc.ErrorIsNil)
   249  		sort.Strings(current)
   250  		return strings.Join(expected, ":") == strings.Join(current, ":")
   251  	}
   252  }
   253  
   254  func isRemoved(st *state.State, name string) func(*gc.C) bool {
   255  	return func(c *gc.C) bool {
   256  		_, err := st.Unit(name)
   257  		if errors.IsNotFound(err) {
   258  			return true
   259  		}
   260  		c.Assert(err, jc.ErrorIsNil)
   261  		return false
   262  	}
   263  }
   264  
   265  func stop(c *gc.C, w worker.Worker) {
   266  	c.Assert(worker.Stop(w), gc.IsNil)
   267  }