docker-api 1.15.0 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -1
  3. data/Rakefile +37 -0
  4. data/TESTING.md +61 -0
  5. data/lib/docker.rb +8 -1
  6. data/lib/docker/container.rb +44 -80
  7. data/lib/docker/exec.rb +98 -0
  8. data/lib/docker/image.rb +4 -3
  9. data/lib/docker/util.rb +79 -0
  10. data/lib/docker/version.rb +2 -2
  11. data/spec/docker/container_spec.rb +192 -56
  12. data/spec/docker/event_spec.rb +4 -4
  13. data/spec/docker/exec_spec.rb +197 -0
  14. data/spec/docker/image_spec.rb +131 -102
  15. data/spec/docker_spec.rb +37 -27
  16. data/spec/fixtures/build_from_dir/Dockerfile +2 -2
  17. data/spec/fixtures/export.tar +0 -0
  18. data/spec/fixtures/top/Dockerfile +2 -2
  19. data/spec/spec_helper.rb +10 -0
  20. data/spec/support/vcr.rb +5 -0
  21. data/spec/vcr/Docker/_authenticate_/with_valid_credentials/logs_in_and_sets_the_creds.yml +6 -8
  22. data/spec/vcr/Docker/_info/returns_the_info_as_a_Hash.yml +7 -9
  23. data/spec/vcr/Docker/_validate_version/when_nothing_is_raised/validate_version_/.yml +7 -9
  24. data/spec/vcr/Docker/_version/returns_the_version_as_a_Hash.yml +7 -9
  25. data/spec/vcr/Docker_Container/_all/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +46 -139
  26. data/spec/vcr/Docker_Container/_attach/with_normal_sized_chunks/yields_each_chunk.yml +62 -20
  27. data/spec/vcr/Docker_Container/_attach/with_very_small_chunks/yields_each_chunk.yml +62 -20
  28. data/spec/vcr/Docker_Container/_changes/returns_the_changes_as_an_array.yml +71 -28
  29. data/spec/vcr/Docker_Container/_commit/creates_a_new_Image_from_the_Container_s_changes.yml +69 -23
  30. data/spec/vcr/Docker_Container/_copy/when_the_file_does_not_exist/raises_an_error.yml +134 -0
  31. data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_directory/yields_each_chunk_of_the_tarred_directory.yml +73 -290
  32. data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_file/yields_each_chunk_of_the_tarred_file.yml +51 -211
  33. data/spec/vcr/Docker_Container/_create/when_creating_a_container_named_bob/should_have_name_set_to_bob.yml +36 -17
  34. data/spec/vcr/Docker_Container/_create/when_the_Container_does_not_yet_exist/when_the_HTTP_request_returns_a_200/sets_the_id.yml +30 -9
  35. data/spec/vcr/Docker_Container/_delete/deletes_the_container.yml +17 -23
  36. data/spec/vcr/Docker_Container/_exec/when_detach_is_true/returns_the_Docker_Exec_object.yml +151 -0
  37. data/spec/vcr/Docker_Container/_exec/when_passed_a_block/streams_the_stdout/stderr_messages.yml +153 -0
  38. data/spec/vcr/Docker_Container/_exec/when_passed_only_a_command/returns_the_stdout/stderr_messages.yml +153 -0
  39. data/spec/vcr/Docker_Container/_exec/when_stdin_object_is_passed/returns_the_stdout/stderr_messages.yml +100 -0
  40. data/spec/vcr/Docker_Container/_exec/when_tty_is_true/returns_the_raw_stdout/stderr_output.yml +152 -0
  41. data/spec/vcr/Docker_Container/_export/yields_each_chunk.yml +263 -28
  42. data/spec/vcr/Docker_Container/_get/when_the_HTTP_response_is_a_200/materializes_the_Container_into_a_Docker_Container.yml +36 -17
  43. data/spec/vcr/Docker_Container/_json/returns_the_description_as_a_Hash.yml +36 -17
  44. data/spec/vcr/Docker_Container/_kill/kills_the_container.yml +55 -53
  45. data/spec/vcr/Docker_Container/_kill/with_a_kill_signal/kills_the_container.yml +74 -96
  46. data/spec/vcr/Docker_Container/_logs/when_not_selecting_any_stream/raises_a_client_error.yml +84 -81
  47. data/spec/vcr/Docker_Container/_logs/when_selecting_stdout/returns_blank_logs.yml +34 -15
  48. data/spec/vcr/Docker_Container/_pause/pauses_the_container.yml +98 -45
  49. data/spec/vcr/Docker_Container/_restart/restarts_the_container.yml +88 -56
  50. data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_does_not_return_status_code_of_0/raises_an_error.yml +39 -22
  51. data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_returns_a_status_code_of_0/creates_a_new_container_to_run_the_specified_command.yml +212 -60
  52. data/spec/vcr/Docker_Container/_start/starts_the_container.yml +45 -30
  53. data/spec/vcr/Docker_Container/_stop/stops_the_container.yml +54 -83
  54. data/spec/vcr/Docker_Container/_streaming_logs/when_not_selecting_any_stream/raises_a_client_error.yml +84 -81
  55. data/spec/vcr/Docker_Container/_streaming_logs/when_selecting_stdout/returns_blank_logs.yml +46 -30
  56. data/spec/vcr/Docker_Container/_top/returns_the_top_commands_as_an_Array.yml +103 -40
  57. data/spec/vcr/Docker_Container/_unpause/unpauses_the_container.yml +81 -57
  58. data/spec/vcr/Docker_Container/_wait/waits_for_the_command_to_finish.yml +39 -22
  59. data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/sets_the_read_timeout_to_that_amount_of_time.yml +39 -22
  60. data/spec/vcr/Docker_Exec/_create/when_the_HTTP_request_returns_a_201/sets_the_id.yml +128 -0
  61. data/spec/vcr/Docker_Exec/_resize/when_exec_instance_has_TTY_enabled/returns_a_200.yml +155 -0
  62. data/spec/vcr/Docker_Exec/_start_/when_detach_is_set_to_false/block_is_passed/attaches_to_the_stream.yml +152 -0
  63. data/spec/vcr/Docker_Exec/_start_/when_detach_is_set_to_false/returns_the_stdout_and_stderr_messages.yml +152 -0
  64. data/spec/vcr/Docker_Exec/_start_/when_detach_is_set_to_true/returns_empty_stdout_and_stderr_messages.yml +151 -0
  65. data/spec/vcr/Docker_Exec/_start_/when_the_HTTP_request_returns_a_201/starts_the_exec_instance.yml +151 -0
  66. data/spec/vcr/Docker_Exec/_start_/when_the_command_has_already_run/raises_an_error.yml +151 -0
  67. data/spec/vcr/Docker_Image/_all/materializes_each_Image_into_a_Docker_Image.yml +86 -200
  68. data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/with_a_block_capturing_build_output/calls_the_block_and_passes_build_output.yml +10 -14
  69. data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/with_specifying_a_repo_in_the_query_parameters/builds_an_image_and_tags_it.yml +147 -39
  70. data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/without_query_parameters/builds_an_image.yml +10 -14
  71. data/spec/vcr/Docker_Image/_build/with_an_invalid_Dockerfile/throws_a_UnexpectedResponseError.yml +12 -14
  72. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_a_block_capturing_build_output/calls_the_block_and_passes_build_output.yml +118 -16
  73. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_credentials_passed/sends_X-Registry-Config_header.yml +118 -14
  74. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_no_query_parameters/builds_the_image.yml +109 -37
  75. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_specifying_a_repo_in_the_query_parameters/builds_the_image_and_tags_it.yml +214 -60
  76. data/spec/vcr/Docker_Image/_create/when_the_Image_does_not_yet_exist_and_the_body_is_a_Hash/sets_the_id_and_sends_Docker_creds.yml +41 -2631
  77. data/spec/vcr/Docker_Image/_exist_/when_the_image_does_exist/returns_true.yml +12 -19
  78. data/spec/vcr/Docker_Image/_get/when_the_image_does_exist/returns_the_new_image.yml +7 -9
  79. data/spec/vcr/Docker_Image/_history/returns_the_history_of_the_Image.yml +17 -198
  80. data/spec/vcr/Docker_Image/_import/when_the_argument_is_a_URI/when_the_URI_is_invalid/raises_an_error.yml +26 -30
  81. data/spec/vcr/Docker_Image/_import/when_the_argument_is_a_URI/when_the_URI_is_valid/returns_an_Image.yml +246 -22
  82. data/spec/vcr/Docker_Image/_import/when_the_file_does_exist/creates_the_Image.yml +35 -10
  83. data/spec/vcr/Docker_Image/_insert_local/when_a_direcory_is_passed/inserts_the_directory.yml +1249 -74
  84. data/spec/vcr/Docker_Image/_insert_local/when_removing_intermediate_containers/creates_a_new_image.yml +84 -94
  85. data/spec/vcr/Docker_Image/_insert_local/when_removing_intermediate_containers/leave_no_intermediate_containers.yml +70 -92
  86. data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_exist/creates_a_new_Image_that_has_that_file.yml +125 -98
  87. data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_not_exist/raises_an_error.yml +13 -60
  88. data/spec/vcr/Docker_Image/_insert_local/when_there_are_multiple_files_passed/creates_a_new_Image_that_has_each_file.yml +190 -135
  89. data/spec/vcr/Docker_Image/_json/returns_additional_information_about_image_image.yml +15 -198
  90. data/spec/vcr/Docker_Image/_push/pushes_the_Image.yml +169 -264
  91. data/spec/vcr/Docker_Image/_push/when_there_are_no_credentials/still_pushes.yml +175 -4543
  92. data/spec/vcr/Docker_Image/_refresh_/updates_the_info_hash.yml +90 -206
  93. data/spec/vcr/Docker_Image/_remove/when_no_name_is_given/removes_the_Image.yml +300 -0
  94. data/spec/vcr/Docker_Image/_run/when_the_argument_is_a_String/splits_the_String_by_spaces_and_creates_a_new_Container.yml +77 -207
  95. data/spec/vcr/Docker_Image/_run/when_the_argument_is_an_Array/creates_a_new_Container.yml +77 -207
  96. data/spec/vcr/Docker_Image/_run/when_the_argument_is_nil/command_configured_in_image/should_normally_show_result_if_image_has_Cmd_configured.yml +160 -0
  97. data/spec/vcr/Docker_Image/_run/when_the_argument_is_nil/no_command_configured_in_image/should_raise_an_error_if_no_command_is_specified.yml +16 -197
  98. data/spec/vcr/Docker_Image/_search/materializes_each_Image_into_a_Docker_Image.yml +151 -73
  99. data/spec/vcr/Docker_Image/_tag/tags_the_image_with_the_repo_name.yml +42 -196
  100. metadata +67 -41
  101. data/spec/vcr/Docker_Container/_commit/if_run_is_passed_it_saves_the_command_in_the_image/saves_the_command.yml +0 -58
  102. data/spec/vcr/Docker_Container/_streaming_logs/when_not_selecting_any_stream/returns_the_error_message.yml +0 -163
  103. data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/and_a_command_runs_for_too_long/raises_a_ServerError.yml +0 -58
  104. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_credentials_passed/sends_Docker_creds.yml +0 -41
  105. data/spec/vcr/Docker_Image/_remove/removes_the_Image.yml +0 -276
