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 }