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 }