beaker 3.21.1 → 3.22.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,491 +0,0 @@
1
- require 'spec_helper'
2
- require 'fakefs/spec_helpers'
3
-
4
- # fake the docker-api
5
- module Docker
6
- class Image
7
- end
8
- class Container
9
- end
10
- end
11
-
12
- module Beaker
13
- platforms = [
14
- "ubuntu-14.04-x86_64",
15
- "cumulus-2.2-x86_64",
16
- "fedora-22-x86_64",
17
- "centos-7-x86_64",
18
- "sles-12-x86_64"
19
- ]
20
-
21
- describe Docker do
22
- let(:hosts) { make_hosts }
23
-
24
- let(:logger) do
25
- logger = double('logger')
26
- allow( logger ).to receive(:debug)
27
- allow( logger ).to receive(:info)
28
- allow( logger ).to receive(:warn)
29
- allow( logger ).to receive(:error)
30
- allow( logger ).to receive(:notify)
31
- logger
32
- end
33
-
34
- let(:options) {{
35
- :logger => logger,
36
- :forward_ssh_agent => true,
37
- :provision => true
38
- }}
39
-
40
- let(:image) do
41
- image = double('Docker::Image')
42
- allow( image ).to receive(:id)
43
- allow( image ).to receive(:tag)
44
- allow( image ).to receive(:delete)
45
- image
46
- end
47
-
48
- let(:container) do
49
- container = double('Docker::Container')
50
- allow( container ).to receive(:id)
51
- allow( container ).to receive(:start)
52
- allow( container ).to receive(:info).and_return(
53
- *(0..2).map { |index| { 'Names' => ["/spec-container-#{index}"] } }
54
- )
55
- allow( container ).to receive(:json).and_return({
56
- 'NetworkSettings' => {
57
- 'IPAddress' => '192.0.2.1',
58
- 'Ports' => {
59
- '22/tcp' => [
60
- {
61
- 'HostIp' => '127.0.1.1',
62
- 'HostPort' => 8022,
63
- },
64
- ],
65
- },
66
- },
67
- })
68
- allow( container ).to receive(:kill)
69
- allow( container ).to receive(:delete)
70
- allow( container ).to receive(:exec)
71
- container
72
- end
73
-
74
- let (:docker) { ::Beaker::Docker.new( hosts, options ) }
75
- let(:docker_options) { nil }
76
- let (:version) { {"ApiVersion"=>"1.18", "Arch"=>"amd64", "GitCommit"=>"4749651", "GoVersion"=>"go1.4.2", "KernelVersion"=>"3.16.0-37-generic", "Os"=>"linux", "Version"=>"1.6.0"} }
77
-
78
- before :each do
79
- # Stub out all of the docker-api gem. we should never really call it
80
- # from these tests
81
- allow_any_instance_of( ::Beaker::Docker ).to receive(:require).with('docker')
82
- allow( ::Docker ).to receive(:options).and_return(docker_options)
83
- allow( ::Docker ).to receive(:options=)
84
- allow( ::Docker ).to receive(:logger=)
85
- allow( ::Docker ).to receive(:version).and_return(version)
86
- allow( ::Docker::Image ).to receive(:build).and_return(image)
87
- allow( ::Docker::Container ).to receive(:create).and_return(container)
88
- allow_any_instance_of( ::Docker::Container ).to receive(:start)
89
- end
90
-
91
- describe '#initialize, failure to validate' do
92
- before :each do
93
- require 'excon'
94
- allow( ::Docker ).to receive(:validate_version!).and_raise(Excon::Errors::SocketError.new( StandardError.new('oops') ))
95
- end
96
- it 'should fail when docker not present' do
97
- expect { docker }.to raise_error(RuntimeError, /Docker instance not connectable./)
98
- expect { docker }.to raise_error(RuntimeError, /Check your DOCKER_HOST variable has been set/)
99
- expect { docker }.to raise_error(RuntimeError, /If you are on OSX or Windows, you might not have Docker Machine setup correctly/)
100
- expect { docker }.to raise_error(RuntimeError, /Error was: oops/)
101
- end
102
- end
103
-
104
- describe '#initialize' do
105
- before :each do
106
- allow( ::Docker ).to receive(:validate_version!)
107
- end
108
-
109
- it 'should require the docker gem' do
110
- expect_any_instance_of( ::Beaker::Docker ).to receive(:require).with('docker').once
111
-
112
- docker
113
- end
114
-
115
- it 'should fail when the gem is absent' do
116
- allow_any_instance_of( ::Beaker::Docker ).to receive(:require).with('docker').and_raise(LoadError)
117
- expect { docker }.to raise_error(LoadError)
118
- end
119
-
120
- it 'should set Docker options' do
121
- expect( ::Docker ).to receive(:options=).with({:write_timeout => 300, :read_timeout => 300}).once
122
-
123
- docker
124
- end
125
-
126
- context 'when Docker options are already set' do
127
- let(:docker_options) {{:write_timeout => 600, :foo => :bar}}
128
-
129
- it 'should not override Docker options' do
130
- expect( ::Docker ).to receive(:options=).with({:write_timeout => 600, :read_timeout => 300, :foo => :bar}).once
131
-
132
- docker
133
- end
134
- end
135
-
136
- it 'should check the Docker gem can work with the api' do
137
- expect( ::Docker ).to receive(:validate_version!).once
138
-
139
- docker
140
- end
141
-
142
- it 'should hook the Beaker logger into the Docker one' do
143
- expect( ::Docker ).to receive(:logger=).with(logger)
144
-
145
- docker
146
- end
147
- end
148
-
149
- describe '#provision' do
150
- before :each do
151
- allow( ::Docker ).to receive(:validate_version!)
152
- allow( docker ).to receive(:dockerfile_for)
153
- end
154
-
155
- it 'should call dockerfile_for with all the hosts' do
156
- hosts.each do |host|
157
- expect( docker ).to receive(:dockerfile_for).with(host).and_return('')
158
- end
159
-
160
- docker.provision
161
- end
162
-
163
- it 'should pass the Dockerfile on to Docker::Image.create' do
164
- allow( docker ).to receive(:dockerfile_for).and_return('special testing value')
165
- expect( ::Docker::Image ).to receive(:build).with('special testing value', { :rm => true, :buildargs => '{}' })
166
-
167
- docker.provision
168
- end
169
-
170
- it 'should pass the buildargs from ENV DOCKER_BUILDARGS on to Docker::Image.create' do
171
- allow( docker ).to receive(:dockerfile_for).and_return('special testing value')
172
- ENV['DOCKER_BUILDARGS'] = 'HTTP_PROXY=http://1.1.1.1:3128'
173
- expect( ::Docker::Image ).to receive(:build).with('special testing value', { :rm => true, :buildargs => "{\"HTTP_PROXY\":\"http://1.1.1.1:3128\"}" })
174
-
175
- docker.provision
176
- end
177
-
178
- it 'should create a container based on the Image (identified by image.id)' do
179
- hosts.each do |host|
180
- expect( ::Docker::Container ).to receive(:create).with({
181
- 'Image' => image.id,
182
- 'Hostname' => host.name,
183
- })
184
- end
185
-
186
- docker.provision
187
- end
188
-
189
- it 'should pass the multiple buildargs from ENV DOCKER_BUILDARGS on to Docker::Image.create' do
190
- allow( docker ).to receive(:dockerfile_for).and_return('special testing value')
191
- ENV['DOCKER_BUILDARGS'] = 'HTTP_PROXY=http://1.1.1.1:3128 HTTPS_PROXY=https://1.1.1.1:3129'
192
- expect( ::Docker::Image ).to receive(:build).with('special testing value', { :rm => true, :buildargs => "{\"HTTP_PROXY\":\"http://1.1.1.1:3128\",\"HTTPS_PROXY\":\"https://1.1.1.1:3129\"}" })
193
-
194
- docker.provision
195
- end
196
-
197
- it 'should create a container based on the Image (identified by image.id)' do
198
- hosts.each do |host|
199
- expect( ::Docker::Container ).to receive(:create).with({
200
- 'Image' => image.id,
201
- 'Hostname' => host.name,
202
- })
203
- end
204
-
205
- docker.provision
206
- end
207
-
208
- it 'should create a named container based on the Image (identified by image.id)' do
209
- hosts.each_with_index do |host, index|
210
- container_name = "spec-container-#{index}"
211
- host['docker_container_name'] = container_name
212
-
213
- expect( ::Docker::Container ).to receive(:create).with({
214
- 'Image' => image.id,
215
- 'Hostname' => host.name,
216
- 'name' => container_name,
217
- })
218
- end
219
-
220
- docker.provision
221
- end
222
-
223
-
224
- it 'should create a container with volumes bound' do
225
- hosts.each_with_index do |host, index|
226
- host['mount_folders'] = {
227
- 'mount1' => {
228
- 'host_path' => '/source_folder',
229
- 'container_path' => '/mount_point',
230
- },
231
- 'mount2' => {
232
- 'host_path' => '/another_folder',
233
- 'container_path' => '/another_mount',
234
- 'opts' => 'ro',
235
- },
236
- 'mount3' => {
237
- 'host_path' => '/different_folder',
238
- 'container_path' => '/different_mount',
239
- 'opts' => 'rw',
240
- },
241
- 'mount4' => {
242
- 'host_path' => './',
243
- 'container_path' => '/relative_mount',
244
- },
245
- 'mount5' => {
246
- 'host_path' => 'local_folder',
247
- 'container_path' => '/another_relative_mount',
248
- }
249
- }
250
-
251
- expect( ::Docker::Container ).to receive(:create).with({
252
- 'Image' => image.id,
253
- 'Hostname' => host.name,
254
- 'HostConfig' => {
255
- 'Binds' => [
256
- '/source_folder:/mount_point',
257
- '/another_folder:/another_mount:ro',
258
- '/different_folder:/different_mount:rw',
259
- "#{File.expand_path('./')}:/relative_mount",
260
- "#{File.expand_path('local_folder')}:/another_relative_mount",
261
- ]
262
- }
263
- })
264
- end
265
-
266
- docker.provision
267
- end
268
-
269
- it 'should start the container' do
270
- expect( container ).to receive(:start).with({'PublishAllPorts' => true, 'Privileged' => true})
271
-
272
- docker.provision
273
- end
274
-
275
- context "connecting to ssh" do
276
- before { @docker_host = ENV['DOCKER_HOST'] }
277
- after { ENV['DOCKER_HOST'] = @docker_host }
278
-
279
- it 'should expose port 22 to beaker' do
280
- ENV['DOCKER_HOST'] = nil
281
- docker.provision
282
-
283
- expect( hosts[0]['ip'] ).to be === '127.0.1.1'
284
- expect( hosts[0]['port'] ).to be === 8022
285
- end
286
-
287
- it 'should expose port 22 to beaker when using DOCKER_HOST' do
288
- ENV['DOCKER_HOST'] = "tcp://192.0.2.2:2375"
289
- docker.provision
290
-
291
- expect( hosts[0]['ip'] ).to be === '192.0.2.2'
292
- expect( hosts[0]['port'] ).to be === 8022
293
- end
294
-
295
- it 'should have ssh agent forwarding enabled' do
296
- ENV['DOCKER_HOST'] = nil
297
- docker.provision
298
-
299
- expect( hosts[0]['ip'] ).to be === '127.0.1.1'
300
- expect( hosts[0]['port'] ).to be === 8022
301
- expect( hosts[0]['ssh'][:password] ).to be === 'root'
302
- expect( hosts[0]['ssh'][:port] ).to be === 8022
303
- expect( hosts[0]['ssh'][:forward_agent] ).to be === true
304
- end
305
-
306
- end
307
-
308
- it "should generate a new /etc/hosts file referencing each host" do
309
- ENV['DOCKER_HOST'] = nil
310
- docker.provision
311
- hosts.each do |host|
312
- expect( docker ).to receive( :get_domain_name ).with( host ).and_return( 'labs.lan' )
313
- expect( docker ).to receive( :set_etc_hosts ).with( host, "127.0.0.1\tlocalhost localhost.localdomain\n192.0.2.1\tvm1.labs.lan vm1\n192.0.2.1\tvm2.labs.lan vm2\n192.0.2.1\tvm3.labs.lan vm3\n" ).once
314
- end
315
- docker.hack_etc_hosts( hosts, options )
316
- end
317
-
318
- it 'should record the image and container for later' do
319
- docker.provision
320
-
321
- expect( hosts[0]['docker_image'] ).to be === image
322
- expect( hosts[0]['docker_container'] ).to be === container
323
- end
324
-
325
- context 'provision=false' do
326
- let(:options) {{
327
- :logger => logger,
328
- :forward_ssh_agent => true,
329
- :provision => false
330
- }}
331
-
332
-
333
- it 'should fix ssh' do
334
- hosts.each_with_index do |host, index|
335
- container_name = "spec-container-#{index}"
336
- host['docker_container_name'] = container_name
337
-
338
- expect( ::Docker::Container ).to receive(:all).and_return([container])
339
- expect(container).to receive(:exec).exactly(4).times
340
- end
341
- docker.provision
342
- end
343
-
344
- it 'should not create a container if a named one already exists' do
345
- hosts.each_with_index do |host, index|
346
- container_name = "spec-container-#{index}"
347
- host['docker_container_name'] = container_name
348
-
349
- expect( ::Docker::Container ).to receive(:all).and_return([container])
350
- expect( ::Docker::Container ).not_to receive(:create)
351
- end
352
-
353
- docker.provision
354
- end
355
- end
356
- end
357
-
358
- describe '#cleanup' do
359
- before :each do
360
- # get into a state where there's something to clean
361
- allow( ::Docker ).to receive(:validate_version!)
362
- allow( docker ).to receive(:dockerfile_for)
363
- docker.provision
364
- end
365
-
366
- it 'should stop the containers' do
367
- allow( docker ).to receive( :sleep ).and_return(true)
368
- expect( container ).to receive(:kill)
369
- docker.cleanup
370
- end
371
-
372
- it 'should delete the containers' do
373
- allow( docker ).to receive( :sleep ).and_return(true)
374
- expect( container ).to receive(:delete)
375
- docker.cleanup
376
- end
377
-
378
- it 'should delete the images' do
379
- allow( docker ).to receive( :sleep ).and_return(true)
380
- expect( image ).to receive(:delete)
381
- docker.cleanup
382
- end
383
-
384
- it 'should not delete the image if docker_preserve_image is set to true' do
385
- allow( docker ).to receive( :sleep ).and_return(true)
386
- hosts.each do |host|
387
- host['docker_preserve_image']=true
388
- end
389
- expect( image ).to_not receive(:delete)
390
- docker.cleanup
391
- end
392
-
393
- it 'should delete the image if docker_preserve_image is set to false' do
394
- allow( docker ).to receive( :sleep ).and_return(true)
395
- hosts.each do |host|
396
- host['docker_preserve_image']=false
397
- end
398
- expect( image ).to receive(:delete)
399
- docker.cleanup
400
- end
401
-
402
- end
403
-
404
- describe '#dockerfile_for' do
405
- FakeFS.deactivate!
406
- before :each do
407
- allow( ::Docker ).to receive(:validate_version!)
408
- end
409
- it 'should raise on an unsupported platform' do
410
- expect { docker.send(:dockerfile_for, {'platform' => 'a_sidewalk', 'image' => 'foobar' }) }.to raise_error(/platform a_sidewalk not yet supported/)
411
- end
412
-
413
- it 'should raise on missing image' do
414
- expect { docker.send(:dockerfile_for, {'platform' => 'centos-7-x86_64'})}.to raise_error(/Docker image undefined/)
415
- end
416
-
417
- it 'should set "ENV container docker"' do
418
- FakeFS.deactivate!
419
- platforms.each do |platform|
420
- dockerfile = docker.send(:dockerfile_for, {
421
- 'platform' => platform,
422
- 'image' => 'foobar',
423
- })
424
- expect( dockerfile ).to be =~ /ENV container docker/
425
- end
426
- end
427
-
428
- it 'should add docker_image_commands as RUN statements' do
429
- FakeFS.deactivate!
430
- platforms.each do |platform|
431
- dockerfile = docker.send(:dockerfile_for, {
432
- 'platform' => platform,
433
- 'image' => 'foobar',
434
- 'docker_image_commands' => [
435
- 'special one',
436
- 'special two',
437
- 'special three',
438
- ]
439
- })
440
-
441
- expect( dockerfile ).to be =~ /RUN special one\nRUN special two\nRUN special three/
442
- end
443
- end
444
-
445
- it 'should add docker_image_entrypoint' do
446
- FakeFS.deactivate!
447
- platforms.each do |platform|
448
- dockerfile = docker.send(:dockerfile_for, {
449
- 'platform' => platform,
450
- 'image' => 'foobar',
451
- 'docker_image_entrypoint' => '/bin/bash'
452
- })
453
-
454
- expect( dockerfile ).to be =~ %r{ENTRYPOINT /bin/bash}
455
- end
456
- end
457
-
458
- it 'should use zypper on sles' do
459
- FakeFS.deactivate!
460
- dockerfile = docker.send(:dockerfile_for, {
461
- 'platform' => 'sles-12-x86_64',
462
- 'image' => 'foobar',
463
- })
464
-
465
- expect( dockerfile ).to be =~ /RUN zypper -n in openssh/
466
- end
467
-
468
- (22..29).to_a.each do | fedora_release |
469
- it "should use dnf on fedora #{fedora_release}" do
470
- FakeFS.deactivate!
471
- dockerfile = docker.send(:dockerfile_for, {
472
- 'platform' => "fedora-#{fedora_release}-x86_64",
473
- 'image' => 'foobar',
474
- })
475
-
476
- expect( dockerfile ).to be =~ /RUN dnf install -y sudo/
477
- end
478
- end
479
-
480
- it 'should use user dockerfile if specified' do
481
- FakeFS.deactivate!
482
- dockerfile = docker.send(:dockerfile_for, {
483
- 'dockerfile' => 'README.md'
484
- })
485
-
486
- expect( dockerfile ).to be == File.read('README.md')
487
- end
488
-
489
- end
490
- end
491
- end