our
@EXPORT_OK
=
qw(
build_client
get_test_db
server_version
server_type
clear_testdbs
get_capped
skip_if_mongod
skip_unless_mongod
skip_unless_failpoints_available
skip_unless_sessions
uri_escape
get_unique_collection
get_features
check_min_server_version
uuid_to_string
)
;
my
@testdbs
;
sub
_check_local_rs {
}
sub
build_client {
my
%args
=
@_
;
my
$host
=
exists
$args
{host} ?
delete
$args
{host}
:
exists
$ENV
{MONGOD} ?
$ENV
{MONGOD}
:
'localhost'
;
my
$ssl
;
if
(
$ENV
{EVG_ORCH_TEST} &&
$ENV
{SSL} eq
'ssl'
) {
$ssl
= {
SSL_cert_file
=>
$ENV
{EVG_TEST_SSL_PEM_FILE},
SSL_ca_file
=>
$ENV
{EVG_TEST_SSL_CA_FILE},
};
}
my
$codec
;
if
(
$ENV
{PERL_MONGO_TEST_CODEC_WRAPPED} ) {
$codec
= BSON->new(
ordered
=> 1,
wrap_dbrefs
=> 1,
wrap_numbers
=> 1,
wrap_strings
=> 1,
);
}
if
(
my
$comp
=
$ENV
{PERL_MONGO_TEST_COMPRESSION}) {
$args
{compressors} ||= [
$comp
];
}
return
MongoDB->
connect
(
$host
,
{
ssl
=>
$ssl
||
$ENV
{MONGO_SSL},
socket_timeout_ms
=> 60000,
server_selection_timeout_ms
=>
$ENV
{ATLAS_PROXY} ? 10000 : 2000,
server_selection_try_once
=> 0,
(
$codec
? (
bson_codec
=>
$codec
) : () ),
%args
,
}
);
}
sub
get_test_db {
my
$conn
=
shift
;
my
$prefix
=
shift
||
'testdb'
;
my
$testdb
=
$prefix
.
int
(
rand
(2**31));
my
$db
=
$conn
->get_database(
$testdb
) or
die
"Can't get database\n"
;
push
(
@testdbs
,
$db
);
return
$db
;
}
sub
get_unique_collection {
my
(
$db
,
$prefix
,
$options
) =
@_
;
return
$db
->get_collection(
sprintf
(
'%s_%d_%d'
,
$prefix
,
time
(),
int
(
rand
(999999)) ),
$options
,
);
}
sub
get_capped {
my
(
$db
,
$name
,
%args
) =
@_
;
$name
||=
'capped'
.
int
(
rand
(2**31));
$args
{size} ||= 500_000;
$db
->run_command([
create
=>
$name
,
capped
=> true,
%args
]);
return
$db
->get_collection(
$name
);
}
sub
skip_unless_mongod {
eval
{
my
$conn
= build_client(
server_selection_timeout_ms
=> 1000 );
my
$topo
=
$conn
->_topology;
$topo
->scan_all_servers;
my
$link
;
eval
{
$link
=
$topo
->get_writable_link }
or
die
"couldn't connect: $@"
;
$conn
->get_database(
"admin"
)->run_command( {
serverStatus
=> 1 } )
or
die
"Database has auth enabled\n"
;
my
$server
=
$link
->server;
if
( !
$ENV
{MONGOD} &&
$topo
->type eq
'Single'
&&
$server
->type =~ /^RS/ ) {
}
};
if
($@) {
(
my
$err
= $@ ) =~ s/\n//g;
if
(
$ENV
{EVG_ORCH_TEST} ) {
BAIL_OUT(
$err
);
}
if
(
$err
=~ /couldn't
connect
|connection refused/i ) {
$err
=
"no mongod on "
. (
$ENV
{MONGOD} ||
"localhost:27017"
);
$err
.=
' and $ENV{MONGOD} not set'
unless
$ENV
{MONGOD};
}
plan
skip_all
=>
"$err"
;
}
}
sub
skip_if_mongod {
eval
{
my
$conn
= build_client(
server_selection_timeout_ms
=> 1000 );
my
$topo
=
$conn
->_topology;
$topo
->scan_all_servers;
$topo
->get_readable_link(MongoDB::ReadPreference->new({
mode
=>
'nearest'
}));
};
if
( ! $@ ) {
plan
skip_all
=>
"Test can't start with a running mongod"
;
}
}
sub
skip_unless_failpoints_available {
my
(
$arg
) =
@_
;
unless
(
$ENV
{FAILPOINT_TESTING} ) {
plan
skip_all
=>
"\$ENV{FAILPOINT_TESTING} is false"
;
}
if
( version->parse(
$ENV
{HARNESS_VERSION} ) < version->parse(3.31) ) {
plan
skip_all
=>
"not safe to run fail points before Test::Harness 3.31"
;
}
if
( $0 =~ m{^t/.*\.t$} ) {
my
$rules
= path(
"t/testrules.yml"
)->slurp_utf8;
plan
skip_all
=>
"$0 not listed in t/testrules.yml"
unless
$rules
=~ m{seq:\s+\Q$0\E};
}
my
$conn
= build_client;
my
$server_type
= server_type(
$conn
);
my
$param
=
eval
{
$conn
->get_database(
'admin'
)
->run_command( [
getParameter
=> 1,
enableTestCommands
=> 1 ] );
};
plan
skip_all
=>
"enableTestCommands is off"
unless
$param
&&
$param
->{enableTestCommands};
plan
skip_all
=>
"fail points not supported via mongos"
if
$server_type
eq
'Mongos'
;
}
sub
skip_unless_sessions {
my
$conn
= build_client;
plan
skip_all
=>
"Session support not available"
unless
$conn
->_topology->_supports_sessions;
}
sub
server_version {
my
$conn
=
shift
;
my
$build
=
$conn
->send_admin_command( [
buildInfo
=> 1 ] )->output;
my
(
$version_str
) =
$build
->{version} =~ m{^([0-9.]+)};
return
version->parse(
"v$version_str"
);
}
sub
check_min_server_version {
my
(
$conn
,
$min_version
) =
@_
;
$min_version
=
"v$min_version"
unless
$min_version
=~ /^v/;
$min_version
.=
".0"
unless
$min_version
=~ /^v\d+\.\d+.\d+$/;
$min_version
= version->new(
$min_version
);
my
$server_version
= server_version(
$conn
);
if
(
$min_version
>
$server_version
) {
return
1;
}
return
0;
}
sub
server_type {
my
$conn
=
shift
;
my
$server_type
;
my
$ismaster
=
$conn
->get_database(
'admin'
)->run_command({
ismaster
=> 1});
if
(
exists
$ismaster
->{msg} &&
$ismaster
->{msg} eq
'isdbgrid'
) {
$server_type
=
'Mongos'
;
}
elsif
(
$ismaster
->{ismaster} &&
exists
$ismaster
->{setName} ) {
$server_type
=
'RSPrimary'
}
elsif
( !
exists
$ismaster
->{setName} && !
$ismaster
->{isreplicaset} ) {
$server_type
=
'Standalone'
}
else
{
$server_type
=
'Unknown'
;
}
return
$server_type
;
}
sub
get_features {
my
$conn
=
shift
;
my
$topo
=
$conn
->_topology;
$topo
->scan_all_servers;
my
$link
;
eval
{
$link
=
$topo
->get_writable_link };
return
$link
// MongoDB::_Link->new(
address
=>
"0:0"
);
}
my
%escapes
=
map
{
chr
(
$_
) =>
sprintf
(
"%%%02X"
,
$_
) } 0..255;
my
$unsafe_char
=
qr/[^A-Za-z0-9\-\._~]/
;
sub
uri_escape {
my
(
$str
) =
@_
;
utf8::encode(
$str
);
$str
=~ s/(
$unsafe_char
)/
$escapes
{$1}/ge;
return
$str
;
}
sub
uuid_to_string {
my
$uuid
=
shift
;
return
join
"-"
,
unpack
(
"H8H4H4H4H12"
,
$uuid
);
}
sub
clear_testdbs {
@testdbs
= () }
END {
for
my
$db
(
@testdbs
) {
$db
->drop;
}
}
1;