Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions spec/docker_container_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,19 @@ describe Testcontainers::DockerContainer do

it "sets default labels" do
container = Testcontainers::DockerContainer.new("redis:latest")
container.labels["org.testcontainers"].should eq("true")
container.labels["org.testcontainers.sessionId"].should eq(Testcontainers::DockerClient::SESSION_ID)
container.labels["org.testcontainers.lang"].should eq("crystal")
container.labels["org.testcontainers.version"].should eq(Testcontainers::VERSION)
end

it "uses the same session id across containers" do
container_1 = Testcontainers::DockerContainer.new("redis:latest")
container_2 = Testcontainers::DockerContainer.new("nginx:latest")

container_1.labels["org.testcontainers.sessionId"].should eq(container_2.labels["org.testcontainers.sessionId"])
end

it "starts with empty configurations" do
container = Testcontainers::DockerContainer.new("redis:latest")
container.name.should be_nil
Expand Down
33 changes: 33 additions & 0 deletions spec/integration_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# Note: These tests require Docker to be running and accessible
# via /var/run/docker.sock

{% if flag?(:integration) %}

Check warning on line 11 in spec/integration_spec.cr

View workflow job for this annotation

GitHub Actions / Integration Tests

expanding macro
describe "Integration: DockerContainer" do
it "starts and stops a Redis container" do
container = Testcontainers::DockerContainer.new("redis:7-alpine")
Expand Down Expand Up @@ -103,6 +103,39 @@
network.remove rescue nil
end
end

it "applies Testcontainers labels to container and network" do
network = Testcontainers::Network.new
container = Testcontainers::DockerContainer.new("redis:7-alpine")
.with_exposed_port(6379)

begin
network.create!
container.start

container_labels = container.info.config.labels
container_labels.should_not be_nil
container_labels = container_labels.not_nil!

network_labels = network.info.labels

container_labels["org.testcontainers"].should eq("true")
network_labels["org.testcontainers"].should eq("true")

container_labels["org.testcontainers.sessionId"].should eq(Testcontainers::DockerClient::SESSION_ID)
network_labels["org.testcontainers.sessionId"].should eq(Testcontainers::DockerClient::SESSION_ID)

container_labels["org.testcontainers.lang"].should eq("crystal")
network_labels["org.testcontainers.lang"].should eq("crystal")

container_labels["org.testcontainers.version"].should eq(Testcontainers::VERSION)
network_labels["org.testcontainers.version"].should eq(Testcontainers::VERSION)
ensure
container.stop rescue nil
container.remove(force: true) rescue nil
network.remove rescue nil
end
end
end
{% else %}
describe "Integration tests" do
Expand Down
8 changes: 8 additions & 0 deletions spec/network_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ describe Testcontainers::Network do
network.created?.should be_false
network.network_id.should be_nil
end

it "sets default labels" do
network = Testcontainers::Network.new
network.labels["org.testcontainers"].should eq("true")
network.labels["org.testcontainers.sessionId"].should eq(Testcontainers::DockerClient::SESSION_ID)
network.labels["org.testcontainers.lang"].should eq("crystal")
network.labels["org.testcontainers.version"].should eq(Testcontainers::VERSION)
end
end

describe ".generate_name" do
Expand Down
18 changes: 18 additions & 0 deletions src/testcontainers/docker_client.cr
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
require "docr"
require "uuid"

module Testcontainers
# DockerClient provides a singleton-like access to the Docr API client
# which communicates with the Docker daemon via the UNIX socket.
module DockerClient
@@api : Docr::API? = nil

TESTCONTAINERS_LABEL = "org.testcontainers"
TESTCONTAINERS_SESSION_ID_LABEL = "#{TESTCONTAINERS_LABEL}.sessionId"
TESTCONTAINERS_LANG_LABEL = "#{TESTCONTAINERS_LABEL}.lang"
TESTCONTAINERS_VERSION_LABEL = "#{TESTCONTAINERS_LABEL}.version"

SESSION_ID = UUID.random.to_s

# Returns the shared Docr::API instance, creating it if needed.
#
# The API instance uses the Docker socket at /var/run/docker.sock
Expand All @@ -22,6 +30,16 @@ module Testcontainers
@@api = nil
end

# Returns the default marker labels applied to Testcontainers resources.
def self.default_labels : Hash(String, String)
{
TESTCONTAINERS_LABEL => "true",
TESTCONTAINERS_SESSION_ID_LABEL => SESSION_ID,
TESTCONTAINERS_LANG_LABEL => "crystal",
TESTCONTAINERS_VERSION_LABEL => Testcontainers::VERSION,
}
end

# Returns the Docker host address.
#
# Resolution order:
Expand Down
5 changes: 1 addition & 4 deletions src/testcontainers/docker_container.cr
Original file line number Diff line number Diff line change
Expand Up @@ -710,10 +710,7 @@ module Testcontainers
end

private def default_labels : Hash(String, String)
{
"org.testcontainers.lang" => "crystal",
"org.testcontainers.version" => Testcontainers::VERSION,
}
DockerClient.default_labels
end

private def normalize_port(port : Int32 | String) : String
Expand Down
3 changes: 3 additions & 0 deletions src/testcontainers/network.cr
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ module Testcontainers
getter name : String
getter driver : String
getter network_id : String?
getter labels : Hash(String, String)

def initialize(
@name : String = Network.generate_name,
@driver : String = DEFAULT_DRIVER,
)
@network_id = nil
@labels = DockerClient.default_labels
end

# Creates the Docker network (idempotent).
Expand All @@ -35,6 +37,7 @@ module Testcontainers
name: @name,
driver: @driver,
check_duplicate: true,
labels: @labels,
)

response = DockerClient.api.networks.create(config)
Expand Down