Class: Testcontainers::MockServerContainer

Inherits:
DockerContainer
  • Object
show all
Defined in:
lib/testcontainers/mockserver.rb

Overview

A Testcontainers module for MockServer.

Starts the official mockserver/mockserver Docker image, waits for the server to begin listening, and exposes connection helpers (host, mapped port, HTTP/HTTPS endpoints) plus a ready-wired #client.

MockServer serves HTTP, HTTPS, SOCKS, and HTTP CONNECT on a single unified port (default 1080).

Examples:

Basic usage

container = Testcontainers::MockServerContainer.new.start
client = container.client
client.when(
  MockServer::HttpRequest.request(path: "/hello")
).respond(
  MockServer::HttpResponse.response(body: "world")
)
# point the system under test at container.endpoint
container.stop

Block form (auto-stop)

Testcontainers::MockServerContainer.new.use do |container|
  client = container.client
  # ...
end

Constant Summary collapse

MOCKSERVER_DEFAULT_PORT =

Default MockServer port (HTTP, HTTPS, SOCKS, and HTTP CONNECT are all served on a single unified port).

1080
IMAGE =

The Docker image name on Docker Hub.

"mockserver/mockserver"
VERSION =

Version of this gem (kept in lockstep with the MockServer release).

::Testcontainers::Mockserver::VERSION

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(image = nil, port: MOCKSERVER_DEFAULT_PORT, **kwargs) ⇒ MockServerContainer

Returns a new instance of MockServerContainer.

Parameters:

  • image (String, nil) (defaults to: nil)

    full Docker image reference; when nil the tag is derived from the MockServer client library version (see default_image).

  • port (Integer) (defaults to: MOCKSERVER_DEFAULT_PORT)

    the port MockServer listens on inside the container



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/testcontainers/mockserver.rb', line 51

def initialize(image = nil, port: MOCKSERVER_DEFAULT_PORT, **kwargs)
  super(image || self.class.default_image, **kwargs)
  @port = port
  @client = nil
  add_exposed_port(port)
  # Wait until MockServer answers PUT /mockserver/status with HTTP 200, the
  # same readiness signal used by the sibling polyglot modules. A host-side
  # TCP-port wait is unreliable here because the Docker port proxy accepts
  # connections before MockServer has bound inside the container.
  @wait_for = ->(container) { container.wait_until_ready }
  with_env("SERVER_PORT", port.to_s)
end

Class Method Details

.default_imageString

Resolves the default Docker image, deriving the tag from the MockServer client library version so the container image stays in lockstep with the client. Falls back to :latest when the version cannot be resolved.

Returns:

  • (String)

    e.g. "mockserver/mockserver:mockserver-7.3.0"



186
187
188
189
190
191
192
193
# File 'lib/testcontainers/mockserver.rb', line 186

def self.default_image
  tag = if defined?(MockServer::VERSION) && !MockServer::VERSION.to_s.empty?
          "mockserver-#{MockServer::VERSION}"
        else
          "latest"
        end
  "#{IMAGE}:#{tag}"
end

Instance Method Details

#clientMockServer::Client

Returns a MockServer::Client connected to this container. The client is created lazily on first call and cached; it is closed automatically when the container is stopped via #stop.

Returns:

  • (MockServer::Client)

    a client connected to the running container



113
114
115
# File 'lib/testcontainers/mockserver.rb', line 113

def client
  @client ||= MockServer::Client.new(host, server_port)
end

#endpointString

Returns the HTTP endpoint in the form http://host:port.

Returns:

  • (String)

    the HTTP endpoint in the form http://host:port



97
98
99
# File 'lib/testcontainers/mockserver.rb', line 97

def endpoint
  "http://#{host}:#{server_port}"
end

#secure_endpointString

MockServer serves HTTP and HTTPS on the same unified port.

Returns:

  • (String)

    the HTTPS endpoint in the form https://host:port



104
105
106
# File 'lib/testcontainers/mockserver.rb', line 104

def secure_endpoint
  "https://#{host}:#{server_port}"
end

#server_portInteger

Returns the mapped host port for MockServer.

