%PDF- %PDF-
Direktori : /home/opti/optisoftcom/.cpanm/work/1544535406.20768/MongoDB-v2.0.2/t/ |
Current File : /home/opti/optisoftcom/.cpanm/work/1544535406.20768/MongoDB-v2.0.2/t/sessions-driver.t |
# Copyright 2018 - present MongoDB, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. use strict; use warnings; use Test::More 0.96; use Test::Fatal; use Test::Deep qw/!blessed/; use utf8; use List::Util 'max'; use Tie::IxHash; use MongoDB; use MongoDB::Error; use lib "t/lib"; use MongoDBTest qw/ build_client skip_unless_mongod skip_unless_sessions get_test_db server_version server_type clear_testdbs get_unique_collection /; skip_unless_mongod(); skip_unless_sessions(); my @events; sub clear_events { @events = () } sub event_count { scalar @events } sub event_cb { push @events, $_[0] } my $conn = build_client( monitoring_callback => \&event_cb, ); my $testdb = get_test_db($conn); my $server_version = server_version($conn); my $server_type = server_type($conn); my $coll = $testdb->get_collection('test_collection'); $coll->insert_one({}); # do a write so cluster establishes an optime clear_events(); # Last in First out subtest 'LIFO Pool' => sub { my $session_a = $conn->start_session; my $session_b = $conn->start_session; # cache the ID's my $id_a = $session_a->session_id; my $id_b = $session_b->session_id; ok defined $id_a->{id}, 'Session A ID defined'; ok defined $id_b->{id}, 'Session B ID defined'; $session_a->end_session; $session_b->end_session; # Internal only check, not part of spec is $session_a->_server_session, undef, 'Session A has been returned'; is $session_b->_server_session, undef, 'Session B has been returned'; my $session_c = $conn->start_session; ok defined $session_c->session_id->{id}, 'Session C ID defined'; is $session_c->session_id->{id}, $id_b->{id}, 'Session C same ID as Session B'; my $session_d = $conn->start_session; ok defined $session_d->session_id->{id}, 'Session D ID defined'; is $session_d->session_id->{id}, $id_a->{id}, 'Session D same ID as Session A'; }; subtest 'clusterTime in commands' => sub { clear_events(); subtest 'SDAM' => sub { my $local_client = get_high_heartbeat_client(); $local_client->topology_status( refresh => 1 ); my $command = $events[0]->{command}; ok exists $command->{'ismaster'}, 'ismaster in sent command'; # first ismaster to unknown hosts won't have it ok !exists $command->{'$clusterTime'}, 'clusterTime in sent command'; # find max time among replies my $max_cluster_time = max( grep { defined } map { $_->{reply}{'$clusterTime'}{clusterTime} } grep { $_->{type} eq 'command_succeeded' } @events ); ok( defined $max_cluster_time, "have max cluster time from ismaster replies" ) or diag explain \@events; clear_events(); $local_client->topology_status( refresh => 1 ); my $command2 = $events[0]->{command}; # next ismaster to known hosts should have $clustertime ok exists $command2->{'ismaster'}, 'ismater in sent command' or diag explain $command2; my $got = $command2->{'$clusterTime'}->{clusterTime}; ok( $got == $max_cluster_time, "clusterTime matches" ) or diag "GOT:\n", explain $got, "\nEXPECTED:\n", explain $max_cluster_time; }; clear_events(); subtest 'ping' => sub { my $local_client = get_high_heartbeat_client(); my $ping_result = $local_client->send_admin_command(Tie::IxHash->new('ping' => 1)); my $command = $events[-2]->{ command }; my $result = $events[-1]->{ reply }; ok exists $command->{'ping'}, 'ping in sent command'; ok exists $command->{'$clusterTime'}, 'clusterTime in sent command'; my $ping_result2 = $local_client->send_admin_command(Tie::IxHash->new('ping' => 1)); my $command2 = $events[-2]->{ command }; ok $command2->{'$clusterTime'}->{clusterTime} == $result->{'$clusterTime'}->{clusterTime}, "clusterTime matches"; }; clear_events(); subtest 'aggregate' => sub { my $local_client = get_high_heartbeat_client(); my $local_db = get_test_db($local_client); my $local_coll = get_unique_collection($local_db, 'cluster_agg'); $local_coll->insert_many( [ { wanted => 1, score => 56 }, { wanted => 1, score => 72 }, { wanted => 1, score => 96 }, { wanted => 1, score => 32 }, { wanted => 1, score => 61 }, { wanted => 1, score => 33 }, { wanted => 0, score => 1000 } ] ); my $agg_result = $local_coll->aggregate( [ { '$match' => { wanted => 1 } }, { '$group' => { _id => 1, 'avgScore' => { '$avg' => '$score' } } } ] ); my $command = $events[-2]->{ command }; my $result = $events[-1]->{ reply }; ok exists $command->{'aggregate'}, 'aggregate in sent command'; ok exists $command->{'$clusterTime'}, 'clusterTime in sent command'; my $agg_result2 = $local_coll->aggregate( [ { '$match' => { wanted => 1 } }, { '$group' => { _id => 1, 'avgScore' => { '$avg' => '$score' } } } ] ); my $command2 = $events[-2]->{ command }; ok $command2->{'$clusterTime'}->{clusterTime} == $result->{'$clusterTime'}->{clusterTime}, "clusterTime matches"; }; clear_events(); subtest 'find' => sub { my $local_client = get_high_heartbeat_client(); my $local_db = get_test_db($local_client); my $local_coll = get_unique_collection($local_db, 'cluster_find'); $local_coll->insert_one({_id => 1}); # need to actually call ->result to make it touch the database, and # explain 1 to get it to show the whole returned result my $find_result = $local_coll->find({_id => 1})->result; my $command = $events[-2]->{ command }; my $result = $events[-1]->{ reply }; ok exists $command->{'find'}, 'find in sent command'; ok exists $command->{'$clusterTime'}, 'clusterTime in sent command'; my $find_result2 = $local_coll->find({_id => 1})->result; my $command2 = $events[-2]->{ command }; ok $command2->{'$clusterTime'}->{clusterTime} == $result->{'$clusterTime'}->{clusterTime}, "clusterTime matches"; }; clear_events(); subtest 'insert_one' => sub { my $local_client = get_high_heartbeat_client(); my $local_db = get_test_db($local_client); my $local_coll = get_unique_collection($local_db, 'cluster_find'); my $insert_result = $local_coll->insert_one({_id => 1}); my $command = $events[-2]->{ command }; my $result = $events[-1]->{ reply }; ok exists $command->{'insert'}, 'insert in sent command'; ok exists $command->{'$clusterTime'}, 'clusterTime in sent command'; my $insert_result2 = $local_coll->insert_one({_id => 2}); my $command2 = $events[-2]->{ command }; ok $command2->{'$clusterTime'}->{clusterTime} == $result->{'$clusterTime'}->{clusterTime}, "clusterTime matches"; }; }; sub get_high_heartbeat_client { my $local_client = build_client( # You want big number? we give you big number heartbeat_frequency_ms => 9_000_000_000, monitoring_callback => \&event_cb, ); return $local_client; } subtest 'correct session for client' => sub { my $client1 = build_client(); my $client2 = build_client(); ok $client1->_id ne $client2->_id, 'client id is different'; my $db1 = get_test_db($client1); my $coll1 = get_unique_collection($db1, 'cross_session'); my $session = $client2->start_session; subtest 'collection sessions' => sub { test_collection_session_exceptions( $coll1, $session, qr/session from another client/i, "Session from another client fails (%s)", ); }; subtest 'database sessions' => sub { test_db_session_exceptions( $db1, $session, qr/session from another client/i, "Session from another client fails (%s)", ); }; }; subtest 'ended session unusable' => sub { my $client1 = build_client(); my $db1 = get_test_db($client1); my $coll1 = get_unique_collection($db1, 'end_session'); my $session = $client1->start_session; $session->end_session; subtest 'collection sessions' => sub { test_collection_session_exceptions( $coll1, $session, qr/session which has ended/i, "Ended session is unusable (%s)", ); }; subtest 'database sessions' => sub { test_db_session_exceptions( $db1, $session, qr/session which has ended/i, "Ended session is unusable (%s)", ); }; }; sub test_collection_session_exceptions { my ( $coll, $session, $error_regex, $message_string ) = @_; # Done in order of listings in METHODS in pod # indexes? like exception { $coll->insert_one( { _id => 1 }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'insert_one' ); like exception { $coll->insert_many( [ { _id => 1 }, { _id => 2 }, { _id => 3 }, { _id => 4 }, ], { session => $session } ) }, $error_regex, sprintf( $message_string, 'insert_many' ); like exception { $coll->delete_one( { _id => 1 }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'delete_one' ); like exception { $coll->delete_many( { _id => { '$in' => [1,2,3,4] } }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'delete_many' ); like exception { $coll->replace_one( { _id => 1 }, { _id => 1, foo => 'qux' }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'replace_one' ); like exception { $coll->update_one( { _id => 1 }, { '$set' => { foo => 'qux' } }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'update_one' ); like exception { $coll->update_many( { _id => { '$in' => [1,2,3,4] } }, { '$set' => { foo => 'qux' } }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'update_many' ); # Must call result to get it to touch the database like exception { $coll->find( { _id => { '$in' => [1,2,3,4] } }, { session => $session } )->result }, $error_regex, sprintf( $message_string, 'find' ); like exception { $coll->find_one( { _id => 1 }, {}, { session => $session } ) }, $error_regex, sprintf( $message_string, 'find_one' ); like exception { $coll->find_id( 1, {}, { session => $session } ) }, $error_regex, sprintf( $message_string, 'find_id' ); like exception { $coll->find_one_and_delete( { _id => 1 }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'find_one_and_delete' ); like exception { $coll->find_one_and_replace( { _id => 1 }, { _id => 1, foo => 'qux' }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'find_one_and_replace' ); like exception { $coll->find_one_and_update( { _id => 1 }, { '$set' => { foo => 'qux' } }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'find_one_and_update' ); like exception { $coll->aggregate( [ { '$match' => { wanted => 1 } }, { '$group' => { _id => 1, 'avgScore' => { '$avg' => '$score' } } } ], { session => $session } ) }, $error_regex, sprintf( $message_string, 'aggregate' ); like exception { $coll->count_documents( { _id => 1 }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'count' ); like exception { $coll->distinct( "id_", { _id => 1 }, { session => $session } ) }, $error_regex, sprintf( $message_string, 'distinct' ); like exception { $coll->rename( "another_collection_name", { session => $session } ) }, $error_regex, sprintf( $message_string, 'rename' ); like exception { $coll->drop( { session => $session } ) }, $error_regex, sprintf( $message_string, 'drop' ); like exception { my $bulk = $coll->ordered_bulk; $bulk->insert_one( { _id => 1 } ); $bulk->insert_one( { _id => 2 } ); $bulk->execute( undef, { session => $session } ); }, $error_regex, sprintf( $message_string, 'ordered_bulk' ); like exception { my $bulk = $coll->unordered_bulk; $bulk->insert_one( { _id => 1 } ); $bulk->insert_one( { _id => 2 } ); $bulk->execute( undef, { session => $session } ); }, $error_regex, sprintf( $message_string, 'unordered_bulk' ); like exception { $coll->bulk_write( [ insert_one => [ { _id => 1 } ], insert_one => [ { _id => 2 } ], ], { session => $session } ) }, $error_regex, sprintf( $message_string, 'bulk_write' ); } sub test_db_session_exceptions { my ( $db, $session, $error_regex, $message_string ) = @_; like exception { $db->list_collections( {}, { session => $session } ) }, $error_regex, sprintf( $message_string, 'list_collections' ); like exception { $db->collection_names( {}, { session => $session } ) }, $error_regex, sprintf( $message_string, 'collection_names' ); # get_collection makes no sense and I dont think ontacts the database until later # same for get_gridfsbucket ? like exception { $db->drop( { session => $session } ) }, $error_regex, sprintf( $message_string, 'drop' ); like exception { $db->run_command( [ is_master => 1 ], undef, { session => $session } ) }, $error_regex, sprintf( $message_string, 'run_command' ); } clear_testdbs; done_testing;