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