our
@EXPORT_OK
=
qw/get_startup_nodes/
;
REDIS_CLUSTER_INITIAL_PORT
=> 9000,
REDIS_CLUSTER_PORTS
=> [ 9000, 9001, 9002, 9003, 9004, 9005 ],
REDIS_VERSION
=>
'6.0.5'
,
TEST_DOCKER_CONTAINER_NAME
=>
'test_for_perl_redis_cluster_fast'
,
};
Test::More::plan
skip_all
=>
'Skip tests using local Docker / Redis Cluster because AUTHOR_TESTING is not set'
unless
$ENV
{AUTHOR_TESTING};
my
$pid
= $$;
sub
_debug_warn {
my
$msg
=
shift
;
chomp
$msg
;
if
(
$ENV
{DEBUG_TEST_DOCKER_IMAGE}) {
warn
sprintf
(
"[%s] %s"
, __PACKAGE__,
$msg
);
}
}
sub
_capture_exec {
_debug_warn(
join
(
' '
,
@_
));
capture_exec(
@_
);
}
sub
_skip_tests {
my
$string
=
shift
;
chomp
$string
;
my
$message
=
join
" "
,
"Failed to create a docker container."
,
"You can set a TEST_REDIS_CLUSTER_STARTUP_NODES environment to specify redis cluster nodes manually."
,
"(e.g. TEST_REDIS_CLUSTER_STARTUP_NODES=localhost:9000,localhost:9001,localhost:9002 )"
;
Test::More::plan
skip_all
=>
sprintf
"[%s] %s ERR: %s"
, __PACKAGE__,
$message
,
$string
;
}
sub
_get_container_ports {
my
$ports
= REDIS_CLUSTER_PORTS;
[
map
{
"$_:$_"
}
@$ports
];
}
sub
_start_redis_cluster {
my
$initial_port
=
"INITIAL_PORT="
. REDIS_CLUSTER_INITIAL_PORT;
my
$container_ports
= _get_container_ports;
my
@ports
=
map
{ (
'-p'
,
$_
) }
@$container_ports
;
my
$image_tag
=
"grokzen/redis-cluster:"
. REDIS_VERSION;
my
(
$container_id
,
$stderr
,
$exit_code
);
retry(2, 0,
sub
{
(
$container_id
,
$stderr
,
$exit_code
) = _capture_exec(
qw/docker run -e IP=127.0.0.1 -d -t/
,
'--name'
, TEST_DOCKER_CONTAINER_NAME,
'-e'
,
$initial_port
,
@ports
,
$image_tag
,
);
chomp
$container_id
;
},
sub
{
if
(
$stderr
=~ /is already in
use
by container
"([a-z|0-9]*)"
./) {
_capture_exec(
qw/docker kill/
, $1);
_capture_exec(
qw/docker rm/
, $1);
return
1;
}
if
(
$stderr
) {
_skip_tests(
$stderr
);
return
1;
}
return
0;
}
);
_skip_tests(
"container_id undefined"
)
unless
defined
$container_id
;
return
$container_id
;
}
sub
get_startup_nodes {
if
(
my
$nodes
=
$ENV
{TEST_REDIS_CLUSTER_STARTUP_NODES}) {
return
[
split
(/,/,
$nodes
) ];
}
else
{
my
$ports
= REDIS_CLUSTER_PORTS;
return
[
map
{
"127.0.0.1:$_"
}
@$ports
];
}
}
my
$guard
;
unless
(
$ENV
{TEST_REDIS_CLUSTER_STARTUP_NODES}) {
my
$running_container_id
= _start_redis_cluster;
my
$redis
;
retry(100, 0.2,
sub
{
$redis
= Redis::Cluster::Fast->new(
startup_nodes
=> get_startup_nodes,
);
},
sub
{
my
$err
= $@;
return
1
if
$err
;
eval
{
my
$info
=
$redis
->cluster_info();
return
0
if
$info
=~ /^cluster_state:ok/;
};
1;
});
$guard
= Scope::Guard->new(
sub
{
if
(
$pid
== $$ && !
$ENV
{TEST_REDIS_CLUSTER_STARTUP_NODES}) {
_capture_exec(
'docker'
,
$_
,
$running_container_id
)
for
qw/kill rm/
;
}
});
sleep
2;
}
END {
undef
$guard
};
1;