docker-api 1.31.0 → 1.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,148 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Docker::Event do
4
- let(:api_response) do
5
- {
6
- 'Action' => 'start',
7
- 'Actor' => {
8
- 'Attributes' => {
9
- 'image' => 'tianon/true',
10
- 'name' => 'true-dat'
11
- },
12
- 'ID' => 'bb2c783a32330b726f18d1eb44d80c899ef45771b4f939326e0fefcfc7e05db8'
13
- },
14
- 'Type' => 'container',
15
- 'from' => 'tianon/true',
16
- 'id' => 'bb2c783a32330b726f18d1eb44d80c899ef45771b4f939326e0fefcfc7e05db8',
17
- 'status' => 'start',
18
- 'time' => 1461083270,
19
- 'timeNano' => 1461083270652069004
20
- }
21
- end
22
-
23
- describe "#to_s" do
24
- context 'with an old event' do
25
- let(:event) do
26
- described_class.new(
27
- status: status,
28
- id: id,
29
- from: from,
30
- time: time
31
- )
32
- end
33
-
34
- let(:status) { "start" }
35
- let(:id) { "398c9f77b5d2" }
36
- let(:from) { "debian:wheezy" }
37
- let(:time) { 1381956164 }
38
-
39
- let(:expected_string) {
40
- "Docker::Event { #{time} #{status} #{id} (from=#{from}) }"
41
- }
42
-
43
- it "equals the expected string" do
44
- expect(event.to_s).to eq(expected_string)
45
- end
46
- end
47
-
48
- context 'with a new event' do
49
- let(:event) { described_class.new(api_response) }
50
-
51
- let(:expected_string) do
52
- 'Docker::Event { 1461083270652069004 container start '\
53
- 'bb2c783a32330b726f18d1eb44d80c899ef45771b4f939326e0fefcfc7e05db8 '\
54
- '(image=tianon/true, name=true-dat) }'
55
- end
56
-
57
- it 'equals the expected string' do
58
- expect(event.to_s).to eq(expected_string)
59
- end
60
- end
61
- end
62
-
63
- describe ".stream" do
64
- let(:container) { Docker::Image.create('fromImage' => 'debian:wheezy').run('bash') }
65
- it 'receives at least 4 events' do
66
- expect(Docker::Event)
67
- .to receive(:new_event)
68
- .at_least(4).times
69
- .and_call_original
70
-
71
- stream_thread = Thread.new do
72
- Docker::Event.stream do |event|
73
- puts "#{event}"
74
- end
75
- end
76
-
77
- stream_thread.join(0.1)
78
- container.wait
79
- stream_thread.join(10)
80
- stream_thread.kill
81
-
82
- container.remove
83
- end
84
- end
85
-
86
- describe ".since" do
87
- let(:time) { Time.now.to_i + 1 }
88
- let(:container) { Docker::Image.create('fromImage' => 'debian:wheezy').run('bash') }
89
-
90
- it 'receives at least 4 events' do
91
- expect(Docker::Event)
92
- .to receive(:new_event)
93
- .at_least(4).times
94
- .and_call_original
95
-
96
- stream_thread = Thread.new do
97
- Docker::Event.since(time) do |event|
98
- puts "#{event}"
99
- end
100
- end
101
-
102
- stream_thread.join(0.1)
103
- container.wait
104
- stream_thread.join(10)
105
- stream_thread.kill
106
-
107
- container.remove
108
- end
109
- end
110
-
111
- describe ".new_event" do
112
- context 'with an old api response' do
113
- let(:event) { Docker::Event.new_event(response_body, nil, nil) }
114
- let(:status) { "start" }
115
- let(:id) { "398c9f77b5d2" }
116
- let(:from) { "debian:wheezy" }
117
- let(:time) { 1381956164 }
118
- let(:response_body) {
119
- "{\"status\":\"#{status}\",\"id\":\"#{id}\""\
120
- ",\"from\":\"#{from}\",\"time\":#{time}}"
121
- }
122
-
123
- it "returns a Docker::Event" do
124
- expect(event).to be_kind_of(Docker::Event)
125
- expect(event.status).to eq(status)
126
- expect(event.id).to eq(id)
127
- expect(event.from).to eq(from)
128
- expect(event.time).to eq(time)
129
- end
130
- end
131
-
132
- context 'with a new api response' do
133
- let(:event) { Docker::Event.new_event(api_response.to_json, nil, nil) }
134
-
135
- it 'returns a Docker::Event' do
136
- expect(event).to be_kind_of(Docker::Event)
137
- expect(event.type).to eq('container')
138
- expect(event.action).to eq('start')
139
- expect(
140
- event.actor.id
141
- ).to eq('bb2c783a32330b726f18d1eb44d80c899ef45771b4f939326e0fefcfc7e05db8')
142
- expect(event.actor.attributes).to eq('image' => 'tianon/true', 'name' => 'true-dat')
143
- expect(event.time).to eq 1461083270
144
- expect(event.time_nano).to eq 1461083270652069004
145
- end
146
- end
147
- end
148
- end
@@ -1,181 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Docker::Exec do
4
- let(:container) {
5
- Docker::Container.create(
6
- 'Cmd' => %w(sleep 300),
7
- 'Image' => 'debian:wheezy'
8
- ).start!
9
- }
10
-
11
- describe '#to_s' do
12
- subject {
13
- described_class.send(:new, Docker.connection, 'id' => rand(10000).to_s)
14
- }
15
-
16
- let(:id) { 'bf119e2' }
17
- let(:connection) { Docker.connection }
18
- let(:expected_string) {
19
- "Docker::Exec { :id => #{id}, :connection => #{connection} }"
20
- }
21
- before do
22
- {
23
- :@id => id,
24
- :@connection => connection
25
- }.each { |k, v| subject.instance_variable_set(k, v) }
26
- end
27
-
28
- its(:to_s) { should == expected_string }
29
- end
30
-
31
- describe '.create' do
32
- subject { described_class }
33
-
34
- context 'when the HTTP request returns a 201' do
35
- let(:options) do
36
- {
37
- 'AttachStdin' => false,
38
- 'AttachStdout' => false,
39
- 'AttachStderr' => false,
40
- 'Tty' => false,
41
- 'Cmd' => [
42
- 'date'
43
- ],
44
- 'Container' => container.id
45
- }
46
- end
47
- let(:process) { subject.create(options) }
48
- after { container.kill!.remove }
49
-
50
- it 'sets the id' do
51
- expect(process).to be_a Docker::Exec
52
- expect(process.id).to_not be_nil
53
- expect(process.connection).to_not be_nil
54
- end
55
- end
56
-
57
- context 'when the parent container does not exist' do
58
- before do
59
- Docker.options = { :mock => true }
60
- Excon.stub({ :method => :post }, { :status => 404 })
61
- end
62
- after do
63
- Excon.stubs.shift
64
- Docker.options = {}
65
- end
66
-
67
- it 'raises an error' do
68
- expect { subject.create }.to raise_error(Docker::Error::NotFoundError)
69
- end
70
- end
71
- end
72
-
73
- describe '#json' do
74
- subject {
75
- described_class.create(
76
- 'Container' => container.id,
77
- 'Detach' => true,
78
- 'Cmd' => %w[true]
79
- )
80
- }
81
-
82
- let(:description) { subject.json }
83
- before { subject.start! }
84
- after { container.kill!.remove }
85
-
86
- it 'returns the description as a Hash' do
87
- expect(description).to be_a Hash
88
- expect(description['ID']).to start_with(subject.id)
89
- end
90
- end
91
-
92
- describe '#start!' do
93
- context 'when the exec instance does not exist' do
94
- subject do
95
- described_class.send(:new, Docker.connection, 'id' => rand(10000).to_s)
96
- end
97
-
98
- it 'raises an error' do
99
- expect { subject.start! }.to raise_error(Docker::Error::NotFoundError)
100
- end
101
- end
102
-
103
- context 'when :detach is set to false' do
104
- subject {
105
- described_class.create(
106
- 'Container' => container.id,
107
- 'AttachStdout' => true,
108
- 'Cmd' => ['bash','-c','sleep 2; echo hello']
109
- )
110
- }
111
- after { container.kill!.remove }
112
-
113
- it 'returns the stdout and stderr messages' do
114
- expect(subject.start!).to eq([["hello\n"],[],0])
115
- end
116
-
117
- context 'block is passed' do
118
- it 'attaches to the stream' do
119
- chunk = nil
120
- result = subject.start! do |stream, c|
121
- chunk ||= c
122
- end
123
- expect(chunk).to eq("hello\n")
124
- expect(result).to eq([["hello\n"], [], 0])
125
- end
126
- end
127
- end
128
-
129
- context 'when :detach is set to true' do
130
- subject {
131
- described_class.create('Container' => container.id, 'Cmd' => %w[date])
132
- }
133
- after { container.kill!.remove }
134
-
135
- it 'returns empty stdout/stderr messages with exitcode' do
136
- expect(subject.start!(:detach => true).length).to eq(3)
137
- end
138
- end
139
-
140
- context 'when :wait set long time value' do
141
- subject {
142
- described_class.create(
143
- 'Container' => container.id,
144
- 'AttachStdout' => true,
145
- 'Cmd' => %w[true]
146
- )
147
- }
148
- after { container.kill!.remove }
149
-
150
- it 'returns empty stdout and stderr messages with exitcode' do
151
- expect(subject.start!(:wait => 100)).to eq([[], [], 0])
152
- end
153
- end
154
-
155
- context 'when :wait set short time value' do
156
- subject {
157
- described_class.create(
158
- 'Container' => container.id,
159
- 'AttachStdout' => true,
160
- 'Cmd' => ['bash', '-c', 'sleep 2; echo hello']
161
- )
162
- }
163
- after { container.kill!.remove }
164
-
165
- it 'raises an error' do
166
- expect { subject.start!(:wait => 1) }.to raise_error(Docker::Error::TimeoutError)
167
- end
168
- end
169
-
170
- context 'when the HTTP request returns a 201' do
171
- subject {
172
- described_class.create('Container' => container.id, 'Cmd' => ['date'])
173
- }
174
- after { container.kill!.remove }
175
-
176
- it 'starts the exec instance' do
177
- expect { subject.start! }.not_to raise_error
178
- end
179
- end
180
- end
181
- end
@@ -1,722 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Docker::Image do
4
- describe '#to_s' do
5
- subject { described_class.new(Docker.connection, info) }
6
-
7
- let(:id) { 'bf119e2' }
8
- let(:connection) { Docker.connection }
9
-
10
- let(:info) do
11
- {"id" => "bf119e2", "Repository" => "debian", "Tag" => "wheezy",
12
- "Created" => 1364102658, "Size" => 24653, "VirtualSize" => 180116135}
13
- end
14
-
15
- let(:expected_string) do
16
- "Docker::Image { :id => #{id}, :info => #{info.inspect}, "\
17
- ":connection => #{connection} }"
18
- end
19
-
20
- its(:to_s) { should == expected_string }
21
- end
22
-
23
- describe '#remove' do
24
-
25
- context 'when no name is given' do
26
- let(:id) { subject.id }
27
- subject { described_class.create('fromImage' => 'busybox:latest') }
28
- after { described_class.create('fromImage' => 'busybox:latest') }
29
-
30
- it 'removes the Image' do
31
- subject.remove(:force => true)
32
- expect(Docker::Image.all.map(&:id)).to_not include(id)
33
- end
34
- end
35
-
36
- context 'when using the class' do
37
- let(:id) { subject.id }
38
- subject { described_class.create('fromImage' => 'busybox:latest') }
39
- after { described_class.create('fromImage' => 'busybox:latest') }
40
-
41
- it 'removes the Image' do
42
- Docker::Image.remove(id, force: true)
43
- expect(Docker::Image.all.map(&:id)).to_not include(id)
44
- end
45
- end
46
-
47
- context 'when a valid tag is given' do
48
- it 'untags the Image'
49
- end
50
-
51
- context 'when an invalid tag is given' do
52
- it 'raises an error'
53
- end
54
- end
55
-
56
- describe '#insert_local' do
57
- include_context "local paths"
58
-
59
- subject { described_class.create('fromImage' => 'debian:wheezy') }
60
-
61
- let(:rm) { false }
62
- let(:new_image) {
63
- opts = {'localPath' => file, 'outputPath' => '/'}
64
- opts[:rm] = true if rm
65
- subject.insert_local(opts)
66
- }
67
-
68
- context 'when the local file does not exist' do
69
- let(:file) { '/lol/not/a/file' }
70
-
71
- it 'raises an error' do
72
- expect { new_image }.to raise_error(Docker::Error::ArgumentError)
73
- end
74
- end
75
-
76
- context 'when the local file does exist' do
77
- let(:file) { File.join(project_dir, 'Gemfile') }
78
- let(:gemfile) { File.read('Gemfile') }
79
- let(:container) { new_image.run('cat /Gemfile').tap(&:wait) }
80
- after do
81
- container.remove
82
- new_image.remove
83
- end
84
-
85
- it 'creates a new Image that has that file' do
86
- output = container.streaming_logs(stdout: true)
87
- expect(output).to eq(gemfile)
88
- end
89
- end
90
-
91
- context 'when a direcory is passed' do
92
- let(:new_image) {
93
- subject.insert_local(
94
- 'localPath' => File.join(project_dir, 'lib'),
95
- 'outputPath' => '/lib'
96
- )
97
- }
98
- let(:container) { new_image.run('ls -a /lib/docker') }
99
- let(:response) { container.tap(&:wait).streaming_logs(stdout: true) }
100
- after do
101
- container.tap(&:wait).remove
102
- new_image.remove
103
- end
104
-
105
- it 'inserts the directory' do
106
- expect(response.split("\n").sort).to eq(Dir.entries('lib/docker').sort)
107
- end
108
- end
109
-
110
- context 'when there are multiple files passed' do
111
- let(:file) {
112
- [File.join(project_dir, 'Gemfile'), File.join(project_dir, 'LICENSE')]
113
- }
114
- let(:gemfile) { File.read('Gemfile') }
115
- let(:license) { File.read('LICENSE') }
116
- let(:container) { new_image.run('cat /Gemfile /LICENSE') }
117
- let(:response) {
118
- container.tap(&:wait).streaming_logs(stdout: true)
119
- }
120
- after do
121
- container.remove
122
- new_image.remove
123
- end
124
-
125
- it 'creates a new Image that has each file' do
126
- expect(response).to eq("#{gemfile}#{license}")
127
- end
128
- end
129
-
130
- context 'when removing intermediate containers' do
131
- let(:rm) { true }
132
- let(:file) { File.join(project_dir, 'Gemfile') }
133
- after(:each) { new_image.remove }
134
-
135
- it 'leave no intermediate containers' do
136
- expect { new_image }.to change {
137
- Docker::Container.all(:all => true).count
138
- }.by 0
139
- end
140
-
141
- it 'creates a new image' do
142
- expect{new_image}.to change{Docker::Image.all.count}.by 1
143
- end
144
- end
145
- end
146
-
147
- describe '#push' do
148
- let(:credentials) {
149
- {
150
- 'username' => ENV['DOCKER_API_USER'],
151
- 'password' => ENV['DOCKER_API_PASS'],
152
- 'serveraddress' => 'https://index.docker.io/v1',
153
- 'email' => ENV['DOCKER_API_EMAIL']
154
- }
155
- }
156
- let(:repo_tag) { "#{ENV['DOCKER_API_USER']}/true" }
157
- let(:image) {
158
- described_class.build("FROM tianon/true\n", "t" => repo_tag).refresh!
159
- }
160
- after { image.remove(:name => repo_tag, :noprune => true) }
161
-
162
- it 'pushes the Image' do
163
- image.push(credentials)
164
- end
165
-
166
- it 'streams output from push' do
167
- expect { |b| image.push(credentials, &b) }
168
- .to yield_control.at_least(1)
169
- end
170
-
171
- context 'when a tag is specified' do
172
- it 'pushes that specific tag'
173
- end
174
-
175
- context 'when the image was retrived by get' do
176
- let(:image) {
177
- described_class.build("FROM tianon/true\n", "t" => repo_tag).refresh!
178
- described_class.get(repo_tag)
179
- }
180
-
181
- context 'when no tag is specified' do
182
- it 'looks up the first repo tag' do
183
- expect { image.push }.to_not raise_error
184
- end
185
- end
186
- end
187
-
188
- context 'when there are no credentials' do
189
- let(:credentials) { nil }
190
- let(:repo_tag) { "localhost:5000/true" }
191
-
192
- it 'still pushes' do
193
- expect { image.push }.to_not raise_error
194
- end
195
- end
196
- end
197
-
198
- describe '#tag' do
199
- subject { described_class.create('fromImage' => 'debian:wheezy') }
200
- after { subject.remove(:name => 'teh:latest', :noprune => true) }
201
-
202
- it 'tags the image with the repo name' do
203
- subject.tag(:repo => :teh, :force => true)
204
- expect(subject.info['RepoTags']).to include 'teh:latest'
205
- end
206
- end
207
-
208
- describe '#json' do
209
- subject { described_class.create('fromImage' => 'debian:wheezy') }
210
- let(:json) { subject.json }
211
-
212
- it 'returns additional information about image image' do
213
- expect(json).to be_a Hash
214
- expect(json.length).to_not be_zero
215
- end
216
- end
217
-
218
- describe '#history' do
219
- subject { described_class.create('fromImage' => 'debian:wheezy') }
220
- let(:history) { subject.history }
221
-
222
- it 'returns the history of the Image' do
223
- expect(history).to be_a Array
224
- expect(history.length).to_not be_zero
225
- expect(history).to be_all { |elem| elem.is_a? Hash }
226
- end
227
- end
228
-
229
- describe '#run' do
230
- let(:cmd) { nil }
231
- let(:options) { {} }
232
-
233
- subject do
234
- described_class.create(
235
- {'fromImage' => 'debian:wheezy'})
236
- end
237
-
238
- let(:container) { subject.run(cmd, options).tap(&:wait) }
239
- let(:output) { container.streaming_logs(stdout: true) }
240
-
241
- context 'when cmd is a String' do
242
- let(:cmd) { 'ls /lib64/' }
243
- after { container.remove }
244
-
245
- it 'splits the String by spaces and creates a new Container' do
246
- expect(output).to eq("ld-linux-x86-64.so.2\n")
247
- end
248
- end
249
-
250
- context 'when cmd is an Array' do
251
- let(:cmd) { %w[which pwd] }
252
- after { container.remove }
253
-
254
- it 'creates a new Container' do
255
- expect(output).to eq("/bin/pwd\n")
256
- end
257
- end
258
-
259
- context 'when cmd is nil' do
260
- let(:cmd) { nil }
261
- context 'no command configured in image' do
262
- subject { described_class.create('fromImage' => 'swipely/base') }
263
- it 'should raise an error if no command is specified' do
264
- expect {container}.to raise_error(Docker::Error::ServerError,
265
- "No command specified.")
266
- end
267
- end
268
-
269
- context "command configured in image" do
270
- let(:cmd) { 'pwd' }
271
- after { container.remove }
272
-
273
- it 'should normally show result if image has Cmd configured' do
274
- expect(output).to eql "/\n"
275
- end
276
- end
277
- end
278
-
279
- context 'when using cpu shares' do
280
- let(:options) { { 'CpuShares' => 50 } }
281
- after { container.remove }
282
-
283
- it 'returns 50' do
284
- expect(container.json["Config"]["CpuShares"]).to eq 50
285
- end
286
- end
287
- end
288
-
289
- describe '#save' do
290
- let(:image) { Docker::Image.get('busybox') }
291
-
292
- it 'calls the class method' do
293
- expect(Docker::Image).to receive(:save)
294
- .with(image.id, 'busybox.tar', anything)
295
- image.save('busybox.tar')
296
- end
297
- end
298
-
299
- describe '#save_stream' do
300
- let(:image) { Docker::Image.get('busybox') }
301
- let(:block) { proc { |chunk| puts chunk } }
302
-
303
- it 'calls the class method' do
304
- expect(Docker::Image).to receive(:save_stream)
305
- .with(image.id, instance_of(Hash), instance_of(Docker::Connection))
306
- image.save_stream(:chunk_size => 1024 * 1024, &block)
307
- end
308
- end
309
-
310
- describe '#refresh!' do
311
- let(:image) { Docker::Image.create('fromImage' => 'debian:wheezy') }
312
-
313
- it 'updates the @info hash' do
314
- size = image.info.size
315
- image.refresh!
316
- expect(image.info.size).to be > size
317
- end
318
-
319
- context 'with an explicit connection' do
320
- let(:connection) { Docker::Connection.new(Docker.url, Docker.options) }
321
- let(:image) {
322
- Docker::Image.create({'fromImage' => 'debian:wheezy'}, nil, connection)
323
- }
324
-
325
- it 'updates using the provided connection' do
326
- image.refresh!
327
- end
328
- end
329
- end
330
-
331
- describe '.load' do
332
- include_context "local paths"
333
- let(:file) { File.join(project_dir, 'spec', 'fixtures', 'load.tar') }
334
-
335
- context 'when the argument is a String' do
336
- it 'loads tianon/true image from the file system' do
337
- result = Docker::Image.load(file)
338
- expect(result).to eq("")
339
- end
340
- end
341
-
342
- context 'when the argument is an IO' do
343
- let(:io) { File.open(file) }
344
-
345
- after { io.close }
346
-
347
- it 'loads tinan/true image from the IO' do
348
- result = Docker::Image.load(io)
349
- expect(result).to eq("")
350
- end
351
- end
352
- end
353
-
354
- describe '.create' do
355
- subject { described_class }
356
-
357
- context 'when the Image does not yet exist and the body is a Hash' do
358
- let(:image) { subject.create('fromImage' => 'swipely/base') }
359
- let(:creds) {
360
- {
361
- :username => ENV['DOCKER_API_USER'],
362
- :password => ENV['DOCKER_API_PASS'],
363
- :email => ENV['DOCKER_API_EMAIL']
364
- }
365
- }
366
-
367
- before do
368
- Docker::Image.create('fromImage' => 'swipely/base').remove
369
- end
370
- after { Docker::Image.create('fromImage' => 'swipely/base') }
371
-
372
- it 'sets the id and sends Docker.creds' do
373
- allow(Docker).to receive(:creds).and_return(creds)
374
- expect(image).to be_a Docker::Image
375
- expect(image.id).to match(/\A(sha256:)?[a-fA-F0-9]+\Z/)
376
- expect(image.id).to_not include('base')
377
- expect(image.id).to_not be_nil
378
- expect(image.id).to_not be_empty
379
- end
380
- end
381
-
382
- context 'with a block capturing create output' do
383
- let(:create_output) { "" }
384
- let(:block) { Proc.new { |chunk| create_output << chunk } }
385
-
386
- before do
387
- Docker.creds = nil
388
- subject.create('fromImage' => 'tianon/true').remove
389
- end
390
-
391
- it 'calls the block and passes build output' do
392
- subject.create('fromImage' => 'tianon/true', &block)
393
- expect(create_output).to match(/Pulling.*tianon\/true/)
394
- end
395
- end
396
- end
397
-
398
- describe '.get' do
399
- subject { described_class }
400
- let(:image) { subject.get(image_name) }
401
-
402
- context 'when the image does exist' do
403
- let(:image_name) { 'debian:wheezy' }
404
-
405
- it 'returns the new image' do
406
- expect(image).to be_a Docker::Image
407
- end
408
- end
409
-
410
- context 'when the image does not exist' do
411
- let(:image_name) { 'abcdefghijkl' }
412
-
413
- before do
414
- Docker.options = { :mock => true }
415
- Excon.stub({ :method => :get }, { :status => 404 })
416
- end
417
-
418
- after do
419
- Docker.options = {}
420
- Excon.stubs.shift
421
- end
422
-
423
- it 'raises a not found error' do
424
- expect { image }.to raise_error(Docker::Error::NotFoundError)
425
- end
426
- end
427
- end
428
-
429
- describe '.save' do
430
- include_context "local paths"
431
-
432
- context 'when a filename is specified' do
433
- let(:file) { "#{project_dir}/scratch.tar" }
434
- after { FileUtils.remove(file) }
435
-
436
- it 'exports tarball of image to specified file' do
437
- Docker::Image.save('swipely/base', file)
438
- expect(File.exist?(file)).to eq true
439
- expect(File.read(file)).to_not be_nil
440
- end
441
- end
442
-
443
- context 'when no filename is specified' do
444
- it 'returns raw binary data as string' do
445
- raw = Docker::Image.save('swipely/base')
446
- expect(raw).to_not be_nil
447
- end
448
- end
449
- end
450
-
451
- describe '.save_stream' do
452
- let(:image) { 'busybox:latest' }
453
- let(:non_streamed) do
454
- Docker.connection.get(
455
- '/images/get',
456
- 'names' => URI.encode(image)
457
- )
458
- end
459
- let(:streamed) { '' }
460
- let(:tar_files) do
461
- proc do |string|
462
- Gem::Package::TarReader
463
- .new(StringIO.new(string, 'rb'))
464
- .map(&:full_name)
465
- .sort
466
- end
467
- end
468
-
469
- it 'yields each chunk of the image' do
470
- Docker::Image.save_stream(image) { |chunk| streamed << chunk }
471
- expect(tar_files.call(streamed)).to eq(tar_files.call(non_streamed))
472
- end
473
- end
474
-
475
- describe '.exist?' do
476
- subject { described_class }
477
- let(:exists) { subject.exist?(image_name) }
478
-
479
- context 'when the image does exist' do
480
- let(:image_name) { 'debian:wheezy' }
481
-
482
- it 'returns true' do
483
- expect(exists).to eq(true)
484
- end
485
- end
486
-
487
- context 'when the image does not exist' do
488
- let(:image_name) { 'abcdefghijkl' }
489
-
490
- before do
491
- Docker.options = { :mock => true }
492
- Excon.stub({ :method => :get }, { :status => 404 })
493
- end
494
-
495
- after do
496
- Docker.options = {}
497
- Excon.stubs.shift
498
- end
499
-
500
- it 'return false' do
501
- expect(exists).to eq(false)
502
- end
503
- end
504
- end
505
-
506
- describe '.import' do
507
- include_context "local paths"
508
-
509
- subject { described_class }
510
-
511
- context 'when the file does not exist' do
512
- let(:file) { '/lol/not/a/file' }
513
-
514
- it 'raises an error' do
515
- expect { subject.import(file) }
516
- .to raise_error(Docker::Error::IOError)
517
- end
518
- end
519
-
520
- context 'when the file does exist' do
521
- let(:file) { File.join(project_dir, 'spec', 'fixtures', 'export.tar') }
522
- let(:import) { subject.import(file) }
523
- after { import.remove(:noprune => true) }
524
-
525
- it 'creates the Image' do
526
- expect(import).to be_a Docker::Image
527
- expect(import.id).to_not be_nil
528
- end
529
- end
530
-
531
- context 'when the argument is a URI' do
532
- context 'when the URI is invalid' do
533
- it 'raises an error' do
534
- expect { subject.import('http://google.com') }
535
- .to raise_error(Docker::Error::IOError)
536
- end
537
- end
538
-
539
- context 'when the URI is valid' do
540
- let(:uri) { 'http://swipely-pub.s3.amazonaws.com/tianon_true.tar' }
541
- let(:import) { subject.import(uri) }
542
- after { import.remove(:noprune => true) }
543
-
544
- it 'returns an Image' do
545
- expect(import).to be_a Docker::Image
546
- expect(import.id).to_not be_nil
547
- end
548
- end
549
- end
550
- end
551
-
552
- describe '.all' do
553
- subject { described_class }
554
-
555
- let(:images) { subject.all(:all => true) }
556
- before { subject.create('fromImage' => 'debian:wheezy') }
557
-
558
- it 'materializes each Image into a Docker::Image' do
559
- images.each do |image|
560
- expect(image).to_not be_nil
561
-
562
- expect(image).to be_a(described_class)
563
-
564
- expect(image.id).to_not be_nil
565
-
566
- %w(Created Size VirtualSize).each do |key|
567
- expect(image.info).to have_key(key)
568
- end
569
- end
570
-
571
- expect(images.length).to_not be_zero
572
- end
573
- end
574
-
575
- describe '.search' do
576
- subject { described_class }
577
-
578
- it 'materializes each Image into a Docker::Image' do
579
- expect(subject.search('term' => 'sshd')).to be_all { |image|
580
- !image.id.nil? && image.is_a?(described_class)
581
- }
582
- end
583
- end
584
-
585
- describe '.build' do
586
- subject { described_class }
587
- context 'with an invalid Dockerfile' do
588
- it 'throws a UnexpectedResponseError' do
589
- expect { subject.build('lololol') }
590
- .to raise_error(Docker::Error::UnexpectedResponseError)
591
- end
592
- end
593
-
594
- context 'with a valid Dockerfile' do
595
- context 'without query parameters' do
596
- let(:image) { subject.build("FROM debian:wheezy\n") }
597
-
598
- it 'builds an image' do
599
- expect(image).to be_a Docker::Image
600
- expect(image.id).to_not be_nil
601
- expect(image.connection).to be_a Docker::Connection
602
- end
603
- end
604
-
605
- context 'with specifying a repo in the query parameters' do
606
- let(:image) {
607
- subject.build(
608
- "FROM debian:wheezy\nRUN true\n",
609
- "t" => "#{ENV['DOCKER_API_USER']}/debian:true"
610
- )
611
- }
612
- after { image.remove(:noprune => true) }
613
-
614
- it 'builds an image and tags it' do
615
- expect(image).to be_a Docker::Image
616
- expect(image.id).to_not be_nil
617
- expect(image.connection).to be_a Docker::Connection
618
- image.refresh!
619
- expect(image.info["RepoTags"]).to eq(
620
- ["#{ENV['DOCKER_API_USER']}/debian:true"]
621
- )
622
- end
623
- end
624
-
625
- context 'with a block capturing build output' do
626
- let(:build_output) { "" }
627
- let(:block) { Proc.new { |chunk| build_output << chunk } }
628
- let!(:image) { subject.build("FROM debian:wheezy\n", &block) }
629
-
630
- it 'calls the block and passes build output' do
631
- expect(build_output).to match(/Step \d : FROM debian:wheezy/)
632
- end
633
- end
634
- end
635
- end
636
-
637
- describe '.build_from_dir' do
638
- subject { described_class }
639
-
640
- context 'with a valid Dockerfile' do
641
- let(:dir) {
642
- File.join(File.dirname(__FILE__), '..', 'fixtures', 'build_from_dir')
643
- }
644
- let(:docker_file) { File.new("#{dir}/Dockerfile") }
645
- let(:image) { subject.build_from_dir(dir, opts, &block) }
646
- let(:opts) { {} }
647
- let(:block) { Proc.new {} }
648
- let(:container) do
649
- Docker::Container.create(
650
- 'Image' => image.id,
651
- 'Cmd' => %w[cat /Dockerfile]
652
- ).tap(&:start).tap(&:wait)
653
- end
654
- let(:output) { container.streaming_logs(stdout: true) }
655
-
656
- after(:each) do
657
- container.remove
658
- image.remove(:noprune => true)
659
- end
660
-
661
- context 'with no query parameters' do
662
- it 'builds the image' do
663
- expect(output).to eq(docker_file.read)
664
- end
665
- end
666
-
667
- context 'with specifying a repo in the query parameters' do
668
- let(:opts) { { "t" => "#{ENV['DOCKER_API_USER']}/debian:from_dir" } }
669
- it 'builds the image and tags it' do
670
- expect(output).to eq(docker_file.read)
671
- image.refresh!
672
- expect(image.info["RepoTags"]).to eq(
673
- ["#{ENV['DOCKER_API_USER']}/debian:from_dir"]
674
- )
675
- end
676
- end
677
-
678
- context 'with a block capturing build output' do
679
- let(:build_output) { "" }
680
- let(:block) { Proc.new { |chunk| build_output << chunk } }
681
-
682
- it 'calls the block and passes build output' do
683
- image # Create the image variable, which is lazy-loaded by Rspec
684
- expect(build_output).to match(/Step \d : FROM debian:wheezy/)
685
- end
686
-
687
- context 'uses a cached version the second time' do
688
- let(:build_output_two) { "" }
689
- let(:block_two) { Proc.new { |chunk| build_output_two << chunk } }
690
- let(:image_two) { subject.build_from_dir(dir, opts, &block_two) }
691
-
692
- it 'calls the block and passes build output' do
693
- image # Create the image variable, which is lazy-loaded by Rspec
694
- expect(build_output).to match(/Step \d : FROM debian:wheezy/)
695
- expect(build_output).to_not match(/Using cache/)
696
-
697
- image_two # Create the image_two variable, which is lazy-loaded by Rspec
698
- expect(build_output_two).to match(/Using cache/)
699
- end
700
- end
701
- end
702
-
703
- context 'with credentials passed' do
704
- let(:creds) {
705
- {
706
- :username => ENV['DOCKER_API_USER'],
707
- :password => ENV['DOCKER_API_PASS'],
708
- :email => ENV['DOCKER_API_EMAIL'],
709
- :serveraddress => 'https://index.docker.io/v1'
710
- }
711
- }
712
-
713
- before { Docker.creds = creds }
714
- after { Docker.creds = nil }
715
-
716
- it 'sends X-Registry-Config header' do
717
- expect(image.info[:headers].keys).to include('X-Registry-Config')
718
- end
719
- end
720
- end
721
- end
722
- end