dockerspec 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/LICENSE +1 -1
- data/README.md +190 -24
- data/Rakefile +60 -6
- data/TODO.md +3 -2
- data/lib/dockerspec.rb +1 -2
- data/lib/dockerspec/builder.rb +13 -6
- data/lib/dockerspec/builder/config_helpers.rb +8 -3
- data/lib/dockerspec/builder/logger/ci.rb +2 -2
- data/lib/dockerspec/builder/matchers.rb +32 -51
- data/lib/dockerspec/configuration.rb +188 -0
- data/lib/dockerspec/docker_exception_parser.rb +2 -2
- data/lib/dockerspec/engine/base.rb +156 -0
- data/lib/dockerspec/engine/infrataster.rb +87 -0
- data/lib/dockerspec/engine/specinfra.rb +130 -0
- data/lib/dockerspec/engine/specinfra/backend.rb +163 -0
- data/lib/dockerspec/{serverspec/specinfra_hack.rb → engine/specinfra/backend_hack.rb} +17 -3
- data/lib/dockerspec/engine_list.rb +150 -0
- data/lib/dockerspec/exceptions.rb +13 -0
- data/lib/dockerspec/helper/multiple_sources_description.rb +3 -3
- data/lib/dockerspec/helper/rspec_example_helpers.rb +86 -6
- data/lib/dockerspec/infrataster.rb +26 -0
- data/lib/dockerspec/rspec.rb +21 -0
- data/lib/dockerspec/{rspec_configuration.rb → rspec/configuration.rb} +1 -1
- data/lib/dockerspec/rspec/resources.rb +602 -0
- data/lib/dockerspec/rspec/resources/its_container.rb +110 -0
- data/lib/dockerspec/{rspec_settings.rb → rspec/settings.rb} +5 -1
- data/lib/dockerspec/runner.rb +2 -357
- data/lib/dockerspec/runner/base.rb +367 -0
- data/lib/dockerspec/runner/compose.rb +322 -0
- data/lib/dockerspec/runner/docker.rb +302 -0
- data/lib/dockerspec/runner/serverspec.rb +21 -0
- data/lib/dockerspec/runner/serverspec/base.rb +185 -0
- data/lib/dockerspec/runner/serverspec/compose.rb +106 -0
- data/lib/dockerspec/runner/serverspec/docker.rb +116 -0
- data/lib/dockerspec/runner/serverspec/rspec.rb +20 -0
- data/lib/dockerspec/{serverspec/rspec_settings.rb → runner/serverspec/rspec/settings.rb} +1 -1
- data/lib/dockerspec/serverspec.rb +12 -2
- data/lib/dockerspec/version.rb +1 -1
- data/spec/spec_helper.rb +6 -2
- metadata +84 -15
- data/lib/dockerspec/rspec_assertions.rb +0 -54
- data/lib/dockerspec/rspec_resources.rb +0 -203
- data/lib/dockerspec/serverspec/rspec_resources.rb +0 -179
- data/lib/dockerspec/serverspec/runner.rb +0 -305
- data/lib/dockerspec/serverspec/specinfra_backend.rb +0 -128
@@ -0,0 +1,367 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author:: Xabier de Zuazo (<xabier@zuazo.org>)
|
4
|
+
# Copyright:: Copyright (c) 2016 Xabier de Zuazo
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'dockerspec/exceptions'
|
21
|
+
require 'dockerspec/engine_list'
|
22
|
+
require 'dockerspec/helper/rspec_example_helpers'
|
23
|
+
|
24
|
+
module Dockerspec
|
25
|
+
module Runner
|
26
|
+
#
|
27
|
+
# A basic class with the minimal skeleton to create a Runner: Classes to
|
28
|
+
# start docker containers.
|
29
|
+
#
|
30
|
+
class Base
|
31
|
+
#
|
32
|
+
# The option key to set when you pass a string instead of a hash of
|
33
|
+
# options.
|
34
|
+
#
|
35
|
+
OPTIONS_DEFAULT_KEY = :ignored
|
36
|
+
|
37
|
+
#
|
38
|
+
# Gets the configuration options.
|
39
|
+
#
|
40
|
+
# @return [Hash] The options.
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
attr_reader :options
|
45
|
+
|
46
|
+
#
|
47
|
+
# Constructs a runner class to run Docker images.
|
48
|
+
#
|
49
|
+
# @param opts [String, Hash] The id/name/file or a list of options.
|
50
|
+
#
|
51
|
+
# @option opts [Boolean] :rm (calculated) Whether to remove the Docker
|
52
|
+
# container afterwards.
|
53
|
+
# @option opts [Integer] :wait Time to wait before running the tests.
|
54
|
+
#
|
55
|
+
# @return [Dockerspec::Runner::Base] Runner object.
|
56
|
+
#
|
57
|
+
# @raise [Dockerspec::EngineError] Raises this exception when the engine
|
58
|
+
# list is empty.
|
59
|
+
#
|
60
|
+
# @api public
|
61
|
+
#
|
62
|
+
def initialize(*opts)
|
63
|
+
@options = parse_options(opts)
|
64
|
+
@engines = EngineList.new(self)
|
65
|
+
ObjectSpace.define_finalizer(self, proc { finalize })
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Runs the Docker Container.
|
70
|
+
#
|
71
|
+
# 1. Sets up the test context.
|
72
|
+
# 2. Runs the container (or Compose).
|
73
|
+
# 3. Saves the created underlaying test context.
|
74
|
+
# 4. Sets the container as ready.
|
75
|
+
# 5. Waits the required (configured) time after container has been
|
76
|
+
# started.
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
# builder = Dockerspec::Builder.new('.')
|
80
|
+
# builder.build
|
81
|
+
# runner = Dockerspec::Runner::Base.new(builder)
|
82
|
+
# runner.run #=> #<Dockerspec::Runner::Base:0x0123>
|
83
|
+
#
|
84
|
+
# @return [Dockerspec::Runner::Base] Runner object.
|
85
|
+
#
|
86
|
+
# @raise [Dockerspec::DockerError] For underlaying docker errors.
|
87
|
+
#
|
88
|
+
# @api public
|
89
|
+
#
|
90
|
+
def run
|
91
|
+
before_running
|
92
|
+
start_time = Time.new.utc
|
93
|
+
run_container
|
94
|
+
when_running
|
95
|
+
when_container_ready
|
96
|
+
do_wait((Time.new.utc - start_time).to_i)
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Restores the Specinfra backend instance to point to this object's
|
102
|
+
# container.
|
103
|
+
#
|
104
|
+
# This is used to avoid Serverspec running against the last started
|
105
|
+
# container if you are testing multiple containers at the same time.
|
106
|
+
#
|
107
|
+
# @return void
|
108
|
+
#
|
109
|
+
def restore_rspec_context
|
110
|
+
@engines.restore
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Gets the internal {Docker::Container} object.
|
115
|
+
#
|
116
|
+
# @return [Docker::Container] The container.
|
117
|
+
#
|
118
|
+
# @raise [Dockerspec::RunnerError] When the method is no implemented in
|
119
|
+
# the subclass.
|
120
|
+
#
|
121
|
+
# @api public
|
122
|
+
#
|
123
|
+
def container
|
124
|
+
raise RunnerError, "#{self.class}#container method must be implemented"
|
125
|
+
end
|
126
|
+
|
127
|
+
#
|
128
|
+
# Gets the container name.
|
129
|
+
#
|
130
|
+
# @return [String] Container name.
|
131
|
+
#
|
132
|
+
# @raise [Dockerspec::RunnerError] When the `#container` method is no
|
133
|
+
# implemented in the subclass or cannot select the container to test.
|
134
|
+
#
|
135
|
+
# @api public
|
136
|
+
#
|
137
|
+
def container_name
|
138
|
+
container.json['Name']
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
# Gets the Docker container ID.
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# builder = Dockerspec::Builder.new('.').build
|
146
|
+
# runner = Dockerspec::Runner::Base.new(builder).run
|
147
|
+
# runner.id #=> "b8ba0befc716[...]"
|
148
|
+
#
|
149
|
+
# @return [String] Container ID.
|
150
|
+
#
|
151
|
+
# @raise [Dockerspec::RunnerError] When the `#container` method is no
|
152
|
+
# implemented in the subclass or cannot select the container to test.
|
153
|
+
#
|
154
|
+
# @api public
|
155
|
+
#
|
156
|
+
def id
|
157
|
+
return nil unless container.respond_to?(:id)
|
158
|
+
container.id
|
159
|
+
end
|
160
|
+
|
161
|
+
#
|
162
|
+
# Gets the Docker image ID.
|
163
|
+
#
|
164
|
+
# @return [String] Image ID.
|
165
|
+
#
|
166
|
+
# @raise [Dockerspec::RunnerError] When the `#container` method is no
|
167
|
+
# implemented in the subclass or cannot select the container to test.
|
168
|
+
#
|
169
|
+
# @api public
|
170
|
+
#
|
171
|
+
def image_id
|
172
|
+
container.json['Image']
|
173
|
+
end
|
174
|
+
|
175
|
+
#
|
176
|
+
# Gets the Docker Container IP address.
|
177
|
+
#
|
178
|
+
# This is used by {Dockerspec::Engine::Infrataster}.
|
179
|
+
#
|
180
|
+
# @return [String] IP address.
|
181
|
+
#
|
182
|
+
# @raise [Dockerspec::RunnerError] When the `#container` method is no
|
183
|
+
# implemented in the subclass or cannot select the container to test.
|
184
|
+
#
|
185
|
+
# @api public
|
186
|
+
#
|
187
|
+
def ipaddress
|
188
|
+
container.json['NetworkSettings']['IPAddress']
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# Stops and deletes the Docker Container.
|
193
|
+
#
|
194
|
+
# Automatically called when `:rm` option is enabled.
|
195
|
+
#
|
196
|
+
# @return void
|
197
|
+
#
|
198
|
+
# @api public
|
199
|
+
#
|
200
|
+
def finalize
|
201
|
+
return if options[:rm] == false || container.nil?
|
202
|
+
container.stop
|
203
|
+
container.delete
|
204
|
+
end
|
205
|
+
|
206
|
+
protected
|
207
|
+
|
208
|
+
#
|
209
|
+
# Sets up the context just before starting the docker container.
|
210
|
+
#
|
211
|
+
# @return void
|
212
|
+
#
|
213
|
+
# @api public
|
214
|
+
#
|
215
|
+
def before_running
|
216
|
+
@engines.before_running
|
217
|
+
end
|
218
|
+
|
219
|
+
#
|
220
|
+
# Saves the context after starting the docker container.
|
221
|
+
#
|
222
|
+
# @return void
|
223
|
+
#
|
224
|
+
# @api public
|
225
|
+
#
|
226
|
+
def when_running
|
227
|
+
@engines.when_running
|
228
|
+
end
|
229
|
+
|
230
|
+
#
|
231
|
+
# Notifies the engines that the container to test is selected and ready.
|
232
|
+
#
|
233
|
+
# @return void
|
234
|
+
#
|
235
|
+
# @api public
|
236
|
+
#
|
237
|
+
def when_container_ready
|
238
|
+
@engines.when_container_ready
|
239
|
+
end
|
240
|
+
|
241
|
+
#
|
242
|
+
# Gets the default options configured using `RSpec.configuration`.
|
243
|
+
#
|
244
|
+
# @example
|
245
|
+
# self.rspec_options #=> {}
|
246
|
+
#
|
247
|
+
# @return [Hash] The configuration options.
|
248
|
+
#
|
249
|
+
# @api private
|
250
|
+
#
|
251
|
+
def rspec_options
|
252
|
+
config = ::RSpec.configuration
|
253
|
+
{}.tap do |opts|
|
254
|
+
opts[:wait] = config.docker_wait if config.docker_wait?
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
#
|
259
|
+
# The option key to set when you pass a string instead of a hash of
|
260
|
+
# options.
|
261
|
+
#
|
262
|
+
# @return [Symbol] The key name.
|
263
|
+
#
|
264
|
+
# @api private
|
265
|
+
#
|
266
|
+
def options_default_key
|
267
|
+
self.class::OPTIONS_DEFAULT_KEY
|
268
|
+
end
|
269
|
+
|
270
|
+
#
|
271
|
+
# Gets the default configuration options after merging them with RSpec
|
272
|
+
# configuration options.
|
273
|
+
#
|
274
|
+
# @example
|
275
|
+
# self.default_options #=> {}
|
276
|
+
#
|
277
|
+
# @return [Hash] The configuration options.
|
278
|
+
#
|
279
|
+
# @api private
|
280
|
+
#
|
281
|
+
def default_options
|
282
|
+
{}.merge(rspec_options)
|
283
|
+
end
|
284
|
+
|
285
|
+
#
|
286
|
+
# Ensures that the passed options are correct.
|
287
|
+
#
|
288
|
+
# Does nothing. Must be implemented in subclasses.
|
289
|
+
#
|
290
|
+
# @return void
|
291
|
+
#
|
292
|
+
# @api private
|
293
|
+
#
|
294
|
+
def assert_options!(opts); end
|
295
|
+
|
296
|
+
#
|
297
|
+
# Parses the configuration options passed to the constructor.
|
298
|
+
#
|
299
|
+
# @example
|
300
|
+
# self.parse_options #=> {:rm=>true, :file=> "docker-compose.yml"}
|
301
|
+
#
|
302
|
+
# @param opts [Array<String, Hash>] The list of options. The strings will
|
303
|
+
# be interpreted as `default_opt` key value, others will be merged.
|
304
|
+
#
|
305
|
+
# @return [Hash] The configuration options.
|
306
|
+
#
|
307
|
+
# @raise [Dockerspec::DockerRunArgumentError] Raises this exception when
|
308
|
+
# some required fields are missing.
|
309
|
+
#
|
310
|
+
# @see #initialize
|
311
|
+
#
|
312
|
+
# @api private
|
313
|
+
#
|
314
|
+
def parse_options(opts)
|
315
|
+
opts_hs_ary = opts.map do |x|
|
316
|
+
x.is_a?(Hash) ? x : { options_default_key => x }
|
317
|
+
end
|
318
|
+
result = opts_hs_ary.reduce(default_options) { |a, e| a.merge(e) }
|
319
|
+
assert_options!(result)
|
320
|
+
result
|
321
|
+
end
|
322
|
+
|
323
|
+
#
|
324
|
+
# Starts the Docker container.
|
325
|
+
#
|
326
|
+
# @return void
|
327
|
+
#
|
328
|
+
# @raise [Dockerspec::RunnerError] When the `#container` method is no
|
329
|
+
# implemented in the subclass.
|
330
|
+
#
|
331
|
+
# @api private
|
332
|
+
#
|
333
|
+
def run_container
|
334
|
+
container.start
|
335
|
+
end
|
336
|
+
|
337
|
+
#
|
338
|
+
# Sleeps for some time if required.
|
339
|
+
#
|
340
|
+
# Reads the seconds to sleep from the `:docker_wait` or `:wait`
|
341
|
+
# configuration option.
|
342
|
+
#
|
343
|
+
# @param waited [Integer] The time already waited.
|
344
|
+
#
|
345
|
+
# @return nil
|
346
|
+
#
|
347
|
+
# @api private
|
348
|
+
#
|
349
|
+
def do_wait(waited)
|
350
|
+
wait = options[:wait]
|
351
|
+
return unless wait.is_a?(Integer) || wait.is_a?(Float)
|
352
|
+
return if waited >= wait
|
353
|
+
sleep(wait - waited)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
#
|
360
|
+
# Restore Specinfra backend:
|
361
|
+
#
|
362
|
+
RSpec.configure do |c|
|
363
|
+
c.before(:each) do
|
364
|
+
metadata = RSpec.current_example.metadata
|
365
|
+
Dockerspec::Helper::RSpecExampleHelpers.restore_rspec_context(metadata)
|
366
|
+
end
|
367
|
+
end
|
@@ -0,0 +1,322 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author:: Xabier de Zuazo (<xabier@zuazo.org>)
|
4
|
+
# Copyright:: Copyright (c) 2016 Xabier de Zuazo
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'docker-compose'
|
21
|
+
require 'dockerspec/exceptions'
|
22
|
+
require 'dockerspec/helper/multiple_sources_description'
|
23
|
+
require 'dockerspec/runner/base'
|
24
|
+
|
25
|
+
module Dockerspec
|
26
|
+
module Runner
|
27
|
+
#
|
28
|
+
# This class runs Docker Compose (without using Serverspec for that).
|
29
|
+
#
|
30
|
+
# This class is used mainly when you are not using Serverspec to run the
|
31
|
+
# tests.
|
32
|
+
#
|
33
|
+
class Compose < Base
|
34
|
+
class << self
|
35
|
+
#
|
36
|
+
# Saves the latest created {Dockerspec::Runner::Compose} object.
|
37
|
+
#
|
38
|
+
# @return [Docker::Runner::Compose::Base] The saved instance.
|
39
|
+
#
|
40
|
+
# @api public
|
41
|
+
#
|
42
|
+
attr_accessor :current_instance
|
43
|
+
end
|
44
|
+
|
45
|
+
include Dockerspec::Helper::MultipleSourcesDescription
|
46
|
+
|
47
|
+
#
|
48
|
+
# @return [Symbol] The option key to set when you pass a string instead
|
49
|
+
# of a hash of options.
|
50
|
+
#
|
51
|
+
OPTIONS_DEFAULT_KEY = :file
|
52
|
+
|
53
|
+
#
|
54
|
+
# The internal {DockerCompose} object.
|
55
|
+
#
|
56
|
+
# @return [DockerCompose] The compose object.
|
57
|
+
#
|
58
|
+
attr_reader :compose
|
59
|
+
|
60
|
+
#
|
61
|
+
# Constructs a runner class to run Docker Compose.
|
62
|
+
#
|
63
|
+
# @example From a Directory
|
64
|
+
# Dockerspec::Runner::Compose.new('directory1')
|
65
|
+
# #=> #<Dockerspec::Runner::Compose:0x0124>
|
66
|
+
#
|
67
|
+
# @example From a YAML File
|
68
|
+
# Dockerspec::Runner::Compose.new('data/docker-compose.yml')
|
69
|
+
# #=> #<Dockerspec::Runner::Compose:0x0124>
|
70
|
+
#
|
71
|
+
# @example From a Directory or File Using Hash Format
|
72
|
+
# Dockerspec::Runner::Compose.new(file: 'file.yml')
|
73
|
+
# #=> #<Dockerspec::Runner::Compose:0x0124>
|
74
|
+
#
|
75
|
+
# @param opts [String, Hash] The `:file` or a list of options.
|
76
|
+
#
|
77
|
+
# @option opts [String] :file The compose YAML file or a directory
|
78
|
+
# containing the `'docker-compose.yml'` file.
|
79
|
+
# @option opts [Boolean] :rm (calculated) Whether to remove the Docker
|
80
|
+
# @option opts [Integer] :wait Time to wait before running the tests.
|
81
|
+
#
|
82
|
+
# @return [Dockerspec::Runner::Compose] Runner object.
|
83
|
+
#
|
84
|
+
# @raise [Dockerspec::DockerRunArgumentError] Raises this exception when
|
85
|
+
# some required options are missing.
|
86
|
+
#
|
87
|
+
# @api public
|
88
|
+
#
|
89
|
+
def initialize(*opts)
|
90
|
+
Compose.current_instance = self
|
91
|
+
@container_options = {}
|
92
|
+
super
|
93
|
+
setup_from_file(file)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Does not call ready because container is still not ready.
|
97
|
+
#
|
98
|
+
# Runs the Docker Container.
|
99
|
+
#
|
100
|
+
# 1. Sets up the test context.
|
101
|
+
# 2. Runs the container (or Compose).
|
102
|
+
# 3. Saves the created underlaying test context.
|
103
|
+
#
|
104
|
+
# @return [Dockerspec::Runner::Compose] Runner object.
|
105
|
+
#
|
106
|
+
# @raise [Dockerspec::DockerError] For underlaying docker errors.
|
107
|
+
#
|
108
|
+
# @see #select_conainer
|
109
|
+
#
|
110
|
+
# @api public
|
111
|
+
#
|
112
|
+
def run
|
113
|
+
before_running
|
114
|
+
start_time = Time.new.utc
|
115
|
+
run_container
|
116
|
+
when_running
|
117
|
+
do_wait((Time.new.utc - start_time).to_i)
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Selects the container to test and sets its configuration options.
|
123
|
+
#
|
124
|
+
# Also sets the selected container as ready in the underlaying test
|
125
|
+
# engines.
|
126
|
+
#
|
127
|
+
# @param name [Symbol, String] The container name.
|
128
|
+
#
|
129
|
+
# @param opts [Hash] Container configuration options.
|
130
|
+
#
|
131
|
+
# @return void
|
132
|
+
#
|
133
|
+
# @api public
|
134
|
+
#
|
135
|
+
def select_container(name, opts = nil)
|
136
|
+
@options[:container] = name
|
137
|
+
@container_options[name] = @options.merge(opts) if opts.is_a?(Hash)
|
138
|
+
when_container_ready
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
# Returns general and container specific options merged.
|
143
|
+
#
|
144
|
+
# @return void
|
145
|
+
#
|
146
|
+
# @api private
|
147
|
+
#
|
148
|
+
def options
|
149
|
+
container_name = @options[:container]
|
150
|
+
@container_options[container_name] || @options
|
151
|
+
end
|
152
|
+
|
153
|
+
#
|
154
|
+
# Gets the selected container name.
|
155
|
+
#
|
156
|
+
# @return [String, nil] The container name.
|
157
|
+
#
|
158
|
+
# @api private
|
159
|
+
#
|
160
|
+
def container_name
|
161
|
+
return nil if @options[:container].nil?
|
162
|
+
@options[:container].to_s
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Gets the selected container object.
|
167
|
+
#
|
168
|
+
# This method is used in {Dockerspec::Runner::Base} to get information
|
169
|
+
# from the container: ID, image ID, ...
|
170
|
+
#
|
171
|
+
# @return [Docker::Container] The container object.
|
172
|
+
#
|
173
|
+
# @raise [Dockerspec::RunnerError] When cannot select the container to
|
174
|
+
# test.
|
175
|
+
#
|
176
|
+
# @api public
|
177
|
+
#
|
178
|
+
def container
|
179
|
+
if container_name.nil?
|
180
|
+
raise RunnerError,
|
181
|
+
'Use `its_container` to select a container to test.'
|
182
|
+
end
|
183
|
+
compose_container = compose.containers[container_name]
|
184
|
+
if compose_container.nil?
|
185
|
+
raise RunnerError, "Container not found: #{compose_container.inspect}"
|
186
|
+
end
|
187
|
+
compose_container.container
|
188
|
+
end
|
189
|
+
|
190
|
+
#
|
191
|
+
# Gets a descriptions of the object.
|
192
|
+
#
|
193
|
+
# @example Running from a Compose File
|
194
|
+
# r = Dockerspec::Runner::Compose.new('docker-compose.yml')
|
195
|
+
# r.to_s #=> "Docker Compose Run from file: \"docker-compose.yml\""
|
196
|
+
#
|
197
|
+
# @example Running from a Compose Directory
|
198
|
+
# r = Dockerspec::Runner::Compose.new('docker_images')
|
199
|
+
# r.to_s #=> "Docker Compose Run from file: "\
|
200
|
+
# # "\"docker_images/docker-compose.yml\""
|
201
|
+
#
|
202
|
+
# @return [String] The object description.
|
203
|
+
#
|
204
|
+
# @api public
|
205
|
+
#
|
206
|
+
def to_s
|
207
|
+
description('Docker Compose Run from')
|
208
|
+
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Stops and deletes the Docker Compose containers.
|
212
|
+
#
|
213
|
+
# Automatically called when `:rm` option is enabled.
|
214
|
+
#
|
215
|
+
# @return void
|
216
|
+
#
|
217
|
+
# @api public
|
218
|
+
#
|
219
|
+
def finalize
|
220
|
+
return if options[:rm] == false || compose.nil?
|
221
|
+
compose.stop
|
222
|
+
compose.delete
|
223
|
+
end
|
224
|
+
|
225
|
+
protected
|
226
|
+
|
227
|
+
#
|
228
|
+
# Gets the full path of the Docker Compose YAML file.
|
229
|
+
#
|
230
|
+
# It adds `'docker-compose.yml'` if you pass a directory.
|
231
|
+
#
|
232
|
+
# @return [String] The file path.
|
233
|
+
#
|
234
|
+
# @api private
|
235
|
+
#
|
236
|
+
def file
|
237
|
+
@file ||=
|
238
|
+
if File.directory?(options[source])
|
239
|
+
File.join(options[source], 'docker-compose.yml')
|
240
|
+
else
|
241
|
+
options[source]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
#
|
246
|
+
# Gets the source to start the container from.
|
247
|
+
#
|
248
|
+
# Possible values: `:file`.
|
249
|
+
#
|
250
|
+
# @example Start the Container from a YAML Configuration File
|
251
|
+
# self.source #=> :file
|
252
|
+
#
|
253
|
+
# @return [Symbol] The source.
|
254
|
+
#
|
255
|
+
# @api private
|
256
|
+
#
|
257
|
+
def source
|
258
|
+
return @source unless @source.nil?
|
259
|
+
@source = %i(file).find { |from| options.key?(from) }
|
260
|
+
end
|
261
|
+
|
262
|
+
#
|
263
|
+
# Gets the default options configured using `RSpec.configuration`.
|
264
|
+
#
|
265
|
+
# @example
|
266
|
+
# self.rspec_options #=> {:container => "webapp", :docker_wait => 30}
|
267
|
+
#
|
268
|
+
# @return [Hash] The configuration options.
|
269
|
+
#
|
270
|
+
# @api private
|
271
|
+
#
|
272
|
+
def rspec_options
|
273
|
+
config = ::RSpec.configuration
|
274
|
+
super.tap do |opts|
|
275
|
+
opts[:container] = config.container_name if config.container_name?
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
#
|
280
|
+
# Ensures that the passed options are correct.
|
281
|
+
#
|
282
|
+
# Currently this only checks that you passed the `:file` argument.
|
283
|
+
#
|
284
|
+
# @return void
|
285
|
+
#
|
286
|
+
# @raise [Dockerspec::DockerRunArgumentError] Raises this exception when
|
287
|
+
# the required fields are missing.
|
288
|
+
#
|
289
|
+
# @api private
|
290
|
+
#
|
291
|
+
def assert_options!(opts)
|
292
|
+
return if opts[:file].is_a?(String)
|
293
|
+
raise DockerRunArgumentError, 'You need to pass the `:file` option '\
|
294
|
+
'to the #docker_compose method.'
|
295
|
+
end
|
296
|
+
|
297
|
+
#
|
298
|
+
# Saves the build internally.
|
299
|
+
#
|
300
|
+
# @param file [String] The configuration file.
|
301
|
+
#
|
302
|
+
# @return void
|
303
|
+
#
|
304
|
+
# @api private
|
305
|
+
#
|
306
|
+
def setup_from_file(file)
|
307
|
+
@compose = ::DockerCompose.load(file)
|
308
|
+
end
|
309
|
+
|
310
|
+
#
|
311
|
+
# Runs Docker Compose.
|
312
|
+
#
|
313
|
+
# @return void
|
314
|
+
#
|
315
|
+
# @api private
|
316
|
+
#
|
317
|
+
def run_container
|
318
|
+
Dir.chdir(::File.dirname(file)) { compose.start }
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|