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 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: