kitchen-google 1.5.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile DELETED
@@ -1,14 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- require "chefstyle"
9
- require "rubocop/rake_task"
10
- RuboCop::RakeTask.new(:style) do |task|
11
- task.options << "--display-cop-names"
12
- end
13
-
14
- task default: [:spec, :style]
@@ -1,29 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "kitchen/driver/gce_version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "kitchen-google"
7
- s.version = Kitchen::Driver::GCE_VERSION
8
- s.date = "2016-03-10"
9
- s.summary = "Kitchen::Driver::Gce"
10
- s.description = "A Test-Kitchen driver for Google Compute Engine"
11
- s.authors = ["Andrew Leonard", "Chef Partner Engineering"]
12
- s.email = ["andy@hurricane-ridge.com", "partnereng@chef.io"]
13
- s.files = `git ls-files`.split($/)
14
- s.homepage = "https://github.com/test-kitchen/kitchen-google"
15
- s.license = "Apache 2.0"
16
-
17
- s.add_dependency "gcewinpass", "~> 1.1"
18
- s.add_dependency "google-api-client", "~> 0.19"
19
- s.add_dependency "test-kitchen"
20
-
21
- s.add_development_dependency "bundler"
22
- s.add_development_dependency "pry"
23
- s.add_development_dependency "rake", "~> 10.5"
24
- s.add_development_dependency "rspec"
25
- s.add_development_dependency "rubocop"
26
- s.add_development_dependency "byebug"
27
-
28
- s.required_ruby_version = ">= 2.0"
29
- end
@@ -1,1278 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Author:: Andrew Leonard (<andy@hurricane-ridge.com>)
4
- # Author:: Chef Partner Engineering (<partnereng@chef.io>)
5
- #
6
- # Copyright (C) 2013-2016, Andrew Leonard and Chef Software, Inc.
7
- #
8
- # Licensed under the Apache License, Version 2.0 (the "License");
9
- # you may not use this file except in compliance with the License.
10
- # You may obtain a copy of the License at
11
- #
12
- # http://www.apache.org/licenses/LICENSE-2.0
13
- #
14
- # Unless required by applicable law or agreed to in writing, software
15
- # distributed under the License is distributed on an "AS IS" BASIS,
16
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
- # See the License for the specific language governing permissions and
18
- # limitations under the License.
19
-
20
- require "spec_helper"
21
- require "google/apis/compute_v1"
22
- require "kitchen/driver/gce"
23
- require "kitchen/provisioner/dummy"
24
- require "kitchen/transport/dummy"
25
- require "kitchen/verifier/dummy"
26
-
27
- shared_examples_for "a validity checker" do |config_key, api_method, *args|
28
- it "returns false if the config value is nil" do
29
- expect(driver).to receive(:config).and_return({})
30
- expect(subject).to eq(false)
31
- end
32
-
33
- it "checks the outcome of the API call" do
34
- connection = double("connection")
35
- allow(driver).to receive(:config).and_return({ config_key => "test_value" })
36
- expect(driver).to receive(:connection).and_return(connection)
37
- expect(connection).to receive(api_method).with(*args, "test_value")
38
- expect(driver).to receive(:check_api_call).and_call_original
39
- expect(subject).to eq(true)
40
- end
41
- end
42
-
43
- describe Kitchen::Driver::Gce do
44
- let(:logged_output) { StringIO.new }
45
- let(:logger) { Logger.new(logged_output) }
46
- let(:platform) { Kitchen::Platform.new(name: "fake_platform") }
47
- let(:transport) { Kitchen::Transport::Dummy.new }
48
- let(:driver) { Kitchen::Driver::Gce.new(config) }
49
-
50
- let(:project) { "test_project" }
51
- let(:zone) { "test_zone" }
52
-
53
- let(:config) do
54
- {
55
- project: project,
56
- zone: zone,
57
- image_name: "test_image",
58
- }
59
- end
60
-
61
- let(:instance) do
62
- instance_double(Kitchen::Instance,
63
- logger: logger,
64
- transport: transport,
65
- platform: platform,
66
- to_str: "instance_str"
67
- )
68
- end
69
-
70
- before do
71
- allow(driver).to receive(:instance).and_return(instance)
72
- allow(driver).to receive(:project).and_return("test_project")
73
- allow(driver).to receive(:zone).and_return("test_zone")
74
- allow(driver).to receive(:region).and_return("test_region")
75
- end
76
-
77
- it "driver API version is 2" do
78
- expect(driver.diagnose_plugin[:api_version]).to eq(2)
79
- end
80
-
81
- describe "#name" do
82
- it "has an overridden name" do
83
- expect(driver.name).to eq("Google Compute (GCE)")
84
- end
85
- end
86
-
87
- describe "#create" do
88
- let(:connection) { double("connection") }
89
- let(:operation) { double("operation", name: "test_operation") }
90
- let(:state) { {} }
91
-
92
- before do
93
- allow(driver).to receive(:validate!)
94
- allow(driver).to receive(:connection).and_return(connection)
95
- allow(driver).to receive(:generate_server_name)
96
- allow(driver).to receive(:wait_for_operation)
97
- allow(driver).to receive(:server_instance)
98
- allow(driver).to receive(:create_instance_object)
99
- allow(driver).to receive(:ip_address_for)
100
- allow(driver).to receive(:update_windows_password)
101
- allow(driver).to receive(:wait_for_server)
102
- allow(connection).to receive(:insert_instance).and_return(operation)
103
- end
104
-
105
- it "does not create the server if the hostname is in the state file" do
106
- expect(connection).not_to receive(:insert_instance)
107
- driver.create(server_name: "server_exists")
108
- end
109
-
110
- it "generates a unique server name and sets the state" do
111
- expect(driver).to receive(:generate_server_name).and_return("server_1")
112
- driver.create(state)
113
- expect(state[:server_name]).to eq("server_1")
114
- end
115
-
116
- it "creates the instance via the API and waits for it to complete" do
117
- expect(driver).to receive(:generate_server_name).and_return("server_1")
118
- expect(driver).to receive(:create_instance_object).with("server_1").and_return("create_obj")
119
- expect(connection).to receive(:insert_instance).with("test_project", "test_zone", "create_obj").and_return(operation)
120
- expect(driver).to receive(:wait_for_operation).with(operation)
121
-
122
- driver.create(state)
123
- end
124
-
125
- it "sets the correct data in the state object" do
126
- expect(driver).to receive(:generate_server_name).and_return("server_1")
127
- expect(driver).to receive(:server_instance).with("server_1").and_return("server_obj")
128
- expect(driver).to receive(:ip_address_for).with("server_obj").and_return("1.2.3.4")
129
- driver.create(state)
130
-
131
- expect(state[:server_name]).to eq("server_1")
132
- expect(state[:hostname]).to eq("1.2.3.4")
133
- expect(state[:zone]).to eq("test_zone")
134
- end
135
-
136
- it "updates the windows password" do
137
- expect(driver).to receive(:generate_server_name).and_return("server_1")
138
- expect(driver).to receive(:update_windows_password).with("server_1")
139
- driver.create(state)
140
- end
141
-
142
- it "waits for the server to be ready" do
143
- expect(driver).to receive(:wait_for_server)
144
- driver.create(state)
145
- end
146
-
147
- it "destroys the server if any exceptions are raised" do
148
- expect(connection).to receive(:insert_instance).and_raise(RuntimeError)
149
- expect(driver).to receive(:destroy).with(state)
150
- expect { driver.create(state) }.to raise_error(RuntimeError)
151
- end
152
- end
153
-
154
- describe "#destroy" do
155
- let(:connection) { double("connection") }
156
- let(:state) { { server_name: "server_1", hostname: "test_host", zone: "test_zone" } }
157
-
158
- before do
159
- allow(driver).to receive(:connection).and_return(connection)
160
- allow(driver).to receive(:server_exist?).and_return(true)
161
- allow(driver).to receive(:wait_for_operation)
162
- allow(connection).to receive(:delete_instance)
163
- end
164
-
165
- it "does not attempt to delete the instance if there is no server_name" do
166
- expect(connection).not_to receive(:delete_instance)
167
- driver.destroy({})
168
- end
169
-
170
- it "does not attempt to delete the instance if it does not exist" do
171
- expect(driver).to receive(:server_exist?).with("server_1").and_return(false)
172
- expect(connection).not_to receive(:delete_instance)
173
- driver.destroy(state)
174
- end
175
-
176
- it "deletes the instance via the API and waits for it to complete" do
177
- expect(connection).to receive(:delete_instance).with("test_project", "test_zone", "server_1").and_return("operation")
178
- expect(driver).to receive(:wait_for_operation).with("operation")
179
- driver.destroy(state)
180
- end
181
-
182
- it "deletes the state keys" do
183
- driver.destroy(state)
184
- expect(state.key?(:server_name)).to eq(false)
185
- expect(state.key?(:hostname)).to eq(false)
186
- expect(state.key?(:zone)).to eq(false)
187
- end
188
- end
189
-
190
- describe "#validate!" do
191
- let(:config) do
192
- {
193
- project: "test_project",
194
- zone: "test_zone",
195
- machine_type: "test_machine_type",
196
- disk_type: "test_disk_type",
197
- image_name: "test_image",
198
- network: "test_network",
199
- }
200
- end
201
-
202
- before do
203
- allow(driver).to receive(:valid_project?).and_return(true)
204
- allow(driver).to receive(:valid_zone?).and_return(true)
205
- allow(driver).to receive(:valid_region?).and_return(true)
206
- allow(driver).to receive(:valid_machine_type?).and_return(true)
207
- allow(driver).to receive(:valid_disk_type?).and_return(true)
208
- allow(driver).to receive(:boot_disk_source_image).and_return("image")
209
- allow(driver).to receive(:valid_network?).and_return(true)
210
- allow(driver).to receive(:valid_subnet?).and_return(true)
211
- allow(driver).to receive(:winrm_transport?).and_return(false)
212
- allow(driver).to receive(:config).and_return(config)
213
- end
214
-
215
- it "does not raise an exception when all validations are successful" do
216
- expect { driver.validate! }.not_to raise_error
217
- end
218
-
219
- context "when neither zone nor region are specified" do
220
- let(:config) { { image_name: "test_image" } }
221
- it "raises an exception" do
222
- expect { driver.validate! }.to raise_error(RuntimeError, "Either zone or region must be specified")
223
- end
224
- end
225
-
226
- context "when neither image_family nor image_name are specified" do
227
- let(:config) { { zone: "test_zone" } }
228
- it "raises an exception" do
229
- expect { driver.validate! }.to raise_error(RuntimeError, "Either image family or name must be specified")
230
- end
231
- end
232
-
233
- context "when zone and region are both set" do
234
- let(:config) { { zone: "test_zone", region: "test_region", image_project: "test_project", image_name: "test_image" } }
235
-
236
- it "warns the user that the region will be ignored" do
237
- expect(driver).to receive(:warn).with("Both zone and region specified - region will be ignored.")
238
- driver.validate!
239
- end
240
- end
241
-
242
- context "when image family and name are both set" do
243
- let(:config) { { image_project: "test_project", image_name: "test_image", image_family: "test_image_family", zone: "test_zone" } }
244
-
245
- it "warns the user that the image family will be ignored" do
246
- expect(driver).to receive(:warn).with("Both image family and name specified - image family will be ignored")
247
- driver.validate!
248
- end
249
- end
250
-
251
- context "when region is set to 'any'" do
252
- let(:config) { { region: "any" } }
253
- it "raises an exception" do
254
- expect { driver.validate! }.to raise_error(RuntimeError, "'any' is no longer a valid region")
255
- end
256
- end
257
-
258
- context "when zone is set" do
259
- let(:config) { { zone: "test_zone" } }
260
-
261
- it "raises an exception if the zone is not valid" do
262
- expect(driver).to receive(:valid_zone?).and_return(false)
263
- expect { driver.validate! }.to raise_error(RuntimeError, "Zone test_zone is not a valid zone")
264
- end
265
- end
266
-
267
- context "when region is set" do
268
- let(:config) { { region: "test_region" } }
269
-
270
- it "raises an exception if the region is not valid" do
271
- expect(driver).to receive(:valid_region?).and_return(false)
272
- expect { driver.validate! }.to raise_error(RuntimeError, "Region test_region is not a valid region")
273
- end
274
- end
275
-
276
- context "when subnet is set" do
277
- let(:config) do
278
- {
279
- project: "test_project",
280
- zone: "test_zone",
281
- image_name: "test_image",
282
- machine_type: "test_machine_type",
283
- disk_type: "test_disk_type",
284
- network: "test_network",
285
- subnet: "test_subnet",
286
- }
287
- end
288
-
289
- it "raises an exception if the subnet is invalid" do
290
- expect(driver).to receive(:valid_subnet?).and_return(false)
291
- expect { driver.validate! }.to raise_error(RuntimeError, "Subnet test_subnet is not valid")
292
- end
293
- end
294
-
295
- it "raises an exception if the project is invalid" do
296
- expect(driver).to receive(:valid_project?).and_return(false)
297
- expect { driver.validate! }.to raise_error(RuntimeError, "Project test_project is not a valid project")
298
- end
299
-
300
- it "raises an exception if the machine_type is invalid" do
301
- expect(driver).to receive(:valid_machine_type?).and_return(false)
302
- expect { driver.validate! }.to raise_error(RuntimeError, "Machine type test_machine_type is not valid")
303
- end
304
-
305
- it "raises an exception if the boot disk source image is invalid" do
306
- expect(driver).to receive(:boot_disk_source_image).and_return(nil)
307
- expect { driver.validate! }.to raise_error(RuntimeError, "Disk image test_image is not valid - check your image name and image project")
308
- end
309
-
310
- context "both disk configurations are active" do
311
- let(:config) do
312
- {
313
- project: "test_project",
314
- zone: "test_zone",
315
- image_name: "test_image",
316
- machine_type: "test_machine_type",
317
- autodelete_disk: true,
318
- disks: {
319
- disk0: {
320
- autodelete_disk: true,
321
- },
322
- },
323
- }
324
- end
325
- it "raises an exception if parameters from both disk configurations are present" do
326
- expect { driver.validate! }.to raise_error(RuntimeError, "You cannot use autodelete_disk, disk_size or disk_type with the new disks configuration")
327
- end
328
- end
329
-
330
- it "raises an exception if the network is invalid" do
331
- expect(driver).to receive(:valid_network?).and_return(false)
332
- expect { driver.validate! }.to raise_error(RuntimeError, "Network test_network is not valid")
333
- end
334
-
335
- it "raises an exception if WinRM transport is used but no email is set" do
336
- expect(driver).to receive(:winrm_transport?).and_return(true)
337
- expect { driver.validate! }.to raise_error(RuntimeError, "Email address of GCE user is not set")
338
- end
339
- end
340
-
341
- describe "#connection" do
342
- it "returns a properly configured ComputeService" do
343
- compute_service = double("compute_service")
344
- client_options = double("client_options")
345
-
346
- expect(Google::Apis::ClientOptions).to receive(:new).and_return(client_options)
347
- expect(client_options).to receive(:application_name=).with("GoogleChefTestKitchen")
348
- expect(client_options).to receive(:application_version=).with(Kitchen::Driver::GCE_VERSION)
349
-
350
- expect(Google::Apis::ComputeV1::ComputeService).to receive(:new).and_return(compute_service)
351
- expect(driver).to receive(:authorization).and_return("authorization_object")
352
- expect(compute_service).to receive(:authorization=).with("authorization_object")
353
- expect(compute_service).to receive(:client_options=).with(client_options)
354
-
355
- expect(driver.connection).to eq(compute_service)
356
- end
357
- end
358
-
359
- describe "#authorization" do
360
- it "returns a Google::Auth authorization object" do
361
- auth_object = double("auth_object")
362
- expect(Google::Auth).to receive(:get_application_default).and_return(auth_object)
363
- expect(driver.authorization).to eq(auth_object)
364
- end
365
- end
366
-
367
- describe "#winrm_transport?" do
368
- it "returns true if the transport name is Winrm" do
369
- expect(transport).to receive(:name).and_return("Winrm")
370
- expect(driver.winrm_transport?).to eq(true)
371
- end
372
-
373
- it "returns false if the transport name is not Winrm" do
374
- expect(transport).to receive(:name).and_return("Ssh")
375
- expect(driver.winrm_transport?).to eq(false)
376
- end
377
- end
378
-
379
- describe "#update_windows_password" do
380
- it "does not attempt to reset the password if the transport is not WinRM" do
381
- expect(driver).to receive(:winrm_transport?).and_return(false)
382
- expect(GoogleComputeWindowsPassword).not_to receive(:new)
383
-
384
- driver.update_windows_password("server_1")
385
- end
386
-
387
- it "resets the password and puts it in the state object if the transport is WinRM" do
388
- state = {}
389
- winpass = double("winpass")
390
- winpass_config = {
391
- project: "test_project",
392
- zone: "test_zone",
393
- instance_name: "server_1",
394
- email: "test_email",
395
- username: "test_username",
396
- }
397
-
398
- allow(driver).to receive(:state).and_return(state)
399
- expect(transport).to receive(:config).and_return(username: "test_username")
400
- expect(driver).to receive(:config).and_return(email: "test_email")
401
- expect(driver).to receive(:winrm_transport?).and_return(true)
402
- expect(GoogleComputeWindowsPassword).to receive(:new).with(winpass_config).and_return(winpass)
403
- expect(winpass).to receive(:new_password).and_return("password123")
404
- driver.update_windows_password("server_1")
405
- expect(state[:password]).to eq("password123")
406
- end
407
- end
408
-
409
- describe "#check_api_call" do
410
- it "returns false and logs a debug message if the block raises a ClientError" do
411
- expect(driver).to receive(:debug).with("API error: whoops")
412
- expect(driver.check_api_call { raise Google::Apis::ClientError.new("whoops") }).to eq(false)
413
- end
414
-
415
- it "raises an exception if the block raises something other than a ClientError" do
416
- expect { driver.check_api_call { raise "whoops" } }.to raise_error(RuntimeError)
417
- end
418
-
419
- it "returns true if the block does not raise an exception" do
420
- expect(driver.check_api_call { true }).to eq(true)
421
- end
422
- end
423
-
424
- describe "#valid_machine_type?" do
425
- subject { driver.valid_machine_type? }
426
- it_behaves_like "a validity checker", :machine_type, :get_machine_type, "test_project", "test_zone"
427
- end
428
-
429
- describe "#valid_network?" do
430
- subject { driver.valid_network? }
431
- it_behaves_like "a validity checker", :network, :get_network, "test_project"
432
- end
433
-
434
- describe "#valid_subnet?" do
435
- subject { driver.valid_subnet? }
436
- it_behaves_like "a validity checker", :subnet, :get_subnetwork, "test_project", "test_region"
437
- end
438
-
439
- describe "#valid_zone?" do
440
- subject { driver.valid_zone? }
441
- it_behaves_like "a validity checker", :zone, :get_zone, "test_project"
442
- end
443
-
444
- describe "#valid_region?" do
445
- subject { driver.valid_region? }
446
- it_behaves_like "a validity checker", :region, :get_region, "test_project"
447
- end
448
-
449
- describe "#image_exist?" do
450
- it "checks the outcome of the API call" do
451
- connection = double("connection")
452
- expect(driver).to receive(:connection).and_return(connection)
453
- expect(connection).to receive(:get_image).with("test_project", "test_image")
454
- expect(driver).to receive(:check_api_call).and_call_original
455
- expect(driver.image_exist?).to eq(true)
456
- end
457
- end
458
-
459
- describe "#server_exist?" do
460
- it "checks the outcome of the API call" do
461
- expect(driver).to receive(:server_instance).with("server_1")
462
- expect(driver).to receive(:check_api_call).and_call_original
463
- expect(driver.server_exist?("server_1")).to eq(true)
464
- end
465
- end
466
-
467
- describe "#project" do
468
- it "returns the project from the config" do
469
- allow(driver).to receive(:project).and_call_original
470
- expect(driver).to receive(:config).and_return(project: "my_project")
471
- expect(driver.project).to eq("my_project")
472
- end
473
- end
474
-
475
- describe "#region" do
476
- it "returns the region from the config if specified" do
477
- allow(driver).to receive(:region).and_call_original
478
- allow(driver).to receive(:config).and_return(region: "my_region")
479
- expect(driver.region).to eq("my_region")
480
- end
481
-
482
- it "returns the region for the zone if no region is specified" do
483
- allow(driver).to receive(:region).and_call_original
484
- allow(driver).to receive(:config).and_return({})
485
- expect(driver).to receive(:region_for_zone).and_return("zone_region")
486
- expect(driver.region).to eq("zone_region")
487
- end
488
- end
489
-
490
- describe "#region_for_zone" do
491
- it "returns the region for a given zone" do
492
- connection = double("connection")
493
- zone_obj = double("zone_obj", region: "/path/to/test_region")
494
-
495
- expect(driver).to receive(:connection).and_return(connection)
496
- expect(connection).to receive(:get_zone).with(project, zone).and_return(zone_obj)
497
- expect(driver.region_for_zone).to eq("test_region")
498
- end
499
- end
500
-
501
- describe "#zone" do
502
- before do
503
- allow(driver).to receive(:zone).and_call_original
504
- end
505
-
506
- context "when a zone exists in the state" do
507
- let(:state) { { zone: "state_zone" } }
508
-
509
- it "returns the zone from the state" do
510
- expect(driver).to receive(:state).and_return(state)
511
- expect(driver.zone).to eq("state_zone")
512
- end
513
- end
514
-
515
- context "when a zone does not exist in the state" do
516
- let(:state) { {} }
517
-
518
- before do
519
- allow(driver).to receive(:state).and_return(state)
520
- end
521
-
522
- it "returns the zone from the config if it exists" do
523
- expect(driver).to receive(:config).and_return(zone: "config_zone")
524
- expect(driver.zone).to eq("config_zone")
525
- end
526
-
527
- it "returns the zone from find_zone if it does not exist in the config" do
528
- expect(driver).to receive(:config).and_return({})
529
- expect(driver).to receive(:find_zone).and_return("found_zone")
530
- expect(driver.zone).to eq("found_zone")
531
- end
532
- end
533
- end
534
-
535
- describe "#find_zone" do
536
- let(:zones_in_region) { double("zones_in_region") }
537
-
538
- before do
539
- expect(driver).to receive(:zones_in_region).and_return(zones_in_region)
540
- end
541
-
542
- it "returns a random zone from the list of zones in the region" do
543
- zone = double("zone", name: "random_zone")
544
- expect(zones_in_region).to receive(:sample).and_return(zone)
545
- expect(driver.find_zone).to eq("random_zone")
546
- end
547
-
548
- it "raises an exception if no zones are found" do
549
- expect(zones_in_region).to receive(:sample).and_return(nil)
550
- expect(driver).to receive(:region).and_return("test_region")
551
- expect { driver.find_zone }.to raise_error(RuntimeError, "Unable to find a suitable zone in test_region")
552
- end
553
- end
554
-
555
- describe "#zones_in_region" do
556
- it "returns a correct list of available zones" do
557
- zone1 = double("zone1", status: "UP", region: "a/b/c/test_region")
558
- zone2 = double("zone2", status: "UP", region: "a/b/c/test_region")
559
- zone3 = double("zone3", status: "DOWN", region: "a/b/c/test_region")
560
- zone4 = double("zone4", status: "UP", region: "a/b/c/wrong_region")
561
- zone5 = double("zone5", status: "UP", region: "a/b/c/test_region")
562
- connection = double("connection")
563
- response = double("response", items: [zone1, zone2, zone3, zone4, zone5])
564
-
565
- allow(driver).to receive(:region).and_return("test_region")
566
- expect(driver).to receive(:connection).and_return(connection)
567
- expect(connection).to receive(:list_zones).and_return(response)
568
- expect(driver.zones_in_region).to eq([zone1, zone2, zone5])
569
- end
570
- end
571
-
572
- describe "#server_instance" do
573
- it "returns the instance from the API" do
574
- connection = double("connection")
575
- expect(driver).to receive(:connection).and_return(connection)
576
- expect(connection).to receive(:get_instance).with("test_project", "test_zone", "server_1").and_return("instance")
577
- expect(driver.server_instance("server_1")).to eq("instance")
578
- end
579
- end
580
-
581
- describe "#ip_address_for" do
582
- it "returns the private IP if use_private_ip is true" do
583
- expect(driver).to receive(:config).and_return(use_private_ip: true)
584
- expect(driver).to receive(:private_ip_for).with("server").and_return("1.2.3.4")
585
- expect(driver.ip_address_for("server")).to eq("1.2.3.4")
586
- end
587
-
588
- it "returns the public IP if use_private_ip is false" do
589
- expect(driver).to receive(:config).and_return(use_private_ip: false)
590
- expect(driver).to receive(:public_ip_for).with("server").and_return("4.3.2.1")
591
- expect(driver.ip_address_for("server")).to eq("4.3.2.1")
592
- end
593
- end
594
-
595
- describe "#private_ip_for" do
596
- it "returns the IP address if it exists" do
597
- network_interface = double("network_interface", network_ip: "1.2.3.4")
598
- server = double("server", network_interfaces: [network_interface])
599
-
600
- expect(driver.private_ip_for(server)).to eq("1.2.3.4")
601
- end
602
-
603
- it "raises an exception if the IP cannot be found" do
604
- server = double("server")
605
-
606
- expect(server).to receive(:network_interfaces).and_raise(NoMethodError)
607
- expect { driver.private_ip_for(server) }.to raise_error(RuntimeError, "Unable to determine private IP for instance")
608
- end
609
- end
610
-
611
- describe "#public_ip_for" do
612
- it "returns the IP address if it exists" do
613
- access_config = double("access_config", nat_ip: "4.3.2.1")
614
- network_interface = double("network_interface", access_configs: [access_config])
615
- server = double("server", network_interfaces: [network_interface])
616
-
617
- expect(driver.public_ip_for(server)).to eq("4.3.2.1")
618
- end
619
-
620
- it "raises an exception if the IP cannot be found" do
621
- network_interface = double("network_interface")
622
- server = double("server", network_interfaces: [network_interface])
623
-
624
- expect(network_interface).to receive(:access_configs).and_raise(NoMethodError)
625
- expect { driver.public_ip_for(server) }.to raise_error(RuntimeError, "Unable to determine public IP for instance")
626
- end
627
- end
628
-
629
- describe "#generate_server_name" do
630
- it "generates and returns a server name" do
631
- expect(instance).to receive(:name).and_return("ABC123")
632
- expect(SecureRandom).to receive(:hex).with(3).and_return("abcdef")
633
- expect(driver.generate_server_name).to eq("tk-abc123-abcdef")
634
- end
635
-
636
- it "uses a UUID-based server name if the instance name is too long" do
637
- expect(instance).to receive(:name).twice.and_return("123456789012345678901234567890123456789012345678901235467890")
638
- expect(driver).to receive(:warn)
639
- expect(SecureRandom).to receive(:hex).with(3).and_return("abcdef")
640
- expect(SecureRandom).to receive(:uuid).and_return("lmnop")
641
- expect(driver.generate_server_name).to eq("tk-lmnop")
642
- end
643
-
644
- it "returns a specific name for the server if given in the config" do
645
- config[:inst_name] = "the_instance_name"
646
-
647
- expect(driver.generate_server_name).to eq("the-instance-name")
648
- end
649
- end
650
-
651
- describe "#create_disks_config" do
652
- it "creates the new disk config from the old one" do
653
- config = {
654
- disk_size: 30,
655
- }
656
-
657
- allow(driver).to receive(:config).and_return(config)
658
- allow(driver).to receive(:valid_disk_type?).and_return(true)
659
- driver.create_disks_config
660
- expect(config[:disks][:disk1][:autodelete_disk]).to eq(true)
661
- expect(config[:disks][:disk1][:disk_type]).to eq("pd-standard")
662
- expect(config[:disks][:disk1][:disk_size]).to eq(30)
663
- end
664
-
665
- it "creates the default disk config, with an incomplete new configuration" do
666
- config = {
667
- disks: {
668
- disk1: {
669
- boot: true,
670
- },
671
- },
672
- }
673
-
674
- allow(driver).to receive(:config).and_return(config)
675
- allow(driver).to receive(:valid_disk_type?).and_return(true)
676
- driver.create_disks_config
677
- expect(config[:disks][:disk1][:autodelete_disk]).to eq(true)
678
- expect(config[:disks][:disk1][:disk_type]).to eq("pd-standard")
679
- expect(config[:disks][:disk1][:disk_size]).to eq(10)
680
- end
681
-
682
- it "creates the default disk config with no config" do
683
- config = {}
684
-
685
- allow(driver).to receive(:config).and_return(config)
686
- allow(driver).to receive(:valid_disk_type?).and_return(true)
687
- driver.create_disks_config
688
- expect(config[:disks][:disk1][:autodelete_disk]).to eq(true)
689
- expect(config[:disks][:disk1][:disk_type]).to eq("pd-standard")
690
- expect(config[:disks][:disk1][:disk_size]).to eq(10)
691
- end
692
-
693
- it "raises an error if disk_size is specified for a local ssd" do
694
- config = {
695
- disks: {
696
- disk0: {
697
- boot: true,
698
- },
699
- disk1: {
700
- disk_type: "local-ssd",
701
- disk_size: "15",
702
- },
703
- },
704
- }
705
- allow(driver).to receive(:config).and_return(config)
706
- allow(driver).to receive(:valid_disk_type?).and_return(true)
707
- expect { driver.create_disks_config }.to raise_error("disk1: Cannot use 'disk_size' with local SSD. They always have 375 GB (https://cloud.google.com/compute/docs/disks/#localssds).")
708
- end
709
-
710
- it "raises an error if the boot disk is specified as local ssd" do
711
- config = {
712
- disks: {
713
- disk0: {
714
- boot: true,
715
- disk_type: "local-ssd",
716
- },
717
- },
718
- }
719
- allow(driver).to receive(:config).and_return(config)
720
- allow(driver).to receive(:valid_disk_type?).and_return(true)
721
- expect { driver.create_disks_config }.to raise_error("Boot disk cannot be local SSD.")
722
- end
723
-
724
- it "raises an error if the disk_name is not valid" do
725
- config = {
726
- disks: {
727
- 'my-invalid&disk/name': {
728
- boot: true,
729
- },
730
- },
731
- }
732
- allow(driver).to receive(:config).and_return(config)
733
- allow(driver).to receive(:valid_disk_type?).and_return(true)
734
- expect { driver.create_disks_config }.to raise_error("Disk name invalid. Must match (?-mix:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?).")
735
- end
736
- end
737
-
738
- describe "#create_disks" do
739
- it "sets up a boot disk if boot is present and returns it" do
740
-
741
- config = {
742
- disks: {
743
- disk1: {
744
- boot: true,
745
- },
746
- },
747
- }
748
-
749
- connection = double("connection")
750
- image = double("image")
751
- allow(image).to receive(:name).and_return("test_image")
752
- allow(connection).to receive(:get_image_from_family).and_return(image)
753
- allow(connection).to receive(:get_image).and_return(image)
754
- allow(driver).to receive(:config).and_return(config)
755
- allow(driver).to receive(:connection).and_return(connection)
756
- disk = driver.create_disks("server_1")
757
- expect(disk.first.initialize_params.disk_name).to eq("server_1-disk1")
758
- expect(disk.first.initialize_params.source_image).to eq("projects/test_project/global/images/test_image")
759
- expect(disk.first.is_a?(Google::Apis::ComputeV1::AttachedDisk)).to eq(true)
760
- expect(disk.first.boot).to eq(true)
761
- end
762
-
763
- it "sets up an local ssd as scratch disk and returns it" do
764
- config = {
765
- disks: {
766
- disk1: {
767
- disk_type: "local-ssd",
768
- },
769
- },
770
- }
771
-
772
- connection = double("connection")
773
- allow(driver).to receive(:config).and_return(config)
774
- allow(driver).to receive(:connection).and_return(connection)
775
- disk = driver.create_disks("server_1")
776
- expect(disk.first.initialize_params.disk_name).to eq(nil)
777
- expect(disk.first.initialize_params.source_image).to eq(nil)
778
- expect(disk.first.initialize_params.disk_size_gb).to eq(nil)
779
- expect(disk.first.initialize_params.disk_type).to eq("zones/test_zone/diskTypes/local-ssd")
780
- expect(disk.first.type).to eq("SCRATCH")
781
- expect(disk.first.is_a?(Google::Apis::ComputeV1::AttachedDisk)).to eq(true)
782
- end
783
-
784
- it "sets up an attached disk if boot is not present and returns it" do
785
- config = {
786
- disks: {
787
- disk1: {
788
- autodelete_disk: false,
789
- },
790
- },
791
- }
792
- connection = double("connection")
793
- item = double("item")
794
- allow(driver).to receive(:connection).and_return(connection)
795
- allow(driver).to receive(:wait_for_operation).and_return(true)
796
- allow(item).to receive(:status).and_return("READY")
797
- allow(connection).to receive(:insert_disk).and_return("DONE")
798
- allow(connection).to receive(:get_disk).with(project, zone, "server_1-disk1").and_return(item)
799
- allow(driver).to receive(:config).and_return(config)
800
- disk = driver.create_disks("server_1")
801
- expect(disk.first.is_a?(Google::Apis::ComputeV1::AttachedDisk)).to eq(true)
802
- expect(disk.first.source).to eq("projects/#{project}/zones/#{zone}/disks/server_1-disk1")
803
- end
804
-
805
- it "sets up a boot disk and an attached disk if two disks are defined" do
806
- config = {
807
- disks: {
808
- disk1: {
809
- autodelete_disk: false,
810
- },
811
- disk2: {
812
- disk_size: 15,
813
- },
814
- },
815
- }
816
- connection = double("connection")
817
- item = double("item")
818
- allow(driver).to receive(:connection).and_return(connection)
819
- allow(driver).to receive(:wait_for_operation).and_return(true)
820
- allow(item).to receive(:status).and_return("READY")
821
- allow(connection).to receive(:insert_disk).and_return("DONE")
822
- allow(connection).to receive(:get_disk).with(project, zone, "server_1-disk2").and_return(item)
823
- allow(connection).to receive(:get_disk).with(project, zone, "server_1-disk1").and_return(item)
824
- allow(driver).to receive(:config).and_return(config)
825
- disks = driver.create_disks("server_1")
826
- expect(disks.first.is_a?(Google::Apis::ComputeV1::AttachedDisk)).to eq(true)
827
- expect(disks.first.source).to eq("projects/#{project}/zones/#{zone}/disks/server_1-disk1")
828
- expect(disks.first.auto_delete).to eq(false)
829
- expect(disks.last.is_a?(Google::Apis::ComputeV1::AttachedDisk)).to eq(true)
830
- expect(disks.last.auto_delete).to eq(nil)
831
- expect(disks.last.source).to eq("projects/#{project}/zones/#{zone}/disks/server_1-disk2")
832
- end
833
- end
834
-
835
- describe "#disk_type_url_for" do
836
- it "returns a disk URL" do
837
- expect(driver.disk_type_url_for("my_type")).to eq("zones/test_zone/diskTypes/my_type")
838
- end
839
- end
840
-
841
- describe "#image_name" do
842
- before do
843
- allow(driver).to receive(:config).and_return(config)
844
- end
845
-
846
- context "when the user supplies an image name" do
847
- let(:config) { { image_project: "my_image_project", image_name: "my_image" } }
848
-
849
- it "returns the image name supplied" do
850
- expect(driver.image_name).to eq("my_image")
851
- end
852
- end
853
-
854
- context "when the user supplies an image family" do
855
- let(:config) { { image_project: "my_image_project", image_family: "my_image_family" } }
856
-
857
- it "returns the image found in the family" do
858
- expect(driver).to receive(:image_name_for_family).with("my_image_family").and_return("my_image")
859
- expect(driver.image_name).to eq("my_image")
860
- end
861
- end
862
- end
863
-
864
- describe "#image_url" do
865
- it "returns nil if the image does not exist" do
866
- expect(driver).to receive(:image_exist?).and_return(false)
867
- expect(driver.image_url).to eq(nil)
868
- end
869
-
870
- it "returns a properly formatted image URL if the image exists" do
871
- expect(driver).to receive(:image_exist?).and_return(true)
872
- expect(driver.image_url).to eq("projects/test_project/global/images/test_image")
873
- end
874
- end
875
-
876
- describe "#machine_type_url" do
877
- it "returns a machine type URL" do
878
- expect(driver).to receive(:config).and_return(machine_type: "machine_type")
879
- expect(driver.machine_type_url).to eq("zones/test_zone/machineTypes/machine_type")
880
- end
881
- end
882
-
883
- describe "#instance_metadata" do
884
- let(:item1 ) { double("item1") }
885
- let(:item2 ) { double("item2") }
886
- let(:item3 ) { double("item3") }
887
- let(:metadata) { double("metadata") }
888
-
889
- it "returns a properly-configured metadata object" do
890
-
891
- expect(instance).to receive(:name).and_return("instance_name")
892
- expect(driver).to receive(:env_user).and_return("env_user")
893
- expect(Google::Apis::ComputeV1::Metadata).to receive(:new).and_return(metadata)
894
- expect(Google::Apis::ComputeV1::Metadata::Item).to receive(:new).and_return(item1)
895
- expect(Google::Apis::ComputeV1::Metadata::Item).to receive(:new).and_return(item2)
896
- expect(Google::Apis::ComputeV1::Metadata::Item).to receive(:new).and_return(item3)
897
- expect(item1).to receive(:key=).with("created-by")
898
- expect(item1).to receive(:value=).with("test-kitchen")
899
- expect(item2).to receive(:key=).with("test-kitchen-instance")
900
- expect(item2).to receive(:value=).with("instance_name")
901
- expect(item3).to receive(:key=).with("test-kitchen-user")
902
- expect(item3).to receive(:value=).with("env_user")
903
- expect(metadata).to receive(:items=).with([item1, item2, item3])
904
-
905
- expect(driver.instance_metadata).to eq(metadata)
906
- end
907
-
908
- it "accepts custom metadata" do
909
- foo = double("foo")
910
- config[:metadata] = { "foo" => "bar" }
911
-
912
- expect(instance).to receive(:name).and_return("instance_name")
913
- expect(driver).to receive(:env_user).and_return("env_user")
914
-
915
- expect(Google::Apis::ComputeV1::Metadata).to receive(:new).and_return(metadata)
916
- expect(Google::Apis::ComputeV1::Metadata::Item).to receive(:new).and_return(foo)
917
- expect(Google::Apis::ComputeV1::Metadata::Item).to receive(:new).and_return(item1)
918
- expect(Google::Apis::ComputeV1::Metadata::Item).to receive(:new).and_return(item2)
919
- expect(Google::Apis::ComputeV1::Metadata::Item).to receive(:new).and_return(item3)
920
- expect(item1).to receive(:key=).with("created-by")
921
- expect(item1).to receive(:value=).with("test-kitchen")
922
- expect(item2).to receive(:key=).with("test-kitchen-instance")
923
- expect(item2).to receive(:value=).with("instance_name")
924
- expect(item3).to receive(:key=).with("test-kitchen-user")
925
- expect(item3).to receive(:value=).with("env_user")
926
- expect(foo).to receive(:key=).with("foo")
927
- expect(foo).to receive(:value=).with("bar")
928
-
929
- expect(metadata).to receive(:items=).with([foo, item1, item2, item3])
930
-
931
- expect(driver.instance_metadata).to eq(metadata)
932
- end
933
- end
934
-
935
- describe "#env_user" do
936
- it "returns the current user from the environment" do
937
- expect(ENV).to receive(:[]).with("USER").and_return("test_user")
938
- expect(driver.env_user).to eq("test_user")
939
- end
940
-
941
- it "returns 'unknown' if there is no USER present" do
942
- expect(ENV).to receive(:[]).with("USER").and_return(nil)
943
- expect(driver.env_user).to eq("unknown")
944
- end
945
- end
946
-
947
- describe "#instance_network_interfaces" do
948
- let(:interface) { double("interface") }
949
-
950
- before do
951
- allow(Google::Apis::ComputeV1::NetworkInterface).to receive(:new).and_return(interface)
952
- allow(driver).to receive(:network_url)
953
- allow(driver).to receive(:subnet_url)
954
- allow(driver).to receive(:interface_access_configs)
955
- allow(interface).to receive(:network=)
956
- allow(interface).to receive(:subnetwork=)
957
- allow(interface).to receive(:access_configs=)
958
- end
959
-
960
- it "creates a network interface object and returns it" do
961
- expect(Google::Apis::ComputeV1::NetworkInterface).to receive(:new).and_return(interface)
962
- expect(driver.instance_network_interfaces).to eq([interface])
963
- end
964
-
965
- it "sets the network" do
966
- expect(driver).to receive(:network_url).and_return("network_url")
967
- expect(interface).to receive(:network=).with("network_url")
968
- driver.instance_network_interfaces
969
- end
970
-
971
- it "sets the access configs" do
972
- expect(driver).to receive(:interface_access_configs).and_return("access_configs")
973
- expect(interface).to receive(:access_configs=).with("access_configs")
974
- driver.instance_network_interfaces
975
- end
976
-
977
- it "does not set a subnetwork by default" do
978
- allow(driver).to receive(:subnet_url).and_return(nil)
979
- expect(interface).not_to receive(:subnetwork=)
980
- driver.instance_network_interfaces
981
- end
982
-
983
- it "sets a subnetwork if one was specified" do
984
- allow(driver).to receive(:subnet_url).and_return("subnet_url")
985
- expect(interface).to receive(:subnetwork=).with("subnet_url")
986
- driver.instance_network_interfaces
987
- end
988
- end
989
-
990
- describe "#network_url" do
991
- context "when the user does not provide network_project" do
992
- it "returns a network URL" do
993
- allow(driver).to receive(:config).and_return(network: "test_network")
994
- expect(driver.network_url).to eq("projects/test_project/global/networks/test_network")
995
- end
996
- end
997
-
998
- context "when the user provides network_project" do
999
- it "returns a network URL" do
1000
- allow(driver).to receive(:config).and_return(network: "test_network", network_project: "test_xpn_project")
1001
- expect(driver.network_url).to eq("projects/test_xpn_project/global/networks/test_network")
1002
- end
1003
- end
1004
- end
1005
-
1006
- describe "#subnet_url_for" do
1007
- it "returns nil if no subnet is specified" do
1008
- expect(driver).to receive(:config).and_return({})
1009
- expect(driver.subnet_url).to eq(nil)
1010
- end
1011
-
1012
- context "when the user does not provide subnet_project" do
1013
- it "returns a properly-formatted subnet URL" do
1014
- allow(driver).to receive(:config).and_return(subnet: "test_subnet")
1015
- expect(driver).to receive(:region).and_return("test_region")
1016
- expect(driver.subnet_url).to eq("projects/test_project/regions/test_region/subnetworks/test_subnet")
1017
- end
1018
- end
1019
-
1020
- context "when the user provides subnet_project" do
1021
- it "returns a properly-formatted subnet URL" do
1022
- allow(driver).to receive(:config).and_return(subnet_project: "test_xpn_project", subnet: "test_subnet")
1023
- expect(driver).to receive(:region).and_return("test_region")
1024
- expect(driver.subnet_url).to eq("projects/test_xpn_project/regions/test_region/subnetworks/test_subnet")
1025
- end
1026
- end
1027
- end
1028
-
1029
- describe "#interface_access_configs" do
1030
- it "returns a properly-configured access config object" do
1031
- access_config = double("access_config")
1032
-
1033
- expect(driver).to receive(:config).and_return({})
1034
- expect(Google::Apis::ComputeV1::AccessConfig).to receive(:new).and_return(access_config)
1035
- expect(access_config).to receive(:name=).with("External NAT")
1036
- expect(access_config).to receive(:type=).with("ONE_TO_ONE_NAT")
1037
-
1038
- expect(driver.interface_access_configs).to eq([access_config])
1039
- end
1040
-
1041
- it "returns an empty array if use_private_ip is true" do
1042
- expect(driver).to receive(:config).and_return(use_private_ip: true)
1043
- expect(driver.interface_access_configs).to eq([])
1044
- end
1045
- end
1046
-
1047
- describe "#instance_scheduling" do
1048
- it "returns a properly-configured scheduling object" do
1049
- scheduling = double("scheduling")
1050
-
1051
- expect(driver).to receive(:auto_restart?).and_return("restart")
1052
- expect(driver).to receive(:preemptible?).and_return("preempt")
1053
- expect(driver).to receive(:migrate_setting).and_return("host_maintenance")
1054
- expect(Google::Apis::ComputeV1::Scheduling).to receive(:new).and_return(scheduling)
1055
- expect(scheduling).to receive(:automatic_restart=).with("restart")
1056
- expect(scheduling).to receive(:preemptible=).with("preempt")
1057
- expect(scheduling).to receive(:on_host_maintenance=).with("host_maintenance")
1058
- expect(driver.instance_scheduling).to eq(scheduling)
1059
- end
1060
- end
1061
-
1062
- describe "#preemptible?" do
1063
- it "returns the preemptible setting from the config" do
1064
- expect(driver).to receive(:config).and_return(preemptible: "test_preempt")
1065
- expect(driver.preemptible?).to eq("test_preempt")
1066
- end
1067
- end
1068
-
1069
- describe "#auto_migrate?" do
1070
- it "returns false if the instance is preemptible" do
1071
- expect(driver).to receive(:preemptible?).and_return(true)
1072
- expect(driver.auto_migrate?).to eq(false)
1073
- end
1074
-
1075
- it "returns the setting from the config if preemptible is false" do
1076
- expect(driver).to receive(:config).and_return(auto_migrate: "test_migrate")
1077
- expect(driver).to receive(:preemptible?).and_return(false)
1078
- expect(driver.auto_migrate?).to eq("test_migrate")
1079
- end
1080
- end
1081
-
1082
- describe "#auto_restart?" do
1083
- it "returns false if the instance is preemptible" do
1084
- expect(driver).to receive(:preemptible?).and_return(true)
1085
- expect(driver.auto_restart?).to eq(false)
1086
- end
1087
-
1088
- it "returns the setting from the config if preemptible is false" do
1089
- expect(driver).to receive(:config).and_return(auto_restart: "test_restart")
1090
- expect(driver).to receive(:preemptible?).and_return(false)
1091
- expect(driver.auto_restart?).to eq("test_restart")
1092
- end
1093
- end
1094
-
1095
- describe "#migrate_setting" do
1096
- it "returns MIGRATE if auto_migrate is true" do
1097
- expect(driver).to receive(:auto_migrate?).and_return(true)
1098
- expect(driver.migrate_setting).to eq("MIGRATE")
1099
- end
1100
-
1101
- it "returns TERMINATE if auto_migrate is false" do
1102
- expect(driver).to receive(:auto_migrate?).and_return(false)
1103
- expect(driver.migrate_setting).to eq("TERMINATE")
1104
- end
1105
- end
1106
-
1107
- describe "#instance_service_accounts" do
1108
- it "returns nil if service_account_scopes is nil" do
1109
- allow(driver).to receive(:config).and_return({})
1110
- expect(driver.instance_service_accounts).to eq(nil)
1111
- end
1112
-
1113
- it "returns nil if service_account_scopes is empty" do
1114
- allow(driver).to receive(:config).and_return(service_account_scopes: [])
1115
- expect(driver.instance_service_accounts).to eq(nil)
1116
- end
1117
-
1118
- it "returns an array containing a properly-formatted service account" do
1119
- service_account = double("service_account")
1120
-
1121
- allow(driver).to receive(:config).and_return(service_account_name: "account_name", service_account_scopes: %w{scope1 scope2})
1122
- expect(Google::Apis::ComputeV1::ServiceAccount).to receive(:new).and_return(service_account)
1123
- expect(service_account).to receive(:email=).with("account_name")
1124
- expect(driver).to receive(:service_account_scope_url).with("scope1").and_return("https://www.googleapis.com/auth/scope1")
1125
- expect(driver).to receive(:service_account_scope_url).with("scope2").and_return("https://www.googleapis.com/auth/scope2")
1126
- expect(service_account).to receive(:scopes=).with([
1127
- "https://www.googleapis.com/auth/scope1",
1128
- "https://www.googleapis.com/auth/scope2",
1129
- ])
1130
-
1131
- expect(driver.instance_service_accounts).to eq([service_account])
1132
- end
1133
- end
1134
-
1135
- describe "#service_account_scope_url" do
1136
- it "returns the passed-in scope if it already looks like a scope URL" do
1137
- scope = "https://www.googleapis.com/auth/fake_scope"
1138
- expect(driver.service_account_scope_url(scope)).to eq(scope)
1139
- end
1140
-
1141
- it "returns a properly-formatted scope URL if a short-name or alias is provided" do
1142
- expect(driver).to receive(:translate_scope_alias).with("scope_alias").and_return("real_scope")
1143
- expect(driver.service_account_scope_url("scope_alias")).to eq("https://www.googleapis.com/auth/real_scope")
1144
- end
1145
- end
1146
-
1147
- describe "#translate_scope_alias" do
1148
- it "returns a scope for a given alias" do
1149
- expect(driver.translate_scope_alias("storage-rw")).to eq("devstorage.read_write")
1150
- end
1151
-
1152
- it "returns the passed-in scope alias if nothing matches in the alias map" do
1153
- expect(driver.translate_scope_alias("fake_scope")).to eq("fake_scope")
1154
- end
1155
- end
1156
-
1157
- describe "#instance_tags" do
1158
- it "returns a properly-formatted tags object" do
1159
- tags_obj = double("tags_obj")
1160
-
1161
- expect(driver).to receive(:config).and_return(tags: "test_tags")
1162
- expect(Google::Apis::ComputeV1::Tags).to receive(:new).and_return(tags_obj)
1163
- expect(tags_obj).to receive(:items=).with("test_tags")
1164
-
1165
- expect(driver.instance_tags).to eq(tags_obj)
1166
- end
1167
- end
1168
-
1169
- describe "#wait_time" do
1170
- it "returns the configured wait time" do
1171
- expect(driver).to receive(:config).and_return(wait_time: 123)
1172
- expect(driver.wait_time).to eq(123)
1173
- end
1174
- end
1175
-
1176
- describe "#refresh_rate" do
1177
- it "returns the configured refresh rate" do
1178
- expect(driver).to receive(:config).and_return(refresh_rate: 321)
1179
- expect(driver.refresh_rate).to eq(321)
1180
- end
1181
- end
1182
-
1183
- describe "#wait_for_status" do
1184
- let(:item) { double("item") }
1185
-
1186
- before do
1187
- allow(driver).to receive(:wait_time).and_return(600)
1188
- allow(driver).to receive(:refresh_rate).and_return(2)
1189
-
1190
- # don"t actually sleep
1191
- allow(driver).to receive(:sleep)
1192
- end
1193
-
1194
- context "when the items completes normally, 3 loops" do
1195
- it "only refreshes the item 3 times" do
1196
- allow(item).to receive(:status).exactly(3).times.and_return("PENDING", "RUNNING", "DONE")
1197
-
1198
- driver.wait_for_status("DONE") { item }
1199
- end
1200
- end
1201
-
1202
- context "when the item is completed on the first loop" do
1203
- it "only refreshes the item 1 time" do
1204
- allow(item).to receive(:status).once.and_return("DONE")
1205
-
1206
- driver.wait_for_status("DONE") { item }
1207
- end
1208
- end
1209
-
1210
- context "when the timeout is exceeded" do
1211
- it "prints a warning and exits" do
1212
- allow(Timeout).to receive(:timeout).and_raise(Timeout::Error)
1213
- expect(driver).to receive(:error)
1214
- .with("Request did not complete in 600 seconds. Check the Google Cloud Console for more info.")
1215
- expect { driver.wait_for_status("DONE") { item } }.to raise_error(RuntimeError)
1216
- end
1217
- end
1218
-
1219
- context "when a non-timeout exception is raised" do
1220
- it "raises the original exception" do
1221
- allow(item).to receive(:status).and_raise(NoMethodError)
1222
- expect { driver.wait_for_status("DONE") { item } }.to raise_error(NoMethodError)
1223
- end
1224
- end
1225
- end
1226
-
1227
- describe "#wait_for_operation" do
1228
- let(:operation) { double("operation", name: "operation-123") }
1229
-
1230
- it "raises a properly-formatted exception when errors exist" do
1231
- error1 = double("error1", code: "ERROR1", message: "error 1")
1232
- error2 = double("error2", code: "ERROR2", message: "error 2")
1233
- expect(driver).to receive(:wait_for_status).with("DONE")
1234
- expect(driver).to receive(:operation_errors).with("operation-123").and_return([error1, error2])
1235
- expect(driver).to receive(:error).with("ERROR1: error 1")
1236
- expect(driver).to receive(:error).with("ERROR2: error 2")
1237
-
1238
- expect { driver.wait_for_operation(operation) }.to raise_error(RuntimeError, "Operation operation-123 failed.")
1239
- end
1240
-
1241
- it "does not raise an exception if no errors are encountered" do
1242
- expect(driver).to receive(:wait_for_status).with("DONE")
1243
- expect(driver).to receive(:operation_errors).with("operation-123").and_return([])
1244
- expect(driver).not_to receive(:error)
1245
-
1246
- expect { driver.wait_for_operation(operation) }.not_to raise_error
1247
- end
1248
- end
1249
-
1250
- describe "#zone_operation" do
1251
- it "fetches the operation from the API and returns it" do
1252
- connection = double("connection")
1253
- expect(driver).to receive(:connection).and_return(connection)
1254
- expect(connection).to receive(:get_zone_operation).with(project, zone, "operation-123").and_return("operation")
1255
- expect(driver.zone_operation("operation-123")).to eq("operation")
1256
- end
1257
- end
1258
-
1259
- describe "#operation_errors" do
1260
- let(:operation) { double("operation") }
1261
- let(:error_obj) { double("error_obj") }
1262
-
1263
- before do
1264
- expect(driver).to receive(:zone_operation).with("operation-123").and_return(operation)
1265
- end
1266
-
1267
- it "returns an empty array if there are no errors" do
1268
- expect(operation).to receive(:error).and_return(nil)
1269
- expect(driver.operation_errors("operation-123")).to eq([])
1270
- end
1271
-
1272
- it "returns the errors from the operation if they exist" do
1273
- expect(operation).to receive(:error).twice.and_return(error_obj)
1274
- expect(error_obj).to receive(:errors).and_return("some errors")
1275
- expect(driver.operation_errors("operation-123")).to eq("some errors")
1276
- end
1277
- end
1278
- end