dockerspec 0.2.0 → 0.3.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.
- 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
|