github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "gopkg.in/check.v1" 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.FakeJujuXDGDataHomeSuite 20 env mockZonedEnviron 21 } 22 23 var _ = gc.Suite(&AvailabilityZoneSuite{}) 24 25 func (s *AvailabilityZoneSuite) SetUpSuite(c *gc.C) { 26 s.FakeJujuXDGDataHomeSuite.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) TestAvailabilityZoneAllocationsAllInstances(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 zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil) 56 c.Assert(called, gc.Equals, 1) 57 c.Assert(err, jc.ErrorIsNil) 58 // az0 is unavailable, so az1 and az2 come out as equal best; 59 // az1 comes first due to lexicographical ordering on the name. 60 c.Assert(zoneInstances, gc.DeepEquals, []common.AvailabilityZoneInstances{{ 61 ZoneName: "az1", 62 Instances: []instance.Id{"inst1"}, 63 }, { 64 ZoneName: "az2", 65 Instances: []instance.Id{"inst2"}, 66 }}) 67 } 68 69 func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsAllInstancesErrors(c *gc.C) { 70 resultErr := fmt.Errorf("oh noes") 71 s.PatchValue(&s.env.allInstances, func() ([]instance.Instance, error) { 72 return nil, resultErr 73 }) 74 zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil) 75 c.Assert(err, gc.Equals, resultErr) 76 c.Assert(zoneInstances, gc.HasLen, 0) 77 } 78 79 func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsPartialInstances(c *gc.C) { 80 var called int 81 s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) { 82 c.Assert(ids, gc.DeepEquals, []instance.Id{"nichts", "inst1", "null", "inst2"}) 83 called++ 84 return []string{"", "az1", "", "az1"}, environs.ErrPartialInstances 85 }) 86 zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, []instance.Id{"nichts", "inst1", "null", "inst2"}) 87 c.Assert(called, gc.Equals, 1) 88 c.Assert(err, jc.ErrorIsNil) 89 // az2 has fewer instances, so comes first. 90 c.Assert(zoneInstances, gc.DeepEquals, []common.AvailabilityZoneInstances{{ 91 ZoneName: "az2", 92 }, { 93 ZoneName: "az1", 94 Instances: []instance.Id{"inst1", "inst2"}, 95 }}) 96 } 97 98 func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsInstanceAvailabilityZonesErrors(c *gc.C) { 99 returnErr := fmt.Errorf("whatever") 100 var called int 101 s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) { 102 called++ 103 return nil, returnErr 104 }) 105 zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil) 106 c.Assert(called, gc.Equals, 1) 107 c.Assert(err, gc.Equals, returnErr) 108 c.Assert(zoneInstances, gc.HasLen, 0) 109 } 110 111 func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsInstanceAvailabilityZonesNoInstances(c *gc.C) { 112 var called int 113 s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) { 114 called++ 115 return nil, environs.ErrNoInstances 116 }) 117 zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil) 118 c.Assert(called, gc.Equals, 1) 119 c.Assert(err, jc.ErrorIsNil) 120 c.Assert(zoneInstances, gc.HasLen, 2) 121 } 122 123 func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsNoZones(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 s.PatchValue(&s.env.availabilityZones, func() ([]common.AvailabilityZone, error) { 131 calls = append(calls, "AvailabilityZones") 132 return []common.AvailabilityZone{}, nil 133 }) 134 zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil) 135 c.Assert(calls, gc.DeepEquals, []string{"InstanceAvailabilityZoneNames", "AvailabilityZones"}) 136 c.Assert(err, jc.ErrorIsNil) 137 c.Assert(zoneInstances, gc.HasLen, 0) 138 } 139 140 func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsErrors(c *gc.C) { 141 var calls []string 142 s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) { 143 c.Assert(ids, gc.DeepEquals, []instance.Id{"inst0", "inst1", "inst2"}) 144 calls = append(calls, "InstanceAvailabilityZoneNames") 145 return []string{"", "", ""}, nil 146 }) 147 resultErr := fmt.Errorf("u can haz no az") 148 s.PatchValue(&s.env.availabilityZones, func() ([]common.AvailabilityZone, error) { 149 calls = append(calls, "AvailabilityZones") 150 return nil, resultErr 151 }) 152 zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil) 153 c.Assert(calls, gc.DeepEquals, []string{"InstanceAvailabilityZoneNames", "AvailabilityZones"}) 154 c.Assert(err, gc.Equals, resultErr) 155 c.Assert(zoneInstances, gc.HasLen, 0) 156 } 157 158 func (s *AvailabilityZoneSuite) TestDistributeInstancesGroup(c *gc.C) { 159 expectedGroup := []instance.Id{"0", "1", "2"} 160 var called bool 161 s.PatchValue(common.InternalAvailabilityZoneAllocations, func(_ common.ZonedEnviron, group []instance.Id) ([]common.AvailabilityZoneInstances, error) { 162 c.Assert(group, gc.DeepEquals, expectedGroup) 163 called = true 164 return nil, nil 165 }) 166 common.DistributeInstances(&s.env, nil, expectedGroup) 167 c.Assert(called, jc.IsTrue) 168 } 169 170 func (s *AvailabilityZoneSuite) TestDistributeInstancesGroupErrors(c *gc.C) { 171 resultErr := fmt.Errorf("whatever") 172 s.PatchValue(common.InternalAvailabilityZoneAllocations, func(_ common.ZonedEnviron, group []instance.Id) ([]common.AvailabilityZoneInstances, error) { 173 return nil, resultErr 174 }) 175 _, err := common.DistributeInstances(&s.env, nil, nil) 176 c.Assert(err, gc.Equals, resultErr) 177 } 178 179 func (s *AvailabilityZoneSuite) TestDistributeInstances(c *gc.C) { 180 var zoneInstances []common.AvailabilityZoneInstances 181 s.PatchValue(common.InternalAvailabilityZoneAllocations, func(_ common.ZonedEnviron, group []instance.Id) ([]common.AvailabilityZoneInstances, error) { 182 return zoneInstances, nil 183 }) 184 185 type distributeInstancesTest struct { 186 zoneInstances []common.AvailabilityZoneInstances 187 candidates []instance.Id 188 eligible []instance.Id 189 } 190 191 tests := []distributeInstancesTest{{ 192 zoneInstances: []common.AvailabilityZoneInstances{{ 193 ZoneName: "az0", 194 Instances: []instance.Id{"i0"}, 195 }, { 196 ZoneName: "az1", 197 Instances: []instance.Id{"i1"}, 198 }, { 199 ZoneName: "az2", 200 Instances: []instance.Id{"i2"}, 201 }}, 202 candidates: []instance.Id{"i2", "i3", "i4"}, 203 eligible: []instance.Id{"i2"}, 204 }, { 205 zoneInstances: []common.AvailabilityZoneInstances{{ 206 ZoneName: "az0", 207 Instances: []instance.Id{"i0"}, 208 }, { 209 ZoneName: "az1", 210 Instances: []instance.Id{"i1"}, 211 }, { 212 ZoneName: "az2", 213 Instances: []instance.Id{"i2"}, 214 }}, 215 candidates: []instance.Id{"i0", "i1", "i2"}, 216 eligible: []instance.Id{"i0", "i1", "i2"}, 217 }, { 218 zoneInstances: []common.AvailabilityZoneInstances{{ 219 ZoneName: "az0", 220 Instances: []instance.Id{"i0"}, 221 }, { 222 ZoneName: "az1", 223 Instances: []instance.Id{"i1"}, 224 }, { 225 ZoneName: "az2", 226 Instances: []instance.Id{"i2"}, 227 }}, 228 candidates: []instance.Id{"i3", "i4", "i5"}, 229 eligible: []instance.Id{}, 230 }, { 231 zoneInstances: []common.AvailabilityZoneInstances{{ 232 ZoneName: "az0", 233 Instances: []instance.Id{"i0"}, 234 }, { 235 ZoneName: "az1", 236 Instances: []instance.Id{"i1"}, 237 }, { 238 ZoneName: "az2", 239 Instances: []instance.Id{"i2"}, 240 }}, 241 candidates: []instance.Id{}, 242 eligible: []instance.Id{}, 243 }, { 244 zoneInstances: []common.AvailabilityZoneInstances{}, 245 candidates: []instance.Id{"i0"}, 246 eligible: []instance.Id{}, 247 }} 248 249 for i, test := range tests { 250 c.Logf("test %d", i) 251 zoneInstances = test.zoneInstances 252 eligible, err := common.DistributeInstances(&s.env, test.candidates, nil) 253 c.Assert(err, jc.ErrorIsNil) 254 c.Assert(eligible, jc.SameContents, test.eligible) 255 } 256 }