github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/discoverspaces/worker_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package discoverspaces_test 5 6 import ( 7 "sync/atomic" 8 "time" 9 10 "github.com/juju/names" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/api" 15 apidiscoverspaces "github.com/juju/juju/api/discoverspaces" 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/environs" 18 "github.com/juju/juju/juju/testing" 19 "github.com/juju/juju/network" 20 "github.com/juju/juju/provider/dummy" 21 "github.com/juju/juju/state" 22 coretesting "github.com/juju/juju/testing" 23 "github.com/juju/juju/worker" 24 "github.com/juju/juju/worker/discoverspaces" 25 "github.com/juju/juju/worker/gate" 26 "github.com/juju/juju/worker/workertest" 27 ) 28 29 type WorkerSuite struct { 30 // TODO(fwereade): we *really* should not be using 31 // JujuConnSuite in new code. 32 testing.JujuConnSuite 33 34 APIConnection api.Connection 35 API *checkingFacade 36 37 numCreateSpaceCalls uint32 38 numAddSubnetsCalls uint32 39 } 40 41 type checkingFacade struct { 42 apidiscoverspaces.API 43 44 createSpacesCallback func() 45 addSubnetsCallback func() 46 } 47 48 func (cf *checkingFacade) CreateSpaces(args params.CreateSpacesParams) (results params.ErrorResults, err error) { 49 if cf.createSpacesCallback != nil { 50 cf.createSpacesCallback() 51 } 52 return cf.API.CreateSpaces(args) 53 } 54 55 func (cf *checkingFacade) AddSubnets(args params.AddSubnetsParams) (params.ErrorResults, error) { 56 if cf.addSubnetsCallback != nil { 57 cf.addSubnetsCallback() 58 } 59 return cf.API.AddSubnets(args) 60 } 61 62 var _ = gc.Suite(&WorkerSuite{}) 63 64 func (s *WorkerSuite) SetUpTest(c *gc.C) { 65 s.JujuConnSuite.SetUpTest(c) 66 67 // Unbreak dummy provider methods. 68 s.AssertConfigParameterUpdated(c, "broken", "") 69 70 s.APIConnection, _ = s.OpenAPIAsNewMachine(c, state.JobManageModel) 71 72 realAPI := s.APIConnection.DiscoverSpaces() 73 s.API = &checkingFacade{ 74 API: *realAPI, 75 createSpacesCallback: func() { 76 atomic.AddUint32(&s.numCreateSpaceCalls, 1) 77 }, 78 addSubnetsCallback: func() { 79 atomic.AddUint32(&s.numAddSubnetsCalls, 1) 80 }, 81 } 82 } 83 84 func (s *WorkerSuite) TearDownTest(c *gc.C) { 85 if s.APIConnection != nil { 86 c.Check(s.APIConnection.Close(), jc.ErrorIsNil) 87 } 88 s.JujuConnSuite.TearDownTest(c) 89 } 90 91 func (s *WorkerSuite) TestSupportsSpaceDiscoveryBroken(c *gc.C) { 92 s.AssertConfigParameterUpdated(c, "broken", "SupportsSpaceDiscovery") 93 94 worker, lock := s.startWorker(c) 95 err := workertest.CheckKilled(c, worker) 96 c.Assert(err, gc.ErrorMatches, "dummy.SupportsSpaceDiscovery is broken") 97 98 select { 99 case <-time.After(coretesting.ShortWait): 100 case <-lock.Unlocked(): 101 c.Fatalf("gate unlocked despite worker failure") 102 } 103 } 104 105 func (s *WorkerSuite) TestSpacesBroken(c *gc.C) { 106 dummy.SetSupportsSpaceDiscovery(true) 107 s.AssertConfigParameterUpdated(c, "broken", "Spaces") 108 109 worker, lock := s.startWorker(c) 110 err := workertest.CheckKilled(c, worker) 111 c.Assert(err, gc.ErrorMatches, "dummy.Spaces is broken") 112 113 select { 114 case <-time.After(coretesting.ShortWait): 115 case <-lock.Unlocked(): 116 c.Fatalf("gate unlocked despite worker failure") 117 } 118 } 119 120 func (s *WorkerSuite) TestWorkerSupportsNetworkingFalse(c *gc.C) { 121 // We set SupportsSpaceDiscovery to true so that spaces *would* be 122 // discovered if networking was supported. So we know that if they're 123 // discovered it must be because networking is not supported. 124 dummy.SetSupportsSpaceDiscovery(true) 125 126 // TODO(fwereade): monkey-patching remote packages is even worse 127 // than monkey-patching local packages, please don't do it. 128 noNetworking := func(environs.Environ) (environs.NetworkingEnviron, bool) { 129 return nil, false 130 } 131 s.PatchValue(&environs.SupportsNetworking, noNetworking) 132 133 s.unlockCheck(c, s.assertDiscoveredNoSpaces) 134 } 135 136 func (s *WorkerSuite) TestWorkerSupportsSpaceDiscoveryFalse(c *gc.C) { 137 s.unlockCheck(c, s.assertDiscoveredNoSpaces) 138 } 139 140 func (s *WorkerSuite) TestWorkerDiscoversSpaces(c *gc.C) { 141 dummy.SetSupportsSpaceDiscovery(true) 142 s.unlockCheck(c, func(*gc.C) { 143 s.assertDiscoveredSpaces(c) 144 s.assertNumCalls(c, 1, 1) 145 }) 146 } 147 148 func (s *WorkerSuite) TestWorkerIdempotent(c *gc.C) { 149 dummy.SetSupportsSpaceDiscovery(true) 150 s.unlockCheck(c, s.assertDiscoveredSpaces) 151 s.unlockCheck(c, func(*gc.C) { 152 s.assertDiscoveredSpaces(c) 153 s.assertNumCalls(c, 2, 2) 154 }) 155 } 156 157 func (s *WorkerSuite) TestWorkerIgnoresExistingSpacesAndSubnets(c *gc.C) { 158 dummy.SetSupportsSpaceDiscovery(true) 159 spaceTag := names.NewSpaceTag("foo") 160 args := params.CreateSpacesParams{ 161 Spaces: []params.CreateSpaceParams{{ 162 Public: false, 163 SpaceTag: spaceTag.String(), 164 ProviderId: "foo", 165 }}} 166 result, err := s.API.CreateSpaces(args) 167 c.Assert(err, jc.ErrorIsNil) 168 c.Assert(result.Results, gc.HasLen, 1) 169 c.Assert(result.Results[0].Error, gc.IsNil) 170 171 subnetArgs := params.AddSubnetsParams{ 172 Subnets: []params.AddSubnetParams{{ 173 SubnetProviderId: "1", 174 SpaceTag: spaceTag.String(), 175 Zones: []string{"zone1"}, 176 }}} 177 subnetResult, err := s.API.AddSubnets(subnetArgs) 178 c.Assert(err, jc.ErrorIsNil) 179 c.Assert(subnetResult.Results, gc.HasLen, 1) 180 c.Assert(subnetResult.Results[0].Error, gc.IsNil) 181 182 s.unlockCheck(c, func(c *gc.C) { 183 spaces, err := s.State.AllSpaces() 184 c.Assert(err, jc.ErrorIsNil) 185 c.Assert(spaces, gc.HasLen, 5) 186 }) 187 } 188 189 func (s *WorkerSuite) startWorker(c *gc.C) (worker.Worker, gate.Lock) { 190 // create fresh environ to see any injected broken-ness 191 config, err := s.State.ModelConfig() 192 c.Assert(err, jc.ErrorIsNil) 193 environ, err := environs.New(config) 194 c.Assert(err, jc.ErrorIsNil) 195 196 lock := gate.NewLock() 197 worker, err := discoverspaces.NewWorker(discoverspaces.Config{ 198 Facade: s.API, 199 Environ: environ, 200 NewName: network.ConvertSpaceName, 201 Unlocker: lock, 202 }) 203 c.Assert(err, jc.ErrorIsNil) 204 return worker, lock 205 } 206 207 func (s *WorkerSuite) unlockCheck(c *gc.C, check func(c *gc.C)) { 208 worker, lock := s.startWorker(c) 209 defer workertest.CleanKill(c, worker) 210 select { 211 case <-time.After(coretesting.LongWait): 212 c.Fatalf("discovery never completed") 213 case <-lock.Unlocked(): 214 check(c) 215 } 216 workertest.CheckAlive(c, worker) 217 } 218 219 func (s *WorkerSuite) assertDiscoveredNoSpaces(c *gc.C) { 220 spaces, err := s.State.AllSpaces() 221 c.Assert(err, jc.ErrorIsNil) 222 c.Check(spaces, gc.HasLen, 0) 223 } 224 225 func (s *WorkerSuite) assertDiscoveredSpaces(c *gc.C) { 226 spaces, err := s.State.AllSpaces() 227 c.Assert(err, jc.ErrorIsNil) 228 c.Assert(spaces, gc.HasLen, 4) 229 expectedSpaces := []network.SpaceInfo{{ 230 Name: "foo", 231 ProviderId: network.Id("0"), 232 Subnets: []network.SubnetInfo{{ 233 ProviderId: network.Id("1"), 234 CIDR: "192.168.1.0/24", 235 AvailabilityZones: []string{"zone1"}, 236 }, { 237 ProviderId: network.Id("2"), 238 CIDR: "192.168.2.0/24", 239 AvailabilityZones: []string{"zone1"}, 240 }}}, { 241 Name: "another-foo-99", 242 ProviderId: network.Id("1"), 243 Subnets: []network.SubnetInfo{{ 244 ProviderId: network.Id("3"), 245 CIDR: "192.168.3.0/24", 246 AvailabilityZones: []string{"zone1"}, 247 }}}, { 248 Name: "foo-2", 249 ProviderId: network.Id("2"), 250 Subnets: []network.SubnetInfo{{ 251 ProviderId: network.Id("4"), 252 CIDR: "192.168.4.0/24", 253 AvailabilityZones: []string{"zone1"}, 254 }}}, { 255 Name: "empty", 256 ProviderId: network.Id("3"), 257 Subnets: []network.SubnetInfo{{ 258 ProviderId: network.Id("5"), 259 CIDR: "192.168.5.0/24", 260 AvailabilityZones: []string{"zone1"}, 261 }}}} 262 expectedSpaceMap := make(map[string]network.SpaceInfo) 263 for _, space := range expectedSpaces { 264 expectedSpaceMap[space.Name] = space 265 } 266 for _, space := range spaces { 267 expected, ok := expectedSpaceMap[space.Name()] 268 if !c.Check(ok, jc.IsTrue) { 269 continue 270 } 271 c.Check(space.ProviderId(), gc.Equals, expected.ProviderId) 272 subnets, err := space.Subnets() 273 if !c.Check(err, jc.ErrorIsNil) { 274 continue 275 } 276 if !c.Check(len(subnets), gc.Equals, len(expected.Subnets)) { 277 continue 278 } 279 for i, subnet := range subnets { 280 expectedSubnet := expected.Subnets[i] 281 c.Check(subnet.ProviderId(), gc.Equals, expectedSubnet.ProviderId) 282 c.Check([]string{subnet.AvailabilityZone()}, jc.DeepEquals, expectedSubnet.AvailabilityZones) 283 c.Check(subnet.CIDR(), gc.Equals, expectedSubnet.CIDR) 284 } 285 } 286 } 287 288 func (s *WorkerSuite) assertNumCalls(c *gc.C, expectedNumCreateSpaceCalls, expectedNumAddSubnetsCalls int) { 289 c.Check(atomic.LoadUint32(&s.numCreateSpaceCalls), gc.Equals, uint32(expectedNumCreateSpaceCalls)) 290 c.Check(atomic.LoadUint32(&s.numAddSubnetsCalls), gc.Equals, uint32(expectedNumAddSubnetsCalls)) 291 }