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