File Coverage

blib/lib/Testcontainers/Wait.pm
Criterion Covered Total %
statement 40 40 100.0
branch 6 6 100.0
condition 3 4 75.0
subroutine 15 15 100.0
pod 0 6 0.0
total 64 71 90.1


line stmt bran cond sub pod time code
1             package Testcontainers::Wait;
2             # ABSTRACT: Wait strategy factory for Testcontainers
3              
4 4     4   136178 use strict;
  4         8  
  4         159  
5 4     4   17 use warnings;
  4         6  
  4         215  
6 4     4   30 use Carp qw( croak );
  4         8  
  4         190  
7              
8 4     4   1958 use Testcontainers::Wait::HostPort;
  4         15  
  4         209  
9 4     4   2526 use Testcontainers::Wait::HTTP;
  4         17  
  4         193  
10 4     4   3657 use Testcontainers::Wait::Log;
  4         19  
  4         190  
11 4     4   3402 use Testcontainers::Wait::HealthCheck;
  4         14  
  4         179  
12 4     4   1903 use Testcontainers::Wait::Multi;
  4         15  
  4         349  
13              
14             our $VERSION = '0.001';
15              
16 4     4   34 use Exporter 'import';
  4         10  
  4         1698  
17             our @EXPORT_OK = qw(
18             for_listening_port
19             for_exposed_port
20             for_http
21             for_log
22             for_health_check
23             for_all
24             );
25              
26             =head1 SYNOPSIS
27              
28             use Testcontainers::Wait;
29              
30             # Wait for a specific port to be listening
31             my $wait = Testcontainers::Wait::for_listening_port('80/tcp');
32              
33             # Wait for the lowest exposed port
34             my $wait = Testcontainers::Wait::for_exposed_port();
35              
36             # Wait for an HTTP endpoint to return 200
37             my $wait = Testcontainers::Wait::for_http('/');
38              
39             # Wait for an HTTP endpoint with custom options
40             my $wait = Testcontainers::Wait::for_http('/health',
41             port => '8080/tcp',
42             status_code => 200,
43             method => 'GET',
44             );
45              
46             # Wait for a log message
47             my $wait = Testcontainers::Wait::for_log('ready to accept connections');
48              
49             # Wait for a log message matching regex
50             my $wait = Testcontainers::Wait::for_log(qr/listening on port \d+/);
51              
52             # Wait for Docker health check
53             my $wait = Testcontainers::Wait::for_health_check();
54              
55             # Combine multiple strategies (all must pass)
56             my $wait = Testcontainers::Wait::for_all(
57             Testcontainers::Wait::for_listening_port('5432/tcp'),
58             Testcontainers::Wait::for_log('ready to accept connections'),
59             );
60              
61             =head1 DESCRIPTION
62              
63             Factory module for creating wait strategies. Wait strategies determine when
64             a container is "ready" for use in tests. Inspired by the Go testcontainers
65             wait package.
66              
67             =cut
68              
69             sub for_listening_port {
70 3     3 0 330099 my ($port) = @_;
71 3 100       180 croak "Port required" unless $port;
72 2         55 return Testcontainers::Wait::HostPort->new(port => $port);
73             }
74              
75             =func for_listening_port($port)
76              
77             Wait for the specified port to be listening. The port should include the protocol
78             (e.g., C<80/tcp>). If no protocol is given, C is assumed.
79              
80             =cut
81              
82             sub for_exposed_port {
83 1     1 0 11014 return Testcontainers::Wait::HostPort->new(use_lowest_port => 1);
84             }
85              
86             =func for_exposed_port()
87              
88             Wait for the lowest exposed port to be listening.
89              
90             =cut
91              
92             sub for_http {
93 2     2 0 12345 my ($path, %opts) = @_;
94 2   50     47 return Testcontainers::Wait::HTTP->new(
95             path => $path // '/',
96             %opts,
97             );
98             }
99              
100             =func for_http($path, %opts)
101              
102             Wait for an HTTP endpoint to return a successful response.
103              
104             Options:
105              
106             =over
107              
108             =item * C - Specific port to check (default: lowest exposed port)
109              
110             =item * C - Expected HTTP status code (default: 200)
111              
112             =item * C - HTTP method (default: GET)
113              
114             =item * C - Request body
115              
116             =item * C - HashRef of HTTP headers
117              
118             =item * C - Use HTTPS (default: false)
119              
120             =back
121              
122             =cut
123              
124             sub for_log {
125 4     4 0 19676 my ($pattern, %opts) = @_;
126 4 100       198 croak "Log pattern required" unless defined $pattern;
127             return Testcontainers::Wait::Log->new(
128             pattern => $pattern,
129 3   100     84 occurrences => $opts{occurrences} // 1,
130             );
131             }
132              
133             =func for_log($pattern, %opts)
134              
135             Wait for a string or regex pattern to appear in container logs.
136              
137             Options:
138              
139             =over
140              
141             =item * C - Number of times the pattern must occur (default: 1)
142              
143             =back
144              
145             =cut
146              
147             sub for_health_check {
148 1     1 0 5385 return Testcontainers::Wait::HealthCheck->new;
149             }
150              
151             =func for_health_check()
152              
153             Wait for the Docker health check to report "healthy".
154              
155             =cut
156              
157             sub for_all {
158 2     2 0 2652 my (@strategies) = @_;
159 2 100       120 croak "At least one strategy required" unless @strategies;
160 1         9 return Testcontainers::Wait::Multi->new(strategies => \@strategies);
161             }
162              
163             =func for_all(@strategies)
164              
165             Combine multiple wait strategies. All must pass for the container to be
166             considered ready.
167              
168             =cut
169              
170             1;