1use Mojo::Base -strict; 2 3use Test::More; 4 5plan skip_all => 'set TEST_ONLINE to enable this test' 6 unless $ENV{TEST_ONLINE}; 7 8use Mango; 9use Mojo::IOLoop; 10use Mojo::IOLoop::Server; 11 12# Defaults 13my $mango = Mango->new; 14is_deeply $mango->hosts, [['localhost']], 'right hosts'; 15is $mango->default_db, 'admin', 'right default database'; 16is $mango->inactivity_timeout, 0, 'right timeout value'; 17is $mango->j, 0, 'right j value'; 18is $mango->w, 1, 'right w value'; 19is $mango->wtimeout, 1000, 'right wtimeout value'; 20is $mango->backlog, 0, 'no operations waiting'; 21 22# Simple connection string 23$mango = Mango->new('mongodb://127.0.0.1:3000'); 24is_deeply $mango->hosts, [['127.0.0.1', 3000]], 'right hosts'; 25is $mango->default_db, 'admin', 'right default database'; 26is $mango->j, 0, 'right j value'; 27is $mango->w, 1, 'right w value'; 28is $mango->wtimeout, 1000, 'right wtimeout value'; 29 30# Complex connection string 31$mango = Mango->new( 32 'mongodb://x1:y2@foo.bar:5000,baz:3000/test?journal=1&w=2&wtimeoutMS=2000'); 33is_deeply $mango->hosts, [['foo.bar', 5000], ['baz', 3000]], 'right hosts'; 34is $mango->default_db, 'test', 'right default database'; 35is $mango->j, 1, 'right j value'; 36is $mango->w, 2, 'right w value'; 37is $mango->wtimeout, 2000, 'right wtimeout value'; 38is $mango->db->name, 'test', 'right database name'; 39 40# Invalid connection string 41eval { Mango->new('http://localhost:3000/test') }; 42like $@, qr/Invalid MongoDB connection string/, 'right error'; 43 44# No port 45$mango = Mango->new->from_string('mongodb://127.0.0.1,127.0.0.1:5000'); 46is_deeply $mango->hosts, [['127.0.0.1'], ['127.0.0.1', 5000]], 'right hosts'; 47 48# Connection error 49my $port = Mojo::IOLoop::Server->generate_port; 50eval { Mango->new("mongodb://127.0.0.1:$port/test")->db->command('getnonce') }; 51ok $@, 'has error'; 52 53# Clean up before start 54$mango = Mango->new($ENV{TEST_ONLINE}); 55my $collection = $mango->db->collection('connection_test'); 56$collection->drop if $collection->options; 57 58# Blocking CRUD 59my $oid = $collection->insert({foo => 'bar'}); 60is $mango->backlog, 0, 'no operations waiting'; 61isa_ok $oid, 'Mango::BSON::ObjectID', 'right class'; 62my $doc = $collection->find_one({foo => 'bar'}); 63is_deeply $doc, {_id => $oid, foo => 'bar'}, 'right document'; 64$doc->{foo} = 'yada'; 65is $collection->update({foo => 'bar'}, $doc)->{n}, 1, 'one document updated'; 66$doc = $collection->find_one($oid); 67is_deeply $doc, {_id => $oid, foo => 'yada'}, 'right document'; 68is $collection->remove->{n}, 1, 'one document removed'; 69 70# Non-blocking CRUD 71my ($fail, $backlog, $created, $updated, $found, $removed); 72my $delay = Mojo::IOLoop->delay( 73 sub { 74 my $delay = shift; 75 $collection->insert({foo => 'bar'} => $delay->begin); 76 $backlog = $collection->db->mango->backlog; 77 }, 78 sub { 79 my ($delay, $err, $oid) = @_; 80 return $delay->pass($err) if $err; 81 $created = $oid; 82 $collection->find_one({foo => 'bar'} => $delay->begin); 83 }, 84 sub { 85 my ($delay, $err, $doc) = @_; 86 return $delay->pass($err) if $err; 87 $doc->{foo} = 'yada'; 88 $collection->update(({foo => 'bar'}, $doc) => $delay->begin); 89 }, 90 sub { 91 my ($delay, $err, $doc) = @_; 92 return $delay->pass($err) if $err; 93 $updated = $doc; 94 $collection->find_one($created => $delay->begin); 95 }, 96 sub { 97 my ($delay, $err, $doc) = @_; 98 return $delay->pass($err) if $err; 99 $found = $doc; 100 $collection->remove($delay->begin); 101 }, 102 sub { 103 my ($delay, $err, $doc) = @_; 104 $fail = $err; 105 $removed = $doc; 106 } 107); 108$delay->wait; 109ok !$fail, 'no error'; 110is $backlog, 1, 'one operation waiting'; 111isa_ok $created, 'Mango::BSON::ObjectID', 'right class'; 112is $updated->{n}, 1, 'one document updated'; 113is_deeply $found, {_id => $created, foo => 'yada'}, 'right document'; 114is $removed->{n}, 1, 'one document removed'; 115 116# Error in callback 117Mojo::IOLoop->singleton->reactor->unsubscribe('error'); 118$fail = undef; 119Mojo::IOLoop->singleton->reactor->once( 120 error => sub { $fail .= pop; Mojo::IOLoop->stop }); 121$collection->insert({foo => 'bar'} => sub { die 'Oops!' }); 122Mojo::IOLoop->start; 123like $fail, qr/Oops!/, 'right error'; 124is $collection->remove->{n}, 1, 'one document removed'; 125 126# Fork safety 127$mango = Mango->new($ENV{TEST_ONLINE}); 128$collection = $mango->db->collection('connection_test'); 129my ($connections, $current); 130$mango->on( 131 connection => sub { 132 my ($mango, $id) = @_; 133 $connections++; 134 $current = $id; 135 } 136); 137is $collection->find->count, 0, 'no documents'; 138is $connections, 1, 'one connection'; 139ok $mango->ioloop->stream($current), 'connection exists'; 140my $last = $current; 141is $collection->find->count, 0, 'no documents'; 142is $connections, 1, 'one connection'; 143ok $mango->ioloop->stream($current), 'connection exists'; 144is $last, $current, 'same connection'; 145{ 146 local $$ = -23; 147 is $collection->find->count, 0, 'no documents'; 148 is $connections, 2, 'two connections'; 149 ok $mango->ioloop->stream($current), 'connection exists'; 150 isnt $last, $current, 'different connections'; 151 $last = $current; 152 is $collection->find->count, 0, 'no documents'; 153 is $connections, 2, 'two connections'; 154 ok $mango->ioloop->stream($current), 'connection exists'; 155 is $last, $current, 'same connection'; 156} 157 158# Mixed concurrent operations 159$collection->insert({test => $_}) for 1 .. 3; 160is $mango->backlog, 0, 'no operations waiting'; 161my @results; 162$delay = Mojo::IOLoop->delay(sub { shift; @results = @_ }); 163$collection->find_one(({test => $_}, {_id => 0}) => $delay->begin) for 1 .. 3; 164is $mango->backlog, 3, 'three operations waiting'; 165is $collection->find_one({test => 1})->{test}, 1, 'right result'; 166$delay->wait; 167is $mango->backlog, 0, 'no operations waiting'; 168ok !$results[0], 'no error'; 169is_deeply $results[1], {test => 1}, 'right result'; 170ok !$results[2], 'no error'; 171is_deeply $results[3], {test => 2}, 'right result'; 172ok !$results[4], 'no error'; 173is_deeply $results[5], {test => 3}, 'right result'; 174is $collection->remove->{n}, 3, 'three documents removed'; 175 176# Fallback server 177$mango = Mango->new($ENV{TEST_ONLINE}); 178$port = Mojo::IOLoop::Server->generate_port; 179unshift @{$mango->hosts}, ['127.0.0.1', $port]; 180ok $mango->db->command('getnonce')->{nonce}, 'command was successful'; 181is_deeply $mango->hosts->[0], ['127.0.0.1', $port], 'right server'; 182ok scalar @{$mango->hosts} > 1, 'more than one server'; 183 184done_testing(); 185