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