github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/provider/common/availabilityzones_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common_test 5 6 import ( 7 "fmt" 8 9 jc "github.com/juju/testing/checkers" 10 gc "launchpad.net/gocheck" 11 12 "github.com/juju/juju/environs" 13 "github.com/juju/juju/instance" 14 "github.com/juju/juju/provider/common" 15 coretesting "github.com/juju/juju/testing" 16 ) 17 18 type AvailabilityZoneSuite struct { 19 coretesting.FakeJujuHomeSuite 20 env mockZonedEnviron 21 } 22 23 var _ = gc.Suite(&AvailabilityZoneSuite{}) 24 25 func (s *AvailabilityZoneSuite) SetUpSuite(c *gc.C) { 26 s.FakeJujuHomeSuite.SetUpSuite(c) 27 28 allInstances := make([]instance.Instance, 3) 29 for i := range allInstances { 30 allInstances[i] = &mockInstance{id: fmt.Sprintf("inst%d", i)} 31 } 32 s.env.allInstances = func() ([]instance.Instance, error) { 33 return allInstances, nil 34 } 35 36 availabilityZones := make([]common.AvailabilityZone, 3) 37 for i := range availabilityZones { 38 availabilityZones[i] = &mockAvailabilityZone{ 39 name: fmt.Sprintf("az%d", i), 40 available: i > 0, 41 } 42 } 43 s.env.availabilityZones = func() ([]common.AvailabilityZone, error) { 44 return availabilityZones, nil 45 } 46 } 47 48 func (s *AvailabilityZoneSuite) TestBestAvailabilityZoneAllocationsAllInstances(c *gc.C) { 49 var called int 50 s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) { 51 c.Assert(ids, gc.DeepEquals, []instance.Id{"inst0", "inst1", "inst2"}) 52 called++ 53 return []string{"az0", "az1", "az2"}, nil 54 }) 55 best, err := common.BestAvailabilityZoneAllocations(&s.env, nil) 56 c.Assert(called, gc.Equals, 1) 57 c.Assert(err, gc.IsNil) 58 // az0 is unavailable, so az1 and az2 come out as equal best. 59 c.Assert(best, gc.DeepEquals, map[string][]instance.Id{ 60 "az1": []instance.Id{"inst1"}, 61 "az2": []instance.Id{"inst2"}, 62 }) 63 } 64 65 func (s *AvailabilityZoneSuite) TestBestAvailabilityZoneAllocationsAllInstancesErrors(c *gc.C) { 66 resultErr := fmt.Errorf("oh noes") 67 s.PatchValue(&s.env.allInstances, func() ([]instance.Instance, error) { 68 return nil, resultErr 69 }) 70 best, err := common.BestAvailabilityZoneAllocations(&s.env, nil) 71 c.Assert(err, gc.Equals, resultErr) 72 c.Assert(best, gc.HasLen, 0) 73 } 74 75 func (s *AvailabilityZoneSuite) TestBestAvailabilityZoneAllocationsPartialInstances(c *gc.C) { 76 var called int 77 s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) { 78 c.Assert(ids, gc.DeepEquals, []instance.Id{"nichts", "inst1", "null", "inst2"}) 79 called++ 80 return []string{"", "az1", "", "az1"}, environs.ErrPartialInstances 81 }) 82 best, err := common.BestAvailabilityZoneAllocations(&s.env, []instance.Id{"nichts", "inst1", "null", "inst2"}) 83 c.Assert(called, gc.Equals, 1) 84 c.Assert(err, gc.IsNil) 85 // All known instances are in az1 and az0 is unavailable, so az2 is the best. 86 c.Assert(best, gc.DeepEquals, map[string][]instance.Id{"az2": nil}) 87 } 88 89 func (s *AvailabilityZoneSuite) TestBestAvailabilityZoneAllocationsInstanceAvailabilityZonesErrors(c *gc.C) { 90 var returnErr error 91 var called int 92 s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) { 93 called++ 94 return nil, returnErr 95 }) 96 errors := []error{environs.ErrNoInstances, fmt.Errorf("whatever")} 97 for i, err := range errors { 98 returnErr = err 99 best, err := common.BestAvailabilityZoneAllocations(&s.env, nil) 100 c.Assert(called, gc.Equals, i+1) 101 c.Assert(err, gc.Equals, returnErr) 102 c.Assert(best, gc.HasLen, 0) 103 } 104 } 105 106 func (s *AvailabilityZoneSuite) TestBestAvailabilityZoneAllocationsNoZones(c *gc.C) { 107 var calls []string 108 s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) { 109 c.Assert(ids, gc.DeepEquals, []instance.Id{"inst0", "inst1", "inst2"}) 110 calls = append(calls, "InstanceAvailabilityZoneNames") 111 return []string{"", "", ""}, nil 112 }) 113 s.PatchValue(&s.env.availabilityZones, func() ([]common.AvailabilityZone, error) { 114 calls = append(calls, "AvailabilityZones") 115 return []common.AvailabilityZone{}, nil 116 }) 117 best, err := common.BestAvailabilityZoneAllocations(&s.env, nil) 118 c.Assert(calls, gc.DeepEquals, []string{"InstanceAvailabilityZoneNames", "AvailabilityZones"}) 119 c.Assert(err, gc.IsNil) 120 c.Assert(best, gc.HasLen, 0) 121 } 122 123 func (s *AvailabilityZoneSuite) TestBestAvailabilityZoneAllocationsErrors(c *gc.C) { 124 var calls []string 125 s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) { 126 c.Assert(ids, gc.DeepEquals, []instance.Id{"inst0", "inst1", "inst2"}) 127 calls = append(calls, "InstanceAvailabilityZoneNames") 128 return []string{"", "", ""}, nil 129 }) 130 resultErr := fmt.Errorf("u can haz no az") 131 s.PatchValue(&s.env.availabilityZones, func() ([]common.AvailabilityZone, error) { 132 calls = append(calls, "AvailabilityZones") 133 return nil, resultErr 134 }) 135 best, err := common.BestAvailabilityZoneAllocations(&s.env, nil) 136 c.Assert(calls, gc.DeepEquals, []string{"InstanceAvailabilityZoneNames", "AvailabilityZones"}) 137 c.Assert(err, gc.Equals, resultErr) 138 c.Assert(best, gc.HasLen, 0) 139 } 140 141 func (s *AvailabilityZoneSuite) TestDistributeInstancesGroup(c *gc.C) { 142 expectedGroup := []instance.Id{"0", "1", "2"} 143 var called bool 144 s.PatchValue(common.InternalBestAvailabilityZoneAllocations, func(_ common.ZonedEnviron, group []instance.Id) (map[string][]instance.Id, error) { 145 c.Assert(group, gc.DeepEquals, expectedGroup) 146 called = true 147 return nil, nil 148 }) 149 common.DistributeInstances(&s.env, nil, expectedGroup) 150 c.Assert(called, jc.IsTrue) 151 } 152 153 func (s *AvailabilityZoneSuite) TestDistributeInstancesGroupErrors(c *gc.C) { 154 resultErr := fmt.Errorf("whatever") 155 s.PatchValue(common.InternalBestAvailabilityZoneAllocations, func(_ common.ZonedEnviron, group []instance.Id) (map[string][]instance.Id, error) { 156 return nil, resultErr 157 }) 158 _, err := common.DistributeInstances(&s.env, nil, nil) 159 c.Assert(err, gc.Equals, resultErr) 160 } 161 162 func (s *AvailabilityZoneSuite) TestDistributeInstances(c *gc.C) { 163 var bestAvailabilityZones map[string][]instance.Id 164 s.PatchValue(common.InternalBestAvailabilityZoneAllocations, func(_ common.ZonedEnviron, group []instance.Id) (map[string][]instance.Id, error) { 165 return bestAvailabilityZones, nil 166 }) 167 168 type distributeInstancesTest struct { 169 bestAvailabilityZones map[string][]instance.Id 170 candidates []instance.Id 171 eligible []instance.Id 172 } 173 174 tests := []distributeInstancesTest{{ 175 bestAvailabilityZones: map[string][]instance.Id{ 176 "az0": []instance.Id{"i0"}, 177 "az1": []instance.Id{"i1"}, 178 "az2": []instance.Id{"i2"}, 179 }, 180 candidates: []instance.Id{"i2", "i3", "i4"}, 181 eligible: []instance.Id{"i2"}, 182 }, { 183 bestAvailabilityZones: map[string][]instance.Id{ 184 "az0": []instance.Id{"i0"}, 185 "az1": []instance.Id{"i1"}, 186 "az2": []instance.Id{"i2"}, 187 }, 188 candidates: []instance.Id{"i0", "i1", "i2"}, 189 eligible: []instance.Id{"i0", "i1", "i2"}, 190 }, { 191 bestAvailabilityZones: map[string][]instance.Id{ 192 "az0": []instance.Id{"i0"}, 193 "az1": []instance.Id{"i1"}, 194 "az2": []instance.Id{"i2"}, 195 }, 196 candidates: []instance.Id{"i3", "i4", "i5"}, 197 eligible: []instance.Id{}, 198 }, { 199 bestAvailabilityZones: map[string][]instance.Id{ 200 "az0": []instance.Id{"i0"}, 201 "az1": []instance.Id{"i1"}, 202 "az2": []instance.Id{"i2"}, 203 }, 204 candidates: []instance.Id{}, 205 eligible: []instance.Id{}, 206 }, { 207 bestAvailabilityZones: map[string][]instance.Id{}, 208 candidates: []instance.Id{"i0"}, 209 eligible: []instance.Id{}, 210 }} 211 212 for i, test := range tests { 213 c.Logf("test %d", i) 214 bestAvailabilityZones = test.bestAvailabilityZones 215 eligible, err := common.DistributeInstances(&s.env, test.candidates, nil) 216 c.Assert(err, gc.IsNil) 217 c.Assert(eligible, jc.SameContents, test.eligible) 218 } 219 }