testcontainers-core 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 584f5aabce655fd2f113af37af6ce59cc8b3e0f6aa4b276bff52378e1d3c5e9d
4
- data.tar.gz: 0a3c73c6a6ba495c61b3ded68092d4a58a06099e1ff543d7ac2a45e9503082a6
3
+ metadata.gz: cd1ecb046574448907ac650c801eda4e7dad34055c6a61fa06a0f066067e2b97
4
+ data.tar.gz: f9c49b86765f2166cf2460bef0899ba40a1b822bdf23451bbe1a3e68531606e4
5
5
  SHA512:
6
- metadata.gz: 18f526847480a5cec71aa4abf2b10393fa7a08ccf5c4f70a07c18667624a8fb49ca3f0d9d241f0f5dd9e32404f3e0e06fc2cb67465059703d5e9eec143c04f4e
7
- data.tar.gz: fcc6793d0bbdf773de7e0cb5933364f45840c034c8821dd12ab99c17d08a05c23967d2b992d4152b2c7298eae12d75d751eaff8e83e21563a060647cdcbd1b67
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
- ## Added
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
- ## Changed
37
+ ### Changed
17
38
 
18
39
  - DockerContainer#mapped_port(port) method now returns an Integer instead of a String.
19
40
 
20
- ## Fixed
41
+ ### Fixed
21
42
 
22
43
  - Links to the GitHub project on the README.md file are fixed.
23
44
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- testcontainers-core (0.1.1)
4
+ testcontainers-core (0.1.3)
5
5
  docker-api (~> 2.2)
6
6
 
7
7
  GEM
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/guilleiguaran/testcontainers. 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/guilleiguaran/testcontainers/blob/main/CODE_OF_CONDUCT.md).
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/guilleiguaran/testcontainers/blob/main/CODE_OF_CONDUCT.md).
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, :env, :labels, :working_dir, :healthcheck
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, name: nil, exposed_ports: nil, port_bindings: nil, volumes: nil, filesystem_binds: nil, env: 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] = [{"HostPort" => ""}]
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Testcontainers
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  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.2
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-05-13 00:00:00.000000000 Z
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/guilleiguaran/testcontainers-ruby
101
+ homepage: https://github.com/testcontainers/testcontainers-ruby
102
102
  licenses:
103
103
  - MIT
104
104
  metadata:
105
- homepage_uri: https://github.com/guilleiguaran/testcontainers-ruby
106
- source_code_uri: https://github.com/guilleiguaran/testcontainers-ruby
107
- changelog_uri: https://github.com/guilleiguaran/testcontainers-ruby/blob/main/core/CHANGELOG.md
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: