skip_unless_mongod
build_client
get_test_db
server_type
server_version
skip_unless_failpoints_available
set_failpoint
clear_failpoint
check_min_server_version
skip_unless_min_version
)
;
skip_unless_mongod();
skip_unless_failpoints_available();
my
$conn
= build_client();
my
$testdb
= get_test_db(
$conn
);
my
$server_type
= server_type(
$conn
);
my
$server_version
= server_version(
$conn
);
my
$coll
;
my
$admin
=
$conn
->get_database(
"admin"
);
note
"CAP-401 test plan"
;
can_ok(
'MongoDB::Cursor'
,
'max_time_ms'
);
$coll
=
$testdb
->get_collection(
"test_collection"
);
my
$bulk
=
$coll
->ordered_bulk;
$bulk
->insert_one( {
_id
=>
$_
} )
for
1 .. 20;
my
$err
= exception {
$bulk
->execute };
is(
$err
,
undef
,
"inserted 20 documents for testing"
);
my
$iv
=
$coll
->indexes;
subtest
"expected behaviors"
=>
sub
{
is( exception {
$coll
->find->max_time_ms()->
next
},
undef
,
"find->max_time_ms()"
);
is( exception {
$coll
->find->max_time_ms(0)->
next
},
undef
,
"find->max_time_ms(0)"
);
is( exception {
$coll
->find->max_time_ms(5000)->
next
},
undef
,
"find->max_time_ms(5000)"
);
like( exception {
$coll
->find->max_time_ms(-1)->
next
},
qr/non-negative/
,
"find->max_time_ms(-1) throws exception"
);
is( exception {
$coll
->find( {}, {
maxTimeMS
=> 5000 } ) },
undef
,
"find with maxTimeMS"
);
is(
exception {
my
$doc
=
$coll
->find_one( {
_id
=> 1 },
undef
, {
maxTimeMS
=> 5000 } );
},
undef
,
"find_one with maxTimeMS works"
);
SKIP: {
skip
"aggregate not available until MongoDB v2.2"
, 1
if
check_min_server_version(
$conn
,
'v2.2.0'
);
is(
exception {
my
$doc
=
$coll
->aggregate(
[ {
'$project'
=> {
name
=> 1,
count
=> 1 } } ],
{
maxTimeMS
=> 5000 },
);
},
undef
,
"aggregate helper with maxTimeMS works"
);
}
is(
exception {
my
$doc
=
$coll
->count_documents( {}, {
maxTimeMS
=> 5000 } );
},
undef
,
"count helper with maxTimeMS works"
);
is(
exception {
my
$doc
=
$coll
->distinct(
'a'
, {}, {
maxTimeMS
=> 5000 } );
},
undef
,
"distinct helper with maxTimeMS works"
);
is(
exception {
my
$doc
=
$coll
->find_one_and_replace(
{
_id
=> 22 },
{
x
=> 1 },
{
upsert
=> 1,
maxTimeMS
=> 5000 }
);
},
undef
,
"find_one_and_replace helper with maxTimeMS works"
);
is(
exception {
my
$doc
=
$coll
->find_one_and_update(
{
_id
=> 23 },
{
'$set'
=> {
x
=> 1 } },
{
upsert
=> 1,
maxTimeMS
=> 5000 }
);
},
undef
,
"find_one_and_update helper with maxTimeMS works"
);
is(
exception {
my
$doc
=
$coll
->find_one_and_delete( {
_id
=> 23 }, {
maxTimeMS
=> 5000 } );
},
undef
,
"find_one_and_delete helper with maxTimeMS works"
);
is(
exception {
my
$cursor
=
$coll
->database->list_collections( {}, {
maxTimeMS
=> 5000 } );
},
undef
,
"list_collections command with maxTimeMS works"
);
};
subtest
"force maxTimeMS failures"
=>
sub
{
skip_unless_min_version(
$conn
,
'v2.6.0'
);
my
$cursor
=
$coll
->find( {}, {
batchSize
=> 5,
maxTimeMS
=> 5000 } )->result;
$cursor
->
next
;
is(
exception {
set_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
,
mode
=>
'alwaysOn'
} );
},
undef
,
"turned on maxTimeAlwaysTimeOut fail point"
);
my
@foo
;
like(
exception {
@foo
=
$cursor
->all },
qr/exceeded time limit/
,
"existing cursor with max_time_ms times out"
) or diag explain \
@foo
;
like(
exception {
$coll
->find()->max_time_ms(10)->
next
},
qr/exceeded time limit/
,
"new cursor with max_time_ms times out"
);
like(
exception {
$coll
->find( {}, {
maxTimeMS
=> 10 } )->
next
},
qr/exceeded time limit/
,
,
"find with maxTimeMS times out"
);
like(
exception {
my
$doc
=
$coll
->find_one( {
_id
=> 1 },
undef
, {
maxTimeMS
=> 10 } );
},
qr/exceeded time limit/
,
"find_one with maxTimeMS times out"
);
like(
exception {
my
$doc
=
$coll
->count_documents( {}, {
maxTimeMS
=> 10 } );
},
qr/exceeded time limit/
,
"count command with maxTimeMS times out"
);
SKIP: {
skip
"aggregate not available until MongoDB v2.2"
, 1
if
check_min_server_version(
$conn
,
'v2.2.0'
);
like(
exception {
my
$doc
=
$coll
->aggregate(
[ {
'$project'
=> {
name
=> 1,
count
=> 1 } } ],
{
maxTimeMS
=> 10 },
);
},
qr/exceeded time limit/
,
"aggregate helper with maxTimeMS times out"
);
}
like(
exception {
my
$doc
=
$coll
->count_documents( {}, {
maxTimeMS
=> 10 } );
},
qr/exceeded time limit/
,
"count helper with maxTimeMS times out"
);
like(
exception {
my
$doc
=
$coll
->distinct(
'a'
, {}, {
maxTimeMS
=> 10 } );
},
qr/exceeded time limit/
,
"distinct helper with maxTimeMS times out"
);
like(
exception {
my
$doc
=
$coll
->find_one_and_replace(
{
_id
=> 22 },
{
x
=> 1 },
{
upsert
=> 1,
maxTimeMS
=> 10 }
);
},
qr/exceeded time limit/
,
"find_one_and_replace helper with maxTimeMS times out"
);
like(
exception {
my
$doc
=
$coll
->find_one_and_update(
{
_id
=> 23 },
{
'$set'
=> {
x
=> 1 } },
{
upsert
=> 1,
maxTimeMS
=> 10 }
);
},
qr/exceeded time limit/
,
"find_one_and_update helper with maxTimeMS times out"
);
like(
exception {
my
$doc
=
$coll
->find_one_and_delete( {
_id
=> 23 }, {
maxTimeMS
=> 10 } );
},
qr/exceeded time limit/
,
"find_one_and_delete helper with maxTimeMS times out"
);
like(
exception {
my
$cursor
=
$coll
->database->list_collections( {}, {
maxTimeMS
=> 10 } );
},
qr/exceeded time limit/
,
"list_collections command times out"
);
subtest
"max_time_ms via constructor"
=>
sub
{
is(
exception {
my
$doc
=
$coll
->count_documents( {} ) },
undef
,
"count helper with default maxTimeMS 0 from client works"
);
my
$conn2
= build_client(
max_time_ms
=> 10 );
my
$testdb2
= get_test_db(
$conn2
);
my
$coll2
=
$testdb2
->get_collection(
"test_collection"
);
like(
exception {
my
$doc
=
$coll2
->count_documents( {} );
},
qr/exceeded time limit/
,
"count helper with configured maxTimeMS times out"
);
};
subtest
"zero disables maxTimeMS"
=>
sub
{
is( exception {
$coll
->find->max_time_ms(0)->
next
},
undef
,
"find->max_time_ms(0)"
);
is( exception {
$coll
->find( {}, {
maxTimeMS
=> 5000 } ) },
undef
,
"find with MaxTimeMS 5000 works"
);
is(
exception {
my
$doc
=
$coll
->find_one( {
_id
=> 1 },
undef
, {
maxTimeMS
=> 0 } );
},
undef
,
"find_one with MaxTimeMS zero works"
);
SKIP: {
skip
"aggregate not available until MongoDB v2.2"
, 1
if
check_min_server_version(
$conn
,
'v2.2.0'
);
is(
exception {
my
$doc
=
$coll
->aggregate(
[ {
'$project'
=> {
name
=> 1,
count
=> 1 } } ],
{
maxTimeMS
=> 0 },
);
},
undef
,
"aggregate helper with MaxTimeMS zero works"
);
}
is(
exception {
my
$doc
=
$coll
->count_documents( {}, {
maxTimeMS
=> 0 } );
},
undef
,
"count helper with MaxTimeMS zero works"
);
is(
exception {
my
$doc
=
$coll
->distinct(
'a'
, {}, {
maxTimeMS
=> 0 } );
},
undef
,
"distinct helper with MaxTimeMS zero works"
);
is(
exception {
my
$doc
=
$coll
->find_one_and_replace(
{
_id
=> 22 },
{
x
=> 1 },
{
upsert
=> 1,
maxTimeMS
=> 0 }
);
},
undef
,
"find_one_and_replace helper with MaxTimeMS zero works"
);
is(
exception {
my
$doc
=
$coll
->find_one_and_update(
{
_id
=> 23 },
{
'$set'
=> {
x
=> 1 } },
{
upsert
=> 1,
maxTimeMS
=> 0 }
);
},
undef
,
"find_one_and_update helper with MaxTimeMS zero works"
);
is(
exception {
my
$doc
=
$coll
->find_one_and_delete( {
_id
=> 23 }, {
maxTimeMS
=> 0 } );
},
undef
,
"find_one_and_delete helper with MaxTimeMS zero works"
);
};
is(
exception {
clear_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
} );
},
undef
,
"turned off maxTimeAlwaysTimeOut fail point"
);
};
subtest
"create_many w/ maxTimeMS"
=>
sub
{
skip_unless_min_version(
$conn
,
'v3.6.0'
);
$coll
->drop;
is(
exception {
set_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
,
mode
=>
'alwaysOn'
} );
},
undef
,
'max time failpoint on'
,
);
like(
exception {
$iv
->create_many(
{
keys
=> [
x
=> 1 ] }, {
keys
=> [
y
=> -1 ] },
{
maxTimeMS
=> 10 },
);
},
qr/exceeded time limit/
,
'timeout for index creation'
,
);
is(
exception {
$iv
->create_many(
{
keys
=> [
x
=> 1 ] }, {
keys
=> [
y
=> -1 ] },
);
},
undef
,
'no timeout without max time'
,
);
is(
exception {
clear_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
} );
},
undef
,
'max time failpoint off'
,
);
is(
exception {
$iv
->create_many(
{
keys
=> [
x
=> 1 ] }, {
keys
=> [
y
=> -1 ] },
{
maxTimeMS
=> 5000 },
);
},
undef
,
'no timeout for index creation'
,
);
};
subtest
"create_one w/ maxTimeMS"
=>
sub
{
skip_unless_min_version(
$conn
,
'v3.6.0'
);
$coll
->drop;
is(
exception {
set_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
,
mode
=>
'alwaysOn'
} );
},
undef
,
'max time failpoint on'
,
);
is(
exception {
$iv
->create_one([
x
=> 1 ]);
},
undef
,
'no timeout without max time'
,
);
like(
exception {
$iv
->create_one([
x
=> 1 ], {
maxTimeMS
=> 10 });
},
qr/exceeded time limit/
,
'timeout for index creation'
,
);
is(
exception {
clear_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
} );
},
undef
,
'max time failpoint off'
,
);
is(
exception {
$iv
->create_one([
x
=> 1 ], {
maxTimeMS
=> 5000 });
},
undef
,
'no timeout for index creation'
,
);
};
subtest
"drop_one w/ maxTimeMS"
=>
sub
{
skip_unless_min_version(
$conn
,
'v3.6.0'
);
$coll
->drop;
is(
exception {
set_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
,
mode
=>
'alwaysOn'
} );
},
undef
,
'max time failpoint on'
,
);
is(
exception {
my
$name
=
$iv
->create_one([
x
=> 1 ]);
$iv
->drop_one(
$name
);
},
undef
,
'no timeout without max time'
,
);
like(
exception {
my
$name
=
$iv
->create_one([
x
=> 1 ]);
$iv
->drop_one(
$name
, {
maxTimeMS
=> 10 });
},
qr/exceeded time limit/
,
'timeout for index drop'
,
);
is(
exception {
clear_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
} );
},
undef
,
'max time failpoint off'
,
);
is(
exception {
my
$name
=
$iv
->create_one([
x
=> 1 ]);
$iv
->drop_one(
$name
, {
maxTimeMS
=> 5000 });
},
undef
,
'no timeout for index drop'
,
);
};
subtest
"drop_all w/ maxTimeMS"
=>
sub
{
skip_unless_min_version(
$conn
,
'v3.6.0'
);
$coll
->drop;
is(
exception {
set_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
,
mode
=>
'alwaysOn'
} );
},
undef
,
'max time failpoint on'
,
);
is(
exception {
$iv
->create_many(
map
{ {
keys
=>
$_
} }[
x
=> 1 ], [
y
=> 1 ], [
z
=> 1 ] );
$iv
->drop_all();
},
undef
,
'no timeout without max time'
,
);
like(
exception {
$iv
->create_many(
map
{ {
keys
=>
$_
} }[
x
=> 1 ], [
y
=> 1 ], [
z
=> 1 ] );
$iv
->drop_all({
maxTimeMS
=> 10 });
},
qr/exceeded time limit/
,
'timeout for index drop'
,
);
is(
exception {
clear_failpoint(
$conn
,
{
configureFailPoint
=>
'maxTimeAlwaysTimeOut'
} );
},
undef
,
'max time failpoint off'
,
);
is(
exception {
$iv
->create_many(
map
{ {
keys
=>
$_
} }[
x
=> 1 ], [
y
=> 1 ], [
z
=> 1 ] );
$iv
->drop_all({
maxTimeMS
=> 5000 });
},
undef
,
'no timeout for index drop'
,
);
};
done_testing;