@@ -6,7 +6,7 @@ describe Docker::Event do
6
6
 
7
7
  let(:status) { "start" }
8
8
  let(:id) { "398c9f77b5d2" }
9
- let(:from) { "base:latest" }
9
+ let(:from) { "debian:wheezy" }
10
10
  let(:time) { 1381956164 }
11
11
 
12
12
  let(:expected_string) {
@@ -26,7 +26,7 @@ describe Docker::Event do
26
26
  .and_call_original
27
27
  fork do
28
28
  sleep 1
29
- Docker::Image.create('fromImage' => 'base').run('bash')
29
+ Docker::Image.create('fromImage' => 'debian:wheezy').run('bash')
30
30
  end
31
31
  Docker::Event.stream do |event|
32
32
  puts "#{event}"
@@ -46,7 +46,7 @@ describe Docker::Event do
46
46
  .and_call_original
47
47
  fork do
48
48
  sleep 1
49
- Docker::Image.create('fromImage' => 'base').run('bash')
49
+ Docker::Image.create('fromImage' => 'debian:wheezy').run('bash')
50
50
  end
51
51
  Docker::Event.since(time) do |event|
52
52
  puts "#{event}"
@@ -61,7 +61,7 @@ describe Docker::Event do
61
61
  subject { Docker::Event.new_event(response_body, nil, nil) }
62
62
  let(:status) { "start" }
63
63
  let(:id) { "398c9f77b5d2" }
64
- let(:from) { "base:latest" }
64
+ let(:from) { "debian:wheezy" }
65
65
  let(:time) { 1381956164 }
66
66
  let(:response_body) {
67
67
  "{\"status\":\"#{status}\",\"id\":\"#{id}\""\
@@ -0,0 +1,197 @@
1
+ require 'spec_helper'
2
+
3
+ describe Docker::Exec do
4
+
5
+ describe '#to_s' do
6
+ subject {
7
+ described_class.send(:new, Docker.connection, 'id' => rand(10000).to_s)
8
+ }
9
+
10
+ let(:id) { 'bf119e2' }
11
+ let(:connection) { Docker.connection }
12
+ let(:expected_string) {
13
+ "Docker::Exec { :id => #{id}, :connection => #{connection} }"
14
+ }
15
+ before do
16
+ {
17
+ :@id => id,
18
+ :@connection => connection
19
+ }.each { |k, v| subject.instance_variable_set(k, v) }
20
+ end
21
+
22
+ its(:to_s) { should == expected_string }
23
+ end
24
+
25
+ describe '.create' do
26
+ subject { described_class }
27
+
28
+ context 'when the HTTP request returns a 201' do
29
+ let(:container) {
30
+ Docker::Container.create(
31
+ 'Cmd' => %w[sleep 5],
32
+ 'Image' => 'debian:wheezy'
33
+ ).start!
34
+ }
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', :vcr 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 '#start!' do
74
+ let(:container) {
75
+ Docker::Container.create(
76
+ 'Cmd' => %w[sleep 10],
77
+ 'Image' => 'debian:wheezy'
78
+ ).start!
79
+ }
80
+
81
+ context 'when the exec instance does not exist' do
82
+ subject do
83
+ described_class.send(:new, Docker.connection, 'id' => rand(10000).to_s)
84
+ end
85
+
86
+ it 'raises an error', :vcr do
87
+ skip 'The Docker API returns a 200 (docker/docker#9341)'
88
+ expect { subject.start! }.to raise_error(Docker::Error::NotFoundError)
89
+ end
90
+ end
91
+
92
+ context 'when :detach is set to false' do
93
+ subject {
94
+ described_class.create(
95
+ 'Container' => container.id,
96
+ 'AttachStdout' => true,
97
+ 'Cmd' => ['bash','-c','sleep 2; echo hello']
98
+ )
99
+ }
100
+ after { container.kill!.remove }
101
+
102
+ it 'returns the stdout and stderr messages', :vcr do
103
+ expect(subject.start!).to eq([["hello\n"],[]])
104
+ end
105
+
106
+ context 'block is passed' do
107
+ it 'attaches to the stream', :vcr do
108
+ chunk = nil
109
+ subject.start! do |stream, c|
110
+ chunk ||= c
111
+ end
112
+ expect(chunk).to eq("hello\n")
113
+ end
114
+ end
115
+ end
116
+
117
+ context 'when :detach is set to true' do
118
+ subject {
119
+ described_class.create('Container' => container.id, 'Cmd' => %w[date])
120
+ }
121
+ after { container.kill!.remove }
122
+
123
+ it 'returns empty stdout and stderr messages', :vcr do
124
+ expect(subject.start!(:detach => true)).to eq([[],[]])
125
+ end
126
+ end
127
+
128
+ context 'when the command has already run' do
129
+ subject {
130
+ described_class.create('Container' => container.id, 'Cmd' => ['date'])
131
+ }
132
+ before { subject.start! }
133
+ after { container.kill!.remove }
134
+
135
+ it 'raises an error', :vcr do
136
+ skip 'The Docker API returns a 200 (docker/docker#9341)'
137
+ expect { subject.start! }.to raise_error(Docker::Error::NotFoundError)
138
+ end
139
+ end
140
+
141
+ context 'when the HTTP request returns a 201' do
142
+ subject {
143
+ described_class.create('Container' => container.id, 'Cmd' => ['date'])
144
+ }
145
+ after { container.kill!.remove }
146
+
147
+ it 'starts the exec instance', :vcr do
148
+ expect { subject.start! }.not_to raise_error
149
+ end
150
+ end
151
+ end
152
+
153
+ describe '#resize' do
154
+ let(:container) {
155
+ Docker::Container.create(
156
+ 'Cmd' => %w[sleep 20],
157
+ 'Image' => 'debian:wheezy'
158
+ ).start!
159
+ }
160
+
161
+ context 'when exec instance has TTY enabled' do
162
+ let(:instance) do
163
+ described_class.create(
164
+ 'Container' => container.id,
165
+ 'AttachStdin' => true,
166
+ 'Tty' => true,
167
+ 'Cmd' => %w[/bin/bash]
168
+ )
169
+ end
170
+ after do
171
+ container.kill!
172
+ sleep 1
173
+ container.remove
174
+ end
175
+
176
+ it 'returns a 200', :vcr do
177
+ t = Thread.new do
178
+ instance.start!(:tty => true)
179
+ end
180
+ sleep 1
181
+ expect { instance.resize(:h => 10, :w => 30) }.not_to raise_error
182
+ t.kill
183
+ end
184
+ end
185
+
186
+ context 'when the exec instance does not exist' do
187
+ subject do
188
+ described_class.send(:new, Docker.connection, 'id' => rand(10000).to_s)
189
+ end
190
+
191
+ it 'raises an error', :vcr do
192
+ skip 'The Docker API returns a 200 (docker/docker#9341)'
193
+ expect { subject.resize }.to raise_error(Docker::Error::NotFoundError)
194
+ end
195
+ end
196
+ end
197
+ end
@@ -8,7 +8,7 @@ describe Docker::Image do
8
8
  let(:connection) { Docker.connection }
9
9
 
10
10
  let(:info) do
11
- {"id" => "bf119e2", "Repository" => "base", "Tag" => "latest",
11
+ {"id" => "bf119e2", "Repository" => "debian", "Tag" => "wheezy",
12
12
  "Created" => 1364102658, "Size" => 24653, "VirtualSize" => 180116135}
13
13
  end
14
14
 
@@ -21,17 +21,30 @@ describe Docker::Image do
21
21
  end
22
22
 
23
23
  describe '#remove' do
24
- let(:id) { subject.id }
25
- subject { described_class.create('fromImage' => 'base') }
26
24
 
27
- it 'removes the Image', :vcr do
28
- subject.remove(:force => true)
29
- expect(Docker::Image.all.map(&:id)).to_not include(id)
25
+ context 'when no name is given' do
26
+ let(:id) { subject.id }
27
+ subject { described_class.create('fromImage' => 'busybox') }
28
+
29
+ it 'removes the Image', :vcr do
30
+ subject.remove(:force => true)
31
+ expect(Docker::Image.all.map(&:id)).to_not include(id)
32
+ end
33
+ end
34
+
35
+ context 'when a valid tag is given' do
36
+ it 'untags the Image'
37
+ end
38
+
39
+ context 'when an invalid tag is given' do
40
+ it 'raises an error'
30
41
  end
31
42
  end
32
43
 
33
44
  describe '#insert_local' do
34
- subject { described_class.build('from base') }
45
+ include_context "local paths"
46
+
47
+ subject { described_class.create('fromImage' => 'debian:wheezy') }
35
48
 
36
49
  let(:rm) { false }
37
50
  let(:new_image) {
@@ -49,23 +62,33 @@ describe Docker::Image do
49
62
  end
50
63
 
51
64
  context 'when the local file does exist' do
52
- let(:file) { './Gemfile' }
65
+ let(:file) { File.join(project_dir, 'Gemfile') }
53
66
  let(:gemfile) { File.read('Gemfile') }
67
+ let(:container) { new_image.run('cat /Gemfile') }
68
+ after do
69
+ container.tap(&:wait).remove
70
+ new_image.remove
71
+ end
54
72
 
55
73
  it 'creates a new Image that has that file', :vcr do
56
- chunk = nil
57
- new_image.run('cat /Gemfile').attach { |stream, c|
58
- chunk ||= c
59
- }
60
- expect(chunk).to eq(gemfile)
74
+ output = container.streaming_logs(stdout: true)
75
+ expect(output).to eq(gemfile)
61
76
  end
62
77
  end
63
78
 
64
79
  context 'when a direcory is passed' do
65
80
  let(:new_image) {
66
- subject.insert_local('localPath' => './lib', 'outputPath' => '/lib')
81
+ subject.insert_local(
82
+ 'localPath' => File.join(project_dir, 'lib'),
83
+ 'outputPath' => '/lib'
84
+ )
67
85
  }
68
- let(:response) { new_image.run('ls -a /lib/docker').attach.flatten.first }
86
+ let(:container) { new_image.run('ls -a /lib/docker') }
87
+ let(:response) { container.streaming_logs(stdout: true) }
88
+ after do
89
+ container.tap(&:wait).remove
90
+ new_image.remove
91
+ end
69
92
 
70
93
  it 'inserts the directory', :vcr do
71
94
  expect(response.split("\n").sort).to eq(Dir.entries('lib/docker').sort)
@@ -73,21 +96,29 @@ describe Docker::Image do
73
96
  end
74
97
 
75
98
  context 'when there are multiple files passed' do
76
- let(:file) { ['./Gemfile', './Rakefile'] }
99
+ let(:file) {
100
+ [File.join(project_dir, 'Gemfile'), File.join(project_dir, 'LICENSE')]
101
+ }
77
102
  let(:gemfile) { File.read('Gemfile') }
78
- let(:rakefile) { File.read('Rakefile') }
103
+ let(:license) { File.read('LICENSE') }
104
+ let(:container) { new_image.run('cat /Gemfile /LICENSE') }
79
105
  let(:response) {
80
- new_image.run('cat /Gemfile /Rakefile').attach
106
+ container.streaming_logs(stdout: true)
81
107
  }
108
+ after do
109
+ container.tap(&:wait).remove
110
+ new_image.remove
111
+ end
82
112
 
83
113
  it 'creates a new Image that has each file', :vcr do
84
- expect(response).to eq([[gemfile, rakefile],[]])
114
+ expect(response).to eq("#{gemfile}#{license}")
85
115
  end
86
116
  end
87
117
 
88
118
  context 'when removing intermediate containers' do
89
119
  let(:rm) { true }
90
- let(:file) { './Gemfile' }
120
+ let(:file) { File.join(project_dir, 'Gemfile') }
121
+ after(:each) { new_image.remove }
91
122
 
92
123
  it 'leave no intermediate containers', :vcr do
93
124
  expect { new_image }.to change {
@@ -104,47 +135,29 @@ describe Docker::Image do
104
135
  describe '#push' do
105
136
  let(:credentials) {
106
137
  {
107
- 'username' => 'nahiluhmot',
108
- 'password' => '******',
138
+ 'username' => ENV['DOCKER_API_USER'],
139
+ 'password' => ENV['DOCKER_API_PASS'],
109
140
  'serveraddress' => 'https://index.docker.io/v1',
110
- 'email' => 'tomhulihan@swipely.com'
141
+ 'email' => ENV['DOCKER_API_EMAIL']
111
142
  }
112
143
  }
113
- let(:base_image) {
114
- described_class.create('fromImage' => 'base')
115
- }
116
- let(:container) {
117
- base_image.run('true')
118
- }
119
- let(:new_image) {
120
- container.commit('repo' => 'nahiluhmot/base2')
121
- Docker::Image.all(:all => true).select { |image|
122
- image.info['RepoTags'].include?('nahiluhmot/base2:latest')
123
- }.first
144
+ let(:repo_tag) { "#{ENV['DOCKER_API_USER']}/true" }
145
+ let(:image) {
146
+ described_class.build("FROM tianon/true\n", "t" => repo_tag).refresh!
124
147
  }
148
+ after { image.remove(:name => repo_tag, :noprune => true) }
125
149
 
126
150
  it 'pushes the Image', :vcr do
127
- new_image.push(credentials)
151
+ image.push(credentials)
152
+ end
153
+
154
+ context 'when a tag is specified' do
155
+ it 'pushes that specific tag'
128
156
  end
129
157
 
130
158
  context 'when there are no credentials' do
131
159
  let(:credentials) { nil }
132
- let(:image) {
133
- Docker::Image.create('fromImage' => 'registry', 'tag' => 'latest')
134
- }
135
-
136
- let(:container) { Docker::Container.create('Image' => image.id) }
137
-
138
- before do
139
- opts = {
140
- "PortBindings" => {
141
- "5000/tcp" => [{"HostPort" => "5000"}]
142
- }
143
- }
144
- container.start!(opts)
145
- sleep 10 # for some reason the registry isn't ready right away
146
- image.tag('repo' => 'localhost:5000/registry', 'tag' => 'test')
147
- end
160
+ let(:repo_tag) { "localhost:5000/true" }
148
161
 
149
162
  it 'still pushes', :vcr do
150
163
  expect { image.push }.to_not raise_error
@@ -153,16 +166,17 @@ describe Docker::Image do
153
166
  end
154
167
 
155
168
  describe '#tag' do
156
- subject { described_class.create('fromImage' => 'base') }
169
+ subject { described_class.create('fromImage' => 'debian:wheezy') }
170
+ after { subject.remove(:name => 'teh:latest', :noprune => true) }
157
171
 
158
172
  it 'tags the image with the repo name', :vcr do
159
- subject.tag(:repo => :base2, :force => true)
160
- expect(subject.info['RepoTags']).to include 'base2:latest'
173
+ subject.tag(:repo => :teh, :force => true)
174
+ expect(subject.info['RepoTags']).to include 'teh:latest'
161
175
  end
162
176
  end
163
177
 
164
178
  describe '#json' do
165
- subject { described_class.create('fromImage' => 'base') }
179
+ subject { described_class.create('fromImage' => 'debian:wheezy') }
166
180
  let(:json) { subject.json }
167
181
 
168
182
  it 'returns additional information about image image', :vcr do
@@ -172,7 +186,7 @@ describe Docker::Image do
172
186
  end
173
187
 
174
188
  describe '#history' do
175
- subject { described_class.create('fromImage' => 'base') }
189
+ subject { described_class.create('fromImage' => 'debian:wheezy') }
176
190
  let(:history) { subject.history }
177
191
 
178
192
  it 'returns the history of the Image', :vcr do
@@ -183,48 +197,51 @@ describe Docker::Image do
183
197
  end
184
198
 
185
199
  describe '#run' do
186
- subject { described_class.create('fromImage' => 'base') }
187
- let(:output) { subject.run(cmd).attach }
200
+ subject { described_class.create('fromImage' => 'debian:wheezy') }
201
+ let(:container) { subject.run(cmd) }
202
+ let(:output) { container.streaming_logs(stdout: true) }
188
203
 
189
204
  context 'when the argument is a String', :vcr do
190
205
  let(:cmd) { 'ls /lib64/' }
206
+ after { container.tap(&:wait).remove }
207
+
191
208
  it 'splits the String by spaces and creates a new Container' do
192
- expect(output).to eq([["ld-linux-x86-64.so.2\n"],[]])
209
+ expect(output).to eq("ld-linux-x86-64.so.2\n")
193
210
  end
194
211
  end
195
212
 
196
213
  context 'when the argument is an Array' do
197
214
  let(:cmd) { %w[which pwd] }
215
+ after { container.tap(&:wait).remove }
198
216
 
199
217
  it 'creates a new Container', :vcr do
200
- expect(output).to eq([["/bin/pwd\n"],[]])
218
+ expect(output).to eq("/bin/pwd\n")
201
219
  end
202
220
  end
203
221
 
204
222
  context 'when the argument is nil', :vcr do
205
223
  let(:cmd) { nil }
206
- context 'no command configured in image'do
224
+ context 'no command configured in image' do
225
+ subject { described_class.create('fromImage' => 'scratch') }
207
226
  it 'should raise an error if no command is specified' do
208
- expect {output}.to raise_error(Docker::Error::ServerError,
227
+ expect {container}.to raise_error(Docker::Error::ServerError,
209
228
  "No command specified.")
210
229
  end
211
230
  end
212
231
 
213
232
  context "command configured in image" do
214
- let(:container) {Docker::Container.create('Cmd' => %w[true],
215
- 'Image' => 'base')}
216
- subject { container.commit('run' => {"Cmd" => %w[pwd]}) }
233
+ let(:cmd) { 'pwd' }
234
+ after { container.tap(&:wait).remove }
217
235
 
218
236
  it 'should normally show result if image has Cmd configured' do
219
- skip 'The docs say this should work, but it clearly does not'
220
- expect(output).to eql [["/\n"],[]]
237
+ expect(output).to eql "/\n"
221
238
  end
222
239
  end
223
240
  end
224
241
  end
225
242
 
226
243
  describe '#refresh!' do
227
- let(:image) { Docker::Image.create('fromImage' => 'base') }
244
+ let(:image) { Docker::Image.create('fromImage' => 'debian:wheezy') }
228
245
 
229
246
  it 'updates the @info hash', :vcr do
230
247
  size = image.info.size
@@ -237,16 +254,17 @@ describe Docker::Image do
237
254
  subject { described_class }
238
255
 
239
256
  context 'when the Image does not yet exist and the body is a Hash' do
240
- let(:image) { subject.create('fromImage' => 'ubuntu') }
257
+ let(:image) { subject.create('fromImage' => 'swipely/scratch') }
241
258
  let(:creds) {
242
259
  {
243
- :username => 'tlunter',
244
- :password => '************',
245
- :email => 'tlunter@gmail.com'
260
+ :username => ENV['DOCKER_API_USER'],
261
+ :password => ENV['DOCKER_API_PASS'],
262
+ :email => ENV['DOCKER_API_EMAIL']
246
263
  }
247
264
  }
248
265
 
249
266
  before { Docker.creds = creds }
267
+ after { image.remove(:name => 'swipely/scratch', :noprune => true) }
250
268
 
251
269
  it 'sets the id and sends Docker.creds', :vcr do
252
270
  expect(image).to be_a Docker::Image
@@ -264,7 +282,7 @@ describe Docker::Image do
264
282
  let(:image) { subject.get(image_name) }
265
283
 
266
284
  context 'when the image does exist' do
267
- let(:image_name) { 'base' }
285
+ let(:image_name) { 'debian:wheezy' }
268
286
 
269
287
  it 'returns the new image', :vcr do
270
288
  expect(image).to be_a Docker::Image
@@ -295,7 +313,7 @@ describe Docker::Image do
295
313
  let(:exists) { subject.exist?(image_name) }
296
314
 
297
315
  context 'when the image does exist' do
298
- let(:image_name) { 'base' }
316
+ let(:image_name) { 'debian:wheezy' }
299
317
 
300
318
  it 'returns true', :vcr do
301
319
  expect(exists).to eq(true)
@@ -322,6 +340,8 @@ describe Docker::Image do
322
340
  end
323
341
 
324
342
  describe '.import' do
343
+ include_context "local paths"
344
+
325
345
  subject { described_class }
326
346
 
327
347
  context 'when the file does not exist' do
@@ -334,15 +354,11 @@ describe Docker::Image do
334
354
  end
335
355
 
336
356
  context 'when the file does exist' do
337
- let(:file) { 'spec/fixtures/export.tar' }
338
- let(:body) { StringIO.new }
339
-
340
- before do
341
- allow(Docker::Image).to receive(:open).with(file).and_yield(body)
342
- end
357
+ let(:file) { File.join(project_dir, 'spec', 'fixtures', 'export.tar') }
358
+ let(:import) { subject.import(file) }
359
+ after { import.remove(:noprune => true) }
343
360
 
344
361
  it 'creates the Image', :vcr do
345
- import = subject.import(file)
346
362
  expect(import).to be_a Docker::Image
347
363
  expect(import.id).to_not be_nil
348
364
  end
@@ -357,12 +373,13 @@ describe Docker::Image do
357
373
  end
358
374
 
359
375
  context 'when the URI is valid' do
360
- let(:uri) { 'http://swipely-pub.s3.amazonaws.com/ubuntu.tar' }
376
+ let(:uri) { 'http://swipely-pub.s3.amazonaws.com/tianon_true.tar' }
377
+ let(:import) { subject.import(uri) }
378
+ after { import.remove(:noprune => true) }
361
379
 
362
380
  it 'returns an Image', :vcr do
363
- image = subject.import(uri)
364
- expect(image).to be_a Docker::Image
365
- expect(image.id).to_not be_nil
381
+ expect(import).to be_a Docker::Image
382
+ expect(import.id).to_not be_nil
366
383
  end
367
384
  end
368
385
  end
@@ -372,7 +389,7 @@ describe Docker::Image do
372
389
  subject { described_class }
373
390
 
374
391
  let(:images) { subject.all(:all => true) }
375
- before { subject.create('fromImage' => 'base') }
392
+ before { subject.create('fromImage' => 'debian:wheezy') }
376
393
 
377
394
  it 'materializes each Image into a Docker::Image', :vcr do
378
395
  images.each do |image|
@@ -412,7 +429,7 @@ describe Docker::Image do
412
429
 
413
430
  context 'with a valid Dockerfile' do
414
431
  context 'without query parameters' do
415
- let(:image) { subject.build("from base\n") }
432
+ let(:image) { subject.build("FROM debian:wheezy\n") }
416
433
 
417
434
  it 'builds an image', :vcr do
418
435
  expect(image).to be_a Docker::Image
@@ -423,25 +440,31 @@ describe Docker::Image do
423
440
 
424
441
  context 'with specifying a repo in the query parameters' do
425
442
  let(:image) {
426
- subject.build("from base\nrun true\n", "t" => "swipely/base")
443
+ subject.build(
444
+ "FROM debian:wheezy\nRUN true\n",
445
+ "t" => "#{ENV['DOCKER_API_USER']}/debian:true"
446
+ )
427
447
  }
428
- let(:images) { subject.all }
448
+ after { image.remove(:noprune => true) }
429
449
 
430
450
  it 'builds an image and tags it', :vcr do
431
451
  expect(image).to be_a Docker::Image
432
452
  expect(image.id).to_not be_nil
433
453
  expect(image.connection).to be_a Docker::Connection
434
- expect(images.first.info["RepoTags"]).to eq(["swipely/base:latest"])
454
+ image.refresh!
455
+ expect(image.info["RepoTags"]).to eq(
456
+ ["#{ENV['DOCKER_API_USER']}/debian:true"]
457
+ )
435
458
  end
436
459
  end
437
460
 
438
461
  context 'with a block capturing build output' do
439
462
  let(:build_output) { "" }
440
463
  let(:block) { Proc.new { |chunk| build_output << chunk } }
441
- let!(:image) { subject.build("FROM base\n", &block) }
464
+ let!(:image) { subject.build("FROM debian:wheezy\n", &block) }
442
465
 
443
466
  it 'calls the block and passes build output', :vcr do
444
- expect(build_output).to match(/Step 0 : FROM base/)
467
+ expect(build_output).to match(/Step 0 : FROM debian:wheezy/)
445
468
  end
446
469
  end
447
470
  end
@@ -463,20 +486,26 @@ describe Docker::Image do
463
486
  'Cmd' => %w[cat /Dockerfile])
464
487
  end
465
488
  let(:output) { container.tap(&:start)
466
- .attach(:stderr => true) }
467
- let(:images) { subject.all }
489
+ .streaming_logs(stdout: true) }
490
+ after(:each) do
491
+ container.tap(&:wait).remove
492
+ image.remove(:noprune => true)
493
+ end
468
494
 
469
495
  context 'with no query parameters' do
470
496
  it 'builds the image', :vcr do
471
- expect(output).to eq([[docker_file.read],[]])
497
+ expect(output).to eq(docker_file.read)
472
498
  end
473
499
  end
474
500
 
475
501
  context 'with specifying a repo in the query parameters' do
476
- let(:opts) { { "t" => "swipely/base2" } }
502
+ let(:opts) { { "t" => "#{ENV['DOCKER_API_USER']}/debian:from_dir" } }
477
503
  it 'builds the image and tags it', :vcr do
478
- expect(output).to eq([[docker_file.read],[]])
479
- expect(images.first.info["RepoTags"]).to eq(["swipely/base2:latest"])
504
+ expect(output).to eq(docker_file.read)
505
+ image.refresh!
506
+ expect(image.info["RepoTags"]).to eq(
507
+ ["#{ENV['DOCKER_API_USER']}/debian:from_dir"]
508
+ )
480
509
  end
481
510
  end
482
511
 
@@ -486,16 +515,16 @@ describe Docker::Image do
486
515
 
487
516
  it 'calls the block and passes build output', :vcr do
488
517
  image # Create the image variable, which is lazy-loaded by Rspec
489
- expect(build_output).to match(/Step 0 : from base/)
518
+ expect(build_output).to match(/Step 0 : FROM debian:wheezy/)
490
519
  end
491
520
  end
492
521
 
493
522
  context 'with credentials passed' do
494
523
  let(:creds) {
495
524
  {
496
- :username => 'nahiluhmot',
497
- :password => '*********',
498
- :email => 'hulihan.tom159@gmail.com',
525
+ :username => ENV['DOCKER_API_USER'],
526
+ :password => ENV['DOCKER_API_PASS'],
527
+ :email => ENV['DOCKER_API_EMAIL'],
499
528
  :serveraddress => 'https://index.docker.io/v1'
500
529
  }
501
530
  }