Returns:

  • (Integer)

    the host port mapped to the MockServer container port



67
68
69
# File 'lib/testcontainers/mockserver.rb', line 67

def server_port
  mapped_port(@port)
end

#stop(force: false) ⇒ MockServerContainer

Stops the cached client (if any) and the container.

Returns:



120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/testcontainers/mockserver.rb', line 120

def stop(force: false)
  if @client
    begin
      @client.close
    rescue StandardError # rubocop:disable Lint/SuppressedException
      # best-effort close; ignore errors while tearing down the client
    ensure
      @client = nil
    end
  end
  super
end

#wait_until_ready(timeout: 60, interval: 0.25) ⇒ true

Blocks until MockServer answers PUT /mockserver/status with HTTP 200. Used as the container's wait strategy.

Parameters:

  • timeout (Integer) (defaults to: 60)

    maximum seconds to wait

  • interval (Float) (defaults to: 0.25)

    seconds between polls

Returns:

  • (true)

    once MockServer is ready

Raises:

  • (Testcontainers::TimeoutError)

    if MockServer is not ready in time



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/testcontainers/mockserver.rb', line 78

def wait_until_ready(timeout: 60, interval: 0.25)
  uri = URI("http://#{host}:#{server_port}/mockserver/status")
  deadline = Time.now + timeout
  loop do
    begin
      response = Net::HTTP.start(uri.hostname, uri.port, open_timeout: 2, read_timeout: 5) do |http|
        http.request(Net::HTTP::Put.new(uri))
      end
      return true if response.code == "200"
    rescue StandardError
      # MockServer is not accepting connections yet
    end
    raise ::Testcontainers::TimeoutError, "MockServer did not become ready within #{timeout}s" if Time.now > deadline

    sleep interval
  end
end

#with_initialization_json(host_init_json_path) ⇒ MockServerContainer

Mounts an initialization JSON file into the container and configures MockServer to load its expectations at startup.

Parameters:

  • host_init_json_path (String)

    path on the host to the JSON file

Returns:



175
176
177
178
179
# File 'lib/testcontainers/mockserver.rb', line 175

def with_initialization_json(host_init_json_path)
  container_path = "/config/initializerJson.json"
  add_filesystem_bind(File.expand_path(host_init_json_path), container_path, "ro")
  with_env("MOCKSERVER_INITIALIZATION_JSON_PATH", container_path)
end

#with_log_level(level) ⇒ MockServerContainer

Sets the MockServer log level (e.g. "INFO", "DEBUG", "WARN", "ERROR", "TRACE").

Parameters:

  • level (String)

Returns:



156
157
158
# File 'lib/testcontainers/mockserver.rb', line 156

def with_log_level(level)
  with_env("MOCKSERVER_LOG_LEVEL", level)
end

#with_property(key, value) ⇒ MockServerContainer

Sets a single MockServer property as an environment variable. The key must be in MockServer env-var form (e.g. "MOCKSERVER_MAX_EXPECTATIONS").

Parameters:

  • key (String)
  • value (String)

Returns:



166
167
168
# File 'lib/testcontainers/mockserver.rb', line 166

def with_property(key, value)
  with_env(key, value.to_s)
end

#with_server_port(port) ⇒ MockServerContainer

Overrides the port MockServer listens on inside the container. Replaces the exposed port so the TCP wait strategy targets the correct port.

Parameters:

  • port (Integer)

Returns:



138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/testcontainers/mockserver.rb', line 138

def with_server_port(port)
  @port = port
  # Replace the exposed port (and its binding) rather than appending, so the
  # TCP wait strategy never blocks on a port MockServer is not listening on.
  @exposed_ports = nil
  @port_bindings = nil
  add_exposed_port(port)
  @wait_for = ->(container) { container.wait_until_ready }
  # Replace (not append) the SERVER_PORT env var — @env is an ordered list
  # and get_env returns the first match, so a stale entry would shadow this.
  @env&.reject! { |entry| entry.start_with?("SERVER_PORT=") }
  with_env("SERVER_PORT", port.to_s)
end