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

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/constraints"
    14  	"github.com/juju/juju/environs/config"
    15  	"github.com/juju/juju/instance"
    16  	"github.com/juju/juju/state"
    17  )
    18  
    19  type InstanceDistributorSuite struct {
    20  	ConnSuite
    21  	distributor mockInstanceDistributor
    22  	wordpress   *state.Service
    23  	machines    []*state.Machine
    24  }
    25  
    26  var _ = gc.Suite(&InstanceDistributorSuite{})
    27  
    28  type mockInstanceDistributor struct {
    29  	candidates        []instance.Id
    30  	distributionGroup []instance.Id
    31  	result            []instance.Id
    32  	err               error
    33  }
    34  
    35  func (p *mockInstanceDistributor) DistributeInstances(candidates, distributionGroup []instance.Id) ([]instance.Id, error) {
    36  	p.candidates = candidates
    37  	p.distributionGroup = distributionGroup
    38  	result := p.result
    39  	if result == nil {
    40  		result = candidates
    41  	}
    42  	return result, p.err
    43  }
    44  
    45  func (s *InstanceDistributorSuite) SetUpTest(c *gc.C) {
    46  	s.ConnSuite.SetUpTest(c)
    47  	s.distributor = mockInstanceDistributor{}
    48  	s.policy.GetInstanceDistributor = func(*config.Config) (state.InstanceDistributor, error) {
    49  		return &s.distributor, nil
    50  	}
    51  	s.wordpress = s.AddTestingServiceWithNetworks(
    52  		c,
    53  		"wordpress",
    54  		s.AddTestingCharm(c, "wordpress"),
    55  		[]string{"net1", "net2"},
    56  	)
    57  	s.wordpress.SetConstraints(constraints.MustParse("networks=net3,^net4,^net5"))
    58  	s.machines = make([]*state.Machine, 3)
    59  	for i := range s.machines {
    60  		var err error
    61  		s.machines[i], err = s.State.AddOneMachine(state.MachineTemplate{
    62  			Series: "quantal",
    63  			Jobs:   []state.MachineJob{state.JobHostUnits},
    64  		})
    65  		c.Assert(err, jc.ErrorIsNil)
    66  	}
    67  }
    68  
    69  func (s *InstanceDistributorSuite) setupScenario(c *gc.C) {
    70  	// Assign a unit so we have a non-empty distribution group, and
    71  	// provision all instances so we have candidates.
    72  	unit, err := s.wordpress.AddUnit()
    73  	c.Assert(err, jc.ErrorIsNil)
    74  	err = unit.AssignToMachine(s.machines[0])
    75  	c.Assert(err, jc.ErrorIsNil)
    76  	for i, m := range s.machines {
    77  		instId := instance.Id(fmt.Sprintf("i-blah-%d", i))
    78  		err = m.SetProvisioned(instId, "fake-nonce", nil)
    79  		c.Assert(err, jc.ErrorIsNil)
    80  	}
    81  }
    82  
    83  func (s *InstanceDistributorSuite) TestDistributeInstances(c *gc.C) {
    84  	s.setupScenario(c)
    85  	unit, err := s.wordpress.AddUnit()
    86  	c.Assert(err, jc.ErrorIsNil)
    87  	_, err = unit.AssignToCleanMachine()
    88  	c.Assert(err, jc.ErrorIsNil)
    89  	c.Assert(s.distributor.candidates, jc.SameContents, []instance.Id{"i-blah-1", "i-blah-2"})
    90  	c.Assert(s.distributor.distributionGroup, jc.SameContents, []instance.Id{"i-blah-0"})
    91  	s.distributor.result = []instance.Id{}
    92  	_, err = unit.AssignToCleanMachine()
    93  	c.Assert(err, gc.ErrorMatches, eligibleMachinesInUse)
    94  }
    95  
    96  func (s *InstanceDistributorSuite) TestDistributeInstancesInvalidInstances(c *gc.C) {
    97  	s.setupScenario(c)
    98  	unit, err := s.wordpress.AddUnit()
    99  	c.Assert(err, jc.ErrorIsNil)
   100  	s.distributor.result = []instance.Id{"notthere"}
   101  	_, err = unit.AssignToCleanMachine()
   102  	c.Assert(err, gc.ErrorMatches, `cannot assign unit "wordpress/1" to clean machine: invalid instance returned: notthere`)
   103  }
   104  
   105  func (s *InstanceDistributorSuite) TestDistributeInstancesNoEmptyMachines(c *gc.C) {
   106  	for i := range s.machines {
   107  		// Assign a unit so we have a non-empty distribution group.
   108  		unit, err := s.wordpress.AddUnit()
   109  		c.Assert(err, jc.ErrorIsNil)
   110  		m, err := unit.AssignToCleanMachine()
   111  		c.Assert(err, jc.ErrorIsNil)
   112  		instId := instance.Id(fmt.Sprintf("i-blah-%d", i))
   113  		err = m.SetProvisioned(instId, "fake-nonce", nil)
   114  		c.Assert(err, jc.ErrorIsNil)
   115  	}
   116  
   117  	// InstanceDistributor is not called if there are no empty instances.
   118  	s.distributor.err = fmt.Errorf("no assignment for you")
   119  	unit, err := s.wordpress.AddUnit()
   120  	c.Assert(err, jc.ErrorIsNil)
   121  	_, err = unit.AssignToCleanMachine()
   122  	c.Assert(err, gc.ErrorMatches, eligibleMachinesInUse)
   123  }
   124  
   125  func (s *InstanceDistributorSuite) TestDistributeInstancesErrors(c *gc.C) {
   126  	s.setupScenario(c)
   127  	unit, err := s.wordpress.AddUnit()
   128  	c.Assert(err, jc.ErrorIsNil)
   129  
   130  	// Ensure that assignment fails when DistributeInstances returns an error.
   131  	s.distributor.err = fmt.Errorf("no assignment for you")
   132  	_, err = unit.AssignToCleanMachine()
   133  	c.Assert(err, gc.ErrorMatches, ".*no assignment for you")
   134  	_, err = unit.AssignToCleanEmptyMachine()
   135  	c.Assert(err, gc.ErrorMatches, ".*no assignment for you")
   136  	// If the policy's InstanceDistributor method fails, that will be returned first.
   137  	s.policy.GetInstanceDistributor = func(*config.Config) (state.InstanceDistributor, error) {
   138  		return nil, fmt.Errorf("incapable of InstanceDistributor")
   139  	}
   140  	_, err = unit.AssignToCleanMachine()
   141  	c.Assert(err, gc.ErrorMatches, ".*incapable of InstanceDistributor")
   142  }
   143  
   144  func (s *InstanceDistributorSuite) TestDistributeInstancesEmptyDistributionGroup(c *gc.C) {
   145  	s.distributor.err = fmt.Errorf("no assignment for you")
   146  
   147  	// InstanceDistributor is not called if the distribution group is empty.
   148  	unit0, err := s.wordpress.AddUnit()
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	_, err = unit0.AssignToCleanMachine()
   151  	c.Assert(err, jc.ErrorIsNil)
   152  
   153  	// Distribution group is still empty, because the machine assigned to has
   154  	// not been provisioned.
   155  	unit1, err := s.wordpress.AddUnit()
   156  	c.Assert(err, jc.ErrorIsNil)
   157  	_, err = unit1.AssignToCleanMachine()
   158  	c.Assert(err, jc.ErrorIsNil)
   159  }
   160  
   161  func (s *InstanceDistributorSuite) TestInstanceDistributorUnimplemented(c *gc.C) {
   162  	s.setupScenario(c)
   163  	var distributorErr error
   164  	s.policy.GetInstanceDistributor = func(*config.Config) (state.InstanceDistributor, error) {
   165  		return nil, distributorErr
   166  	}
   167  	unit, err := s.wordpress.AddUnit()
   168  	c.Assert(err, jc.ErrorIsNil)
   169  	_, err = unit.AssignToCleanMachine()
   170  	c.Assert(err, gc.ErrorMatches, `cannot assign unit "wordpress/1" to clean machine: policy returned nil instance distributor without an error`)
   171  	distributorErr = errors.NotImplementedf("InstanceDistributor")
   172  	_, err = unit.AssignToCleanMachine()
   173  	c.Assert(err, jc.ErrorIsNil)
   174  }
   175  
   176  func (s *InstanceDistributorSuite) TestDistributeInstancesNoPolicy(c *gc.C) {
   177  	s.policy.GetInstanceDistributor = func(*config.Config) (state.InstanceDistributor, error) {
   178  		c.Errorf("should not have been invoked")
   179  		return nil, nil
   180  	}
   181  	state.SetPolicy(s.State, nil)
   182  	unit, err := s.wordpress.AddUnit()
   183  	c.Assert(err, jc.ErrorIsNil)
   184  	_, err = unit.AssignToCleanMachine()
   185  	c.Assert(err, jc.ErrorIsNil)
   186  }