testcontainers-core 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -3
- data/Gemfile.lock +1 -1
- data/README.md +2 -2
- data/lib/testcontainers/docker_container.rb +167 -7
- data/lib/testcontainers/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd1ecb046574448907ac650c801eda4e7dad34055c6a61fa06a0f066067e2b97
|
4
|
+
data.tar.gz: f9c49b86765f2166cf2460bef0899ba40a1b822bdf23451bbe1a3e68531606e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6dfd296c157b51d3429f0c470e5ee1a46d15de6c47b1d417045260c55fed5482e8562a6bc8ac689254fc80a835dff36a0b2af26d6a5f11e75e162f546d15233
|
7
|
+
data.tar.gz: 77ed8e5fe3cc9df35744fdeccebb9cef54a3a359aa36afe90e0f9dcbd3375a16411db5132590746084c89c3f091b42eb021b033e9d4dce184a12de9499563b4f
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,27 @@
|
|
1
|
+
## [0.1.3] - 2023-06-10
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
- Support for entrypoint customization and the DockerContainer#with_entrypoint method
|
6
|
+
|
7
|
+
- Methods to read/write strings from and to containers: read_file, store_file
|
8
|
+
|
9
|
+
- Methods to copy files from and to containers: copy_file_from_container, copy_file_to_container
|
10
|
+
|
11
|
+
- Support for waiting strategies on start
|
12
|
+
|
13
|
+
- DockerContainer#with_exposed_port (singular) for convenience
|
14
|
+
|
15
|
+
- GenericContainer as alias for DockerContainer
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
|
19
|
+
- DockerContainer#add_exposed_ports don't override PortBinding settings added by #add_fixed_exposed_port
|
20
|
+
|
21
|
+
|
1
22
|
## [0.1.2] - 2023-05-13
|
2
23
|
|
3
|
-
|
24
|
+
### Added
|
4
25
|
|
5
26
|
- DockerContainer#first_mapped_port method returns the first of the
|
6
27
|
mapped ports for convenience.
|
@@ -13,11 +34,11 @@
|
|
13
34
|
|
14
35
|
redis_container.with_healthcheck(test: ["redis-cli ping"], interval: 30, timeout: 30, retries: 3)
|
15
36
|
|
16
|
-
|
37
|
+
### Changed
|
17
38
|
|
18
39
|
- DockerContainer#mapped_port(port) method now returns an Integer instead of a String.
|
19
40
|
|
20
|
-
|
41
|
+
### Fixed
|
21
42
|
|
22
43
|
- Links to the GitHub project on the README.md file are fixed.
|
23
44
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -28,7 +28,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
28
28
|
|
29
29
|
## Contributing
|
30
30
|
|
31
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
31
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/testcontainers/testcontainers-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/testcontainers/testcontainers-ruby/blob/main/CODE_OF_CONDUCT.md).
|
32
32
|
|
33
33
|
## License
|
34
34
|
|
@@ -36,4 +36,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
36
36
|
|
37
37
|
## Code of Conduct
|
38
38
|
|
39
|
-
Everyone interacting in the Testcontainers project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
39
|
+
Everyone interacting in the Testcontainers project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/testcontainers/testcontainers-ruby/blob/main/CODE_OF_CONDUCT.md).
|
@@ -6,6 +6,7 @@ module Testcontainers
|
|
6
6
|
# @attr name [String] the container's name
|
7
7
|
# @attr image [String] the container's image name
|
8
8
|
# @attr command [Array<String>, nil] the command to run in the container
|
9
|
+
# @attr entrypoint [Array<String>, nil] the entrypoint to run in the container
|
9
10
|
# @attr exposed_ports [Hash, nil] a hash mapping exposed container ports to an empty hash (used for Docker API compatibility)
|
10
11
|
# @attr port_bindings [Hash, nil] a hash mapping container ports to host port bindings (used for Docker API compatibility)
|
11
12
|
# @attr volumes [Hash, nil] a hash mapping volume paths in the container to an empty hash (used for Docker API compatibility)
|
@@ -18,7 +19,8 @@ module Testcontainers
|
|
18
19
|
# @attr_reader _container [Docker::Container, nil] the underlying Docker::Container object
|
19
20
|
# @attr_reader _id [String, nil] the container's ID
|
20
21
|
class DockerContainer
|
21
|
-
attr_accessor :name, :image, :command, :exposed_ports, :port_bindings, :volumes, :filesystem_binds,
|
22
|
+
attr_accessor :name, :image, :command, :entrypoint, :exposed_ports, :port_bindings, :volumes, :filesystem_binds,
|
23
|
+
:env, :labels, :working_dir, :healthcheck, :wait_for
|
22
24
|
attr_accessor :logger
|
23
25
|
attr_reader :_container, :_id
|
24
26
|
|
@@ -35,12 +37,13 @@ module Testcontainers
|
|
35
37
|
# @param labels [Hash, nil] a hash of labels to be applied to the container
|
36
38
|
# @param working_dir [String, nil] the working directory for the container
|
37
39
|
# @param logger [Logger] a logger instance for the container
|
38
|
-
def initialize(image, command: nil,
|
39
|
-
labels: nil, working_dir: nil, healthcheck: nil, logger: Testcontainers.logger)
|
40
|
+
def initialize(image, name: nil, command: nil, entrypoint: nil, exposed_ports: nil, port_bindings: nil, volumes: nil, filesystem_binds: nil,
|
41
|
+
env: nil, labels: nil, working_dir: nil, healthcheck: nil, wait_for: nil, logger: Testcontainers.logger)
|
40
42
|
|
41
43
|
@image = image
|
42
|
-
@command = command
|
43
44
|
@name = name
|
45
|
+
@command = command
|
46
|
+
@entrypoint = entrypoint
|
44
47
|
@exposed_ports = add_exposed_ports(exposed_ports) if exposed_ports
|
45
48
|
@port_bindings = add_fixed_exposed_ports(port_bindings) if port_bindings
|
46
49
|
@volumes = add_volumes(volumes) if volumes
|
@@ -49,6 +52,7 @@ module Testcontainers
|
|
49
52
|
@labels = add_labels(labels) if labels
|
50
53
|
@working_dir = working_dir
|
51
54
|
@healthcheck = add_healthcheck(healthcheck) if healthcheck
|
55
|
+
@wait_for = add_wait_for(wait_for)
|
52
56
|
@logger = logger
|
53
57
|
@_container = nil
|
54
58
|
@_id = nil
|
@@ -78,8 +82,8 @@ module Testcontainers
|
|
78
82
|
port = normalize_port(port)
|
79
83
|
@exposed_ports ||= {}
|
80
84
|
@port_bindings ||= {}
|
81
|
-
@exposed_ports[port]
|
82
|
-
@port_bindings[port]
|
85
|
+
@exposed_ports[port] ||= {}
|
86
|
+
@port_bindings[port] ||= [{"HostPort" => ""}]
|
83
87
|
@exposed_ports
|
84
88
|
end
|
85
89
|
|
@@ -242,6 +246,51 @@ module Testcontainers
|
|
242
246
|
}
|
243
247
|
end
|
244
248
|
|
249
|
+
# Add a wait_for strategy to the container configuration.
|
250
|
+
#
|
251
|
+
# @param method [Symbol, String, Proc, Array] The method to call on the container to wait for it to be ready.
|
252
|
+
# @param args [Array] The arguments to pass to the method if it is a symbol or string.
|
253
|
+
# @param kwargs [Hash] The keyword arguments to pass to the method if it is a symbol or string.
|
254
|
+
# @param block [Proc] The block to call on the container to wait for it to be ready.
|
255
|
+
# @return [Proc] The wait_for strategy.
|
256
|
+
def add_wait_for(method = nil, *args, **kwargs, &block)
|
257
|
+
if method.nil?
|
258
|
+
if block
|
259
|
+
if block.arity == 1
|
260
|
+
@wait_for = block
|
261
|
+
else
|
262
|
+
raise ArgumentError, "Invalid wait_for block: #{block}"
|
263
|
+
end
|
264
|
+
elsif @exposed_ports && !@exposed_ports.empty?
|
265
|
+
port = @exposed_ports.keys.first.split("/").first
|
266
|
+
@wait_for = ->(container) { container.wait_for_tcp_port(port) }
|
267
|
+
end
|
268
|
+
elsif method.is_a?(Proc)
|
269
|
+
if method.arity == 1
|
270
|
+
@wait_for = method
|
271
|
+
else
|
272
|
+
raise ArgumentError, "Invalid wait_for method: #{method}"
|
273
|
+
end
|
274
|
+
elsif method.is_a?(Array)
|
275
|
+
method_name = "wait_for_#{method[0]}".to_sym
|
276
|
+
args = method[1] || []
|
277
|
+
kwargs = method[2] || {}
|
278
|
+
if respond_to?(method_name)
|
279
|
+
@wait_for = ->(container) { container.send(method_name, *args, **kwargs) }
|
280
|
+
else
|
281
|
+
raise ArgumentError, "Invalid wait_for method: #{method_name}"
|
282
|
+
end
|
283
|
+
else
|
284
|
+
method_name = "wait_for_#{method}".to_sym
|
285
|
+
if respond_to?(method_name)
|
286
|
+
@wait_for = ->(container) { container.send(method_name, *args, **kwargs) }
|
287
|
+
else
|
288
|
+
raise ArgumentError, "Invalid wait_for method: #{method_name}"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
@wait_for
|
292
|
+
end
|
293
|
+
|
245
294
|
# Set options for the container configuration using "with_" methods.
|
246
295
|
#
|
247
296
|
# @param options [Hash] A hash of options where keys correspond to "with_" methods and values are the arguments for those methods.
|
@@ -269,6 +318,16 @@ module Testcontainers
|
|
269
318
|
self
|
270
319
|
end
|
271
320
|
|
321
|
+
# Set the entrypoint for the container.
|
322
|
+
#
|
323
|
+
# @param parts [Array<String>] The entry point for the container as an array of strings.
|
324
|
+
# @return [DockerContainer] The updated DockerContainer instance.
|
325
|
+
def with_entrypoint(*parts)
|
326
|
+
@entrypoint = parts.first.is_a?(Array) ? parts.first : parts
|
327
|
+
|
328
|
+
self
|
329
|
+
end
|
330
|
+
|
272
331
|
# Set the name of the container.
|
273
332
|
#
|
274
333
|
# @param name [String] The name of the container.
|
@@ -309,6 +368,15 @@ module Testcontainers
|
|
309
368
|
self
|
310
369
|
end
|
311
370
|
|
371
|
+
# Adds a single exposed port to the container.
|
372
|
+
#
|
373
|
+
# @param port [String, Integer] The port to expose.
|
374
|
+
# @return [DockerContainer] The updated DockerContainer instance.
|
375
|
+
def with_exposed_port(port)
|
376
|
+
add_exposed_ports(port)
|
377
|
+
self
|
378
|
+
end
|
379
|
+
|
312
380
|
# Adds a fixed exposed port to the container.
|
313
381
|
#
|
314
382
|
# @param container_port [String, Integer, Hash] The container port in the format "port/protocol" or as an integer.
|
@@ -373,6 +441,18 @@ module Testcontainers
|
|
373
441
|
self
|
374
442
|
end
|
375
443
|
|
444
|
+
# Add a wait_for strategy to the container configuration.
|
445
|
+
#
|
446
|
+
# @param method [Symbol, String, Proc, Array] The method to call on the container to wait for it to be ready.
|
447
|
+
# @param args [Array] The arguments to pass to the method if it is a symbol or string.
|
448
|
+
# @param kwargs [Hash] The keyword arguments to pass to the method if it is a symbol or string.
|
449
|
+
# @param block [Proc] The block to call on the container to wait for it to be ready.
|
450
|
+
# @return [DockerContainer] The updated DockerContainer instance.
|
451
|
+
def with_wait_for(method = nil, *args, **kwargs, &block)
|
452
|
+
add_wait_for(method, *args, **kwargs, &block)
|
453
|
+
self
|
454
|
+
end
|
455
|
+
|
376
456
|
# Starts the container, yields the container instance to the block, and stops the container.
|
377
457
|
#
|
378
458
|
# @yield [DockerContainer] The container instance.
|
@@ -396,10 +476,11 @@ module Testcontainers
|
|
396
476
|
|
397
477
|
@_id = @_container.id
|
398
478
|
json = @_container.json
|
399
|
-
|
400
479
|
@name = json["Name"]
|
401
480
|
@_created_at = json["Created"]
|
402
481
|
|
482
|
+
@wait_for&.call(self)
|
483
|
+
|
403
484
|
self
|
404
485
|
rescue Excon::Error::Socket => e
|
405
486
|
raise ConnectionError, e.message
|
@@ -810,6 +891,81 @@ module Testcontainers
|
|
810
891
|
File.exist?("/.dockerenv")
|
811
892
|
end
|
812
893
|
|
894
|
+
# Copies a IO object or a file from the host to the container.
|
895
|
+
#
|
896
|
+
# @param container_path [String] The path to the file inside the container.
|
897
|
+
# @param host_path_or_io [String, IO] The path to the file on the host or a IO object.
|
898
|
+
# @raise [ContainerNotStartedError] If the container has not been started.
|
899
|
+
# @raise [ConnectionError] If the connection to the Docker daemon fails.
|
900
|
+
# @return [self]
|
901
|
+
def copy_file_to_container(container_path, host_path_or_io)
|
902
|
+
raise ContainerNotStartedError, "Container has not been started" unless running?
|
903
|
+
raise ArgumentError, "Container path must be a non-empty string" if container_path.to_s.empty?
|
904
|
+
|
905
|
+
begin
|
906
|
+
io = host_path_or_io.is_a?(String) ? File.open(host_path_or_io) : host_path_or_io
|
907
|
+
io.rewind if io.pos != 0
|
908
|
+
store_file(container_path, io.read)
|
909
|
+
io.rewind
|
910
|
+
rescue => e
|
911
|
+
puts "Error while copying file to container: #{e.message}"
|
912
|
+
return false
|
913
|
+
ensure
|
914
|
+
io.close if io.respond_to?(:close)
|
915
|
+
end
|
916
|
+
|
917
|
+
true
|
918
|
+
end
|
919
|
+
|
920
|
+
# Copies a file from the container to the host.
|
921
|
+
#
|
922
|
+
# @param container_path [String] The path to the file inside the container.
|
923
|
+
# @param host_path_or_io [String, IO] The path to the file on the host or a IO object.
|
924
|
+
# @raise [ContainerNotStartedError] If the container has not been started.
|
925
|
+
# @raise [ConnectionError] If the connection to the Docker daemon fails.
|
926
|
+
# @return [String] The contents of the file inside the container.
|
927
|
+
def copy_file_from_container(container_path, host_path_or_io)
|
928
|
+
raise ContainerNotStartedError, "Container has not been started" unless running?
|
929
|
+
raise ArgumentError, "Container path must be a non-empty string" if container_path.to_s.empty?
|
930
|
+
|
931
|
+
begin
|
932
|
+
io = host_path_or_io.is_a?(String) ? File.open(host_path_or_io, "w") : host_path_or_io
|
933
|
+
io.rewind if io.pos != 0
|
934
|
+
content = read_file(container_path)
|
935
|
+
io.write(content)
|
936
|
+
io.rewind
|
937
|
+
rescue => e
|
938
|
+
puts "Error while copying file from container: #{e.message}"
|
939
|
+
raise e # Optionally re-raise the exception or handle it according to your needs
|
940
|
+
ensure
|
941
|
+
io.close if io.respond_to?(:close)
|
942
|
+
end
|
943
|
+
|
944
|
+
content
|
945
|
+
end
|
946
|
+
|
947
|
+
# Reads the contents of a file inside the container.
|
948
|
+
#
|
949
|
+
# @param path [String] The path to the file.
|
950
|
+
# @return [String] The contents of the file.
|
951
|
+
def read_file(path)
|
952
|
+
raise ContainerNotStartedError unless @_container
|
953
|
+
|
954
|
+
@_container.read_file(path)
|
955
|
+
end
|
956
|
+
|
957
|
+
# Writes the contents of a file inside the container.
|
958
|
+
#
|
959
|
+
# @param path [String] The path to the file.
|
960
|
+
# @param contents [String] The contents of the file.
|
961
|
+
# @raise [ContainerNotStartedError] If the container has not been started.
|
962
|
+
# @raise [ConnectionError] If the connection to the Docker daemon fails.
|
963
|
+
def store_file(path, contents)
|
964
|
+
raise ContainerNotStartedError unless @_container
|
965
|
+
|
966
|
+
@_container.store_file(path, contents)
|
967
|
+
end
|
968
|
+
|
813
969
|
private
|
814
970
|
|
815
971
|
def normalize_ports(ports)
|
@@ -937,6 +1093,7 @@ module Testcontainers
|
|
937
1093
|
"name" => @name,
|
938
1094
|
"Image" => @image,
|
939
1095
|
"Cmd" => @command,
|
1096
|
+
"Entrypoint" => @entrypoint,
|
940
1097
|
"ExposedPorts" => @exposed_ports,
|
941
1098
|
"Volumes" => @volumes,
|
942
1099
|
"Env" => @env,
|
@@ -950,4 +1107,7 @@ module Testcontainers
|
|
950
1107
|
}.compact
|
951
1108
|
end
|
952
1109
|
end
|
1110
|
+
|
1111
|
+
# Alias for forward-compatibility
|
1112
|
+
GenericContainer = DockerContainer
|
953
1113
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: testcontainers-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guillermo Iguaran
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: docker-api
|
@@ -98,13 +98,13 @@ files:
|
|
98
98
|
- lib/testcontainers.rb
|
99
99
|
- lib/testcontainers/docker_container.rb
|
100
100
|
- lib/testcontainers/version.rb
|
101
|
-
homepage: https://github.com/
|
101
|
+
homepage: https://github.com/testcontainers/testcontainers-ruby
|
102
102
|
licenses:
|
103
103
|
- MIT
|
104
104
|
metadata:
|
105
|
-
homepage_uri: https://github.com/
|
106
|
-
source_code_uri: https://github.com/
|
107
|
-
changelog_uri: https://github.com/
|
105
|
+
homepage_uri: https://github.com/testcontainers/testcontainers-ruby
|
106
|
+
source_code_uri: https://github.com/testcontainers/testcontainers-ruby
|
107
|
+
changelog_uri: https://github.com/testcontainers/testcontainers-ruby/blob/main/core/CHANGELOG.md
|
108
108
|
post_install_message:
|
109
109
|
rdoc_options: []
|
110
110
|
require_paths:
|