Contributing to Testcontainers Perl 5

First off, thank you for considering contributing to Testcontainers for Perl 5! It's people like you that make Testcontainers such a great tool.

Code of Conduct

This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.

How to Contribute

Reporting Bugs

Suggesting Features

Pull Requests

  1. Fork the repository.

  2. Create a feature branch from main:

    git checkout -b feature/my-feature
    
  3. Install dependencies:

    cpanm --installdeps .
    
  4. Build:

    perl Build.PL && ./Build
    
  5. Run unit tests (no Docker required):

    prove -l t/01-load.t t/02-container-request.t t/03-wait-strategies.t
    
  6. Run all tests (requires Docker):

    TESTCONTAINERS_LIVE=1 prove -l t/
    
  7. Commit, push, and open a PR against main.

Perl Code Style

Example

package Testcontainers::Wait::MyStrategy;
use Moo;
with 'Testcontainers::Wait::Base';

use Carp qw( croak );
use Log::Any qw( $log );

has some_option => (
    is      => 'ro',
    default => 'value',
);

sub check {
    my ($self, $container) = @_;
    $log->debugf("Checking with option: %s", $self->some_option);
    # Return 1 if ready, 0 if not
    return 1;
}

1;

Adding a Container Module

  1. Create lib/Testcontainers/Module/MyService.pm:
package Testcontainers::Module::MyService;
use strict;
use warnings;
use Exporter 'import';
our @EXPORT_OK = qw( myservice_container );

use Testcontainers qw( run );
use Testcontainers::Wait;

my $DEFAULT_IMAGE = 'myservice:latest';
my $DEFAULT_PORT  = '1234/tcp';

sub myservice_container {
    my (%opts) = @_;
    my $image = $opts{image} // $DEFAULT_IMAGE;

    my $container = run($image,
        exposed_ports    => [$DEFAULT_PORT],
        env              => { MY_VAR => $opts{my_var} // 'default' },
        _internal_labels => { 'org.testcontainers.module' => 'myservice' },
        wait_for         => Testcontainers::Wait::for_listening_port($DEFAULT_PORT),
        startup_timeout  => $opts{startup_timeout} // 60,
    );

    return Testcontainers::Module::MyService::Container->new(
        _container => $container,
    );
}

# Inner container class with convenience methods
package Testcontainers::Module::MyService::Container;
use Moo;

has _container => (is => 'ro', required => 1, handles => [qw(
    id host mapped_port endpoint exec logs stop start terminate
    is_running container_id
)]);

sub connection_string {
    my ($self) = @_;
    my $host = $self->host;
    my $port = $self->mapped_port($DEFAULT_PORT);
    return "myservice://$host:$port";
}

1;
  1. Add tests in t/05-modules.t or a new test file.
  2. Update README.md with a usage example.

Commit Messages

Follow Conventional Commits:

feat: add MyService module
fix: correct port mapping for UDP
docs: update QUICKSTART with MyService example
test: add integration test for MyService module
chore: update cpanfile dependencies

Testing

Questions?

Open an issue or start a discussion. We're happy to help!