PYTHON-2773 Mockupdb test failures (#796)

This commit is contained in:
Julius Park 2021-11-17 17:37:05 -08:00 committed by GitHub
parent 12a6af7ab6
commit 9cf88cfdc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 59 additions and 521 deletions

View File

@ -15,6 +15,7 @@
from collections import namedtuple
from mockupdb import *
from mockupdb import OpMsgReply
from pymongo import ReadPreference
__all__ = ['operations', 'upgrades']
@ -51,11 +52,11 @@ secondaries in a replica set, or select a mongos for secondary reads in a
sharded cluster (PYTHON-868).
"""
not_master_reply_to_query = OpReply(
not_master_reply_to_query = OpMsgReply(
{'$err': 'not master'},
flags=REPLY_FLAGS['QueryFailure'])
not_master_reply_to_command = OpReply(ok=0, errmsg='not master')
not_master_reply_to_command = OpMsgReply(ok=0, errmsg='not master')
operations = [
Operation(
@ -76,20 +77,6 @@ operations = [
reply={'cursor': {'id': 0, 'firstBatch': []}},
op_type='may-use-secondary',
not_master=not_master_reply_to_command),
Operation(
'mapreduce',
lambda client: client.db.collection.map_reduce(
'function() {}', 'function() {}'),
reply={'result': {'db': 'db', 'collection': 'out_collection'}},
op_type='must-use-primary',
not_master=not_master_reply_to_command),
Operation(
'inline_mapreduce',
lambda client: client.db.collection.inline_map_reduce(
'function() {}', 'function() {}', {'out': {'inline': 1}}),
reply={'results': []},
op_type='may-use-secondary',
not_master=not_master_reply_to_command),
Operation(
'options',
lambda client: client.db.collection.options(),
@ -109,12 +96,6 @@ operations = [
reply={'ok': 1},
op_type='always-use-secondary',
not_master=OpReply(ok=0, errmsg='node is recovering')),
Operation(
'listCollections',
lambda client: client.db.collection_names(),
reply={'cursor': {'id': 0, 'firstBatch': []}},
op_type='must-use-primary',
not_master=not_master_reply_to_command),
Operation(
'listIndexes',
lambda client: client.db.collection.index_information(),
@ -130,19 +111,9 @@ Upgrade = namedtuple('Upgrade',
['name', 'function', 'old', 'new', 'wire_version'])
upgrades = [
Upgrade('index_information',
lambda client: client.db.collection.index_information(),
old=OpQuery(namespace='db.system.indexes'),
new=Command('listIndexes', 'collection', namespace='db'),
wire_version=3),
Upgrade('collection_names',
lambda client: client.db.collection_names(),
old=Command('aggregate', 'system.namespaces', namespace='db'),
new=Command('listCollections', namespace='db'),
wire_version=3),
Upgrade('options',
lambda client: client.db.collection.options(),
old=Command('aggregate', 'system.namespaces', namespace='db'),
new=Command('listCollections', namespace='db'),
wire_version=3),
Upgrade('estimated_document_count',
lambda client: client.db.collection.estimated_document_count(),
old=OpMsg('count', 'collection', namespace='db'),
new=OpMsg('aggregate', 'collection', namespace='db'),
wire_version=12),
]

View File

@ -44,7 +44,7 @@ class TestAuthRecoveringMember(unittest.TestCase):
# error. If it raises AutoReconnect we know it actually tried the
# server, and that's wrong.
with self.assertRaises(ServerSelectionTimeoutError):
client.db.authenticate('user', 'password')
client.db.command("ping")
if __name__ == '__main__':
unittest.main()

View File

@ -19,8 +19,7 @@ from mockupdb import going, MockupDB
from pymongo import (MongoClient,
InsertOne,
UpdateOne,
DeleteMany,
version_tuple)
DeleteMany)
import unittest
@ -54,23 +53,6 @@ class TestClusterTime(unittest.TestCase):
reply['$clusterTime'] = {'clusterTime': cluster_time}
request.reply(reply)
# Now test that no commands include $clusterTime with wire version 5,
# even though the isMaster reply still has $clusterTime.
server.cancel_responder(responder)
server.autoresponds('ismaster',
{'minWireVersion': 0,
'maxWireVersion': 5,
'$clusterTime': {'clusterTime': cluster_time}})
client = MongoClient(server.uri)
self.addCleanup(client.close)
with going(callback, client):
for reply in replies:
request = server.receives()
self.assertNotIn('$clusterTime', request)
request.reply(reply)
def test_command(self):
def callback(client):
client.db.command('ping')
@ -158,27 +140,16 @@ class TestClusterTime(unittest.TestCase):
request.reply(error)
# PyMongo 3.11+ closes the monitoring connection on command errors.
if version_tuple >= (3, 11, -1):
# Fourth exchange: the Monitor closes the connection and runs the
# handshake on a new connection.
request = server.receives('ismaster')
# No $clusterTime in first ismaster, only in subsequent ones
self.assertNotIn('$clusterTime', request)
# Reply without $clusterTime.
reply.pop('$clusterTime')
request.reply(reply)
else:
# Fourth exchange: the Monitor retry attempt uses the clusterTime
# from the previous isMaster error.
request = server.receives('ismaster')
self.assertEqual(request['$clusterTime']['clusterTime'],
cluster_time)
# Fourth exchange: the Monitor closes the connection and runs the
# handshake on a new connection.
request = server.receives('ismaster')
# No $clusterTime in first ismaster, only in subsequent ones
self.assertNotIn('$clusterTime', request)
cluster_time = Timestamp(cluster_time.time,
cluster_time.inc + 1)
error['$clusterTime'] = {'clusterTime': cluster_time}
request.reply(error)
# Reply without $clusterTime.
reply.pop('$clusterTime')
request.reply(reply)
# Fifth exchange: the Monitor attempt uses the clusterTime from
# the previous isMaster error.

View File

@ -15,7 +15,7 @@
"""Test list_indexes with more than one batch."""
from mockupdb import going, MockupDB
from pymongo import MongoClient, version_tuple
from pymongo import MongoClient
import unittest
@ -57,7 +57,6 @@ class TestCursorNamespace(unittest.TestCase):
return list(self.client.test.collection.aggregate([]))
self._test_cursor_namespace(op, 'aggregate')
@unittest.skipUnless(version_tuple >= (3, 11, -1), 'Fixed in pymongo 3.11')
def test_find_cursor(self):
def op():
return list(self.client.test.collection.find())
@ -71,7 +70,6 @@ class TestCursorNamespace(unittest.TestCase):
class TestKillCursorsNamespace(unittest.TestCase):
@classmethod
@unittest.skipUnless(version_tuple >= (3, 12, -1), 'Fixed in pymongo 3.12')
def setUpClass(cls):
cls.server = MockupDB(auto_ismaster={'maxWireVersion': 6})
cls.server.run()

View File

@ -14,7 +14,7 @@
from mockupdb import MockupDB, OpReply, OpMsg, absent, Command, go
from pymongo import MongoClient, version as pymongo_version, version_tuple
from pymongo import MongoClient, version as pymongo_version
from pymongo.errors import OperationFailure
import unittest
@ -33,7 +33,6 @@ def _check_handshake_data(request):
class TestHandshake(unittest.TestCase):
@unittest.skipUnless(version_tuple >= (3, 4), "requires PyMongo 3.4")
def test_client_handshake_data(self):
primary, secondary = MockupDB(), MockupDB()
for server in primary, secondary:
@ -72,20 +71,14 @@ class TestHandshake(unittest.TestCase):
primary.receives('ismaster', 1, client=absent).ok(error_response)
secondary.receives('ismaster', 1, client=absent).ok(error_response)
# PyMongo 3.11+ closes the monitoring connection on command errors.
if version_tuple >= (3, 11, -1):
# The heartbeat retry (on a new connection) does have client data.
heartbeat = primary.receives('ismaster')
_check_handshake_data(heartbeat)
heartbeat.ok(primary_response)
# The heartbeat retry (on a new connection) does have client data.
heartbeat = primary.receives('ismaster')
_check_handshake_data(heartbeat)
heartbeat.ok(primary_response)
heartbeat = secondary.receives('ismaster')
_check_handshake_data(heartbeat)
heartbeat.ok(secondary_response)
else:
# The heartbeat retry has no client data after a command failure.
primary.receives('ismaster', 1, client=absent).ok(error_response)
secondary.receives('ismaster', 1, client=absent).ok(error_response)
heartbeat = secondary.receives('ismaster')
_check_handshake_data(heartbeat)
heartbeat.ok(secondary_response)
# Still no client data.
primary.receives('ismaster', 1, client=absent).ok(primary_response)
@ -113,15 +106,11 @@ class TestHandshake(unittest.TestCase):
request.ok(primary_response)
else:
# Command succeeds.
if version_tuple >= (3, 7):
request.assert_matches(OpMsg('whatever'))
else:
request.assert_matches(Command('whatever'))
request.assert_matches(OpMsg('whatever'))
request.ok()
assert future()
return
@unittest.skipUnless(version_tuple >= (3, 11, -1), "requires PyMongo 3.11")
def test_client_handshake_saslSupportedMechs(self):
server = MockupDB()
server.run()

View File

@ -1,126 +0,0 @@
# Copyright 2017 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.
from bson.son import SON
from mockupdb import (MockupDB, going, OpInsert, OpMsg, absent, Command,
OP_MSG_FLAGS)
from pymongo import MongoClient, WriteConcern, version_tuple
import unittest
class TestLegacyCRUD(unittest.TestCase):
def test_op_insert_manipulate_false(self):
# Test three aspects of legacy insert with manipulate=False:
# 1. The return value is None, [None], or [None, None] as appropriate.
# 2. _id is not set on the passed-in document object.
# 3. _id is not sent to server.
server = MockupDB(auto_ismaster=True)
server.run()
self.addCleanup(server.stop)
client = MongoClient(server.uri)
self.addCleanup(client.close)
coll = client.db.get_collection('coll', write_concern=WriteConcern(w=0))
doc = {}
with going(coll.insert, doc, manipulate=False) as future:
if version_tuple >= (3, 7):
server.receives(OpMsg(SON([
("insert", coll.name),
("ordered", True),
("writeConcern", {"w": 0}),
("documents", [{}])]), flags=OP_MSG_FLAGS['moreToCome']))
else:
server.receives(OpInsert({'_id': absent}))
self.assertFalse('_id' in doc)
self.assertIsNone(future())
docs = [{}] # One doc in a list.
with going(coll.insert, docs, manipulate=False) as future:
if version_tuple >= (3, 7):
# PyMongo 3.7 ordered bulk w:0 writes use implicit w:1.
request = server.receives()
request.assert_matches(OpMsg(SON([
("insert", coll.name),
("ordered", True),
("documents", [{}])]), flags=0))
request.reply({"n": 1})
else:
server.receives(OpInsert({'_id': absent}))
self.assertFalse('_id' in docs[0])
self.assertEqual(future(), [None])
docs = [{}, {}] # Two docs.
with going(coll.insert, docs, manipulate=False) as future:
if version_tuple >= (3, 7):
# PyMongo 3.7 ordered bulk w:0 writes use implicit w:1.
request = server.receives()
request.assert_matches(OpMsg(SON([
("insert", coll.name),
("ordered", True),
("documents", [{}, {}])]), flags=0))
request.reply({"n": 2})
else:
server.receives(OpInsert({'_id': absent}, {'_id': absent}))
self.assertFalse('_id' in docs[0])
self.assertFalse('_id' in docs[1])
self.assertEqual(future(), [None, None])
def test_insert_command_manipulate_false(self):
# Test same three aspects as test_op_insert_manipulate_false does,
# with the "insert" command.
server = MockupDB(auto_ismaster={'maxWireVersion': 2})
server.run()
self.addCleanup(server.stop)
client = MongoClient(server.uri)
self.addCleanup(client.close)
doc = {}
with going(client.db.coll.insert, doc, manipulate=False) as future:
r = server.receives(Command("insert", "coll", documents=[{}]))
# MockupDB doesn't understand "absent" in subdocuments yet.
self.assertFalse('_id' in r.doc['documents'][0])
r.ok()
self.assertFalse('_id' in doc)
self.assertIsNone(future())
docs = [{}] # One doc in a list.
with going(client.db.coll.insert, docs, manipulate=False) as future:
r = server.receives(Command("insert", "coll", documents=[{}]))
self.assertFalse('_id' in r.doc['documents'][0])
r.ok()
self.assertFalse('_id' in docs[0])
self.assertEqual(future(), [None])
docs = [{}, {}] # Two docs.
with going(client.db.coll.insert, docs, manipulate=False) as future:
r = server.receives(Command("insert", "coll", documents=[{}, {}]))
self.assertFalse('_id' in r.doc['documents'][0])
self.assertFalse('_id' in r.doc['documents'][1])
r.ok()
self.assertFalse('_id' in docs[0])
self.assertFalse('_id' in docs[1])
self.assertEqual(future(), [None, None])
if __name__ == '__main__':
unittest.main()

View File

@ -23,29 +23,6 @@ import unittest
class TestListIndexes(unittest.TestCase):
def test_list_indexes_opquery(self):
server = MockupDB(auto_ismaster={'maxWireVersion': 3})
server.run()
self.addCleanup(server.stop)
client = MongoClient(server.uri)
self.addCleanup(client.close)
with going(client.test.collection.list_indexes) as cursor:
request = server.receives(
listIndexes='collection', namespace='test')
request.reply({'cursor': {
'firstBatch': [{'name': 'index_0'}],
'id': 123}})
with going(list, cursor()) as indexes:
request = server.receives(OpGetMore,
namespace='test.collection',
cursor_id=123)
request.reply([{'name': 'index_1'}], cursor_id=0)
self.assertEqual([{'name': 'index_0'}, {'name': 'index_1'}], indexes())
for index_info in indexes():
self.assertIsInstance(index_info, SON)
def test_list_indexes_command(self):
server = MockupDB(auto_ismaster={'maxWireVersion': 6})

View File

@ -21,7 +21,7 @@ import unittest
class TestMaxStalenessMongos(unittest.TestCase):
def test_mongos(self):
mongos = MockupDB()
mongos.autoresponds('ismaster', maxWireVersion=5,
mongos.autoresponds('ismaster', maxWireVersion=6,
ismaster=True, msg='isdbgrid')
mongos.run()
self.addCleanup(mongos.stop)

View File

@ -21,7 +21,7 @@ try:
except ImportError:
from Queue import Queue
from mockupdb import MockupDB, go
from mockupdb import MockupDB, go, OpMsg
from pymongo import MongoClient
import unittest

View File

@ -15,7 +15,7 @@
import itertools
from bson import SON
from mockupdb import MockupDB, going
from mockupdb import MockupDB, going, OpMsg, go
from pymongo import MongoClient, ReadPreference
from pymongo.read_preferences import (make_read_preference,
read_pref_mode_from_name,
@ -29,7 +29,7 @@ class TestMongosCommandReadMode(unittest.TestCase):
def test_aggregate(self):
server = MockupDB()
server.autoresponds('ismaster', ismaster=True, msg='isdbgrid',
minWireVersion=2, maxWireVersion=5)
minWireVersion=2, maxWireVersion=6)
self.addCleanup(server.stop)
server.run()
@ -39,18 +39,16 @@ class TestMongosCommandReadMode(unittest.TestCase):
with going(collection.aggregate, []):
command = server.receives(aggregate='collection', pipeline=[])
self.assertFalse(command.slave_ok, 'SlaveOkay set')
self.assertNotIn('$readPreference', command)
command.ok(result=[{}])
secondary_collection = collection.with_options(
read_preference=ReadPreference.SECONDARY)
with going(secondary_collection.aggregate, []):
command = server.receives(
{'$query': SON([('aggregate', 'collection'),
('pipeline', []),
('cursor', {})]),
'$readPreference': {'mode': 'secondary'}})
command = server.receives(OpMsg({"aggregate": "collection",
"pipeline": [],
'$readPreference': {'mode': 'secondary'}}))
command.ok(result=[{}])
self.assertTrue(command.slave_ok, 'SlaveOkay not set')
@ -61,37 +59,28 @@ def create_mongos_read_mode_test(mode, operation):
self.addCleanup(server.stop)
server.run()
server.autoresponds('ismaster', ismaster=True, msg='isdbgrid',
minWireVersion=2, maxWireVersion=5)
minWireVersion=2, maxWireVersion=6)
pref = make_read_preference(read_pref_mode_from_name(mode),
tag_sets=None)
client = MongoClient(server.uri, read_preference=pref)
self.addCleanup(client.close)
with going(operation.function, client) as future:
with going(operation.function, client):
request = server.receive()
request.reply(operation.reply)
future() # No error.
if operation.op_type == 'always-use-secondary':
self.assertEqual(ReadPreference.SECONDARY.document,
request.doc.get('$readPreference'))
slave_ok = mode != 'primary'
self.assertIn('$query', request.doc)
elif operation.op_type == 'must-use-primary':
self.assertNotIn('$readPreference', request)
self.assertNotIn('$query', request.doc)
slave_ok = False
elif operation.op_type == 'may-use-secondary':
slave_ok = mode != 'primary'
if mode in ('primary', 'secondaryPreferred'):
self.assertNotIn('$readPreference', request)
self.assertNotIn('$query', request.doc)
else:
self.assertEqual(pref.document,
request.doc.get('$readPreference'))
self.assertIn('$query', request.doc)
self.assertEqual(pref.document,
request.doc.get('$readPreference'))
else:
self.fail('unrecognized op_type %r' % operation.op_type)

View File

@ -15,7 +15,7 @@
from collections import namedtuple
from mockupdb import MockupDB, going, OpMsg, OpMsgReply, OP_MSG_FLAGS
from pymongo import MongoClient, WriteConcern, version_tuple
from pymongo import MongoClient, WriteConcern
from pymongo.operations import InsertOne, UpdateOne, DeleteOne
from pymongo.cursor import CursorType
@ -125,54 +125,6 @@ operations = [
request=OpMsg({"delete": "coll"}, flags=OP_MSG_FLAGS['moreToCome']),
reply=None),
# Legacy methods
Operation(
'insert',
lambda coll: coll.insert({}),
request=OpMsg({"insert": "coll"}, flags=0),
reply={'ok': 1, 'n': 1}),
Operation(
'insert-w0',
lambda coll: coll.with_options(
write_concern=WriteConcern(w=0)).insert({}),
request=OpMsg({"insert": "coll"}, flags=OP_MSG_FLAGS['moreToCome']),
reply=None),
Operation(
'insert-w0-argument',
lambda coll: coll.insert({}, w=0),
request=OpMsg({"insert": "coll"}, flags=OP_MSG_FLAGS['moreToCome']),
reply=None),
Operation(
'update',
lambda coll: coll.update({"_id": 1}, {"new": 1}),
request=OpMsg({"update": "coll"}, flags=0),
reply={'ok': 1, 'n': 1, 'nModified': 1}),
Operation(
'update-w0',
lambda coll: coll.with_options(
write_concern=WriteConcern(w=0)).update({"_id": 1}, {"new": 1}),
request=OpMsg({"update": "coll"}, flags=OP_MSG_FLAGS['moreToCome']),
reply=None),
Operation(
'update-w0-argument',
lambda coll: coll.update({"_id": 1}, {"new": 1}, w=0),
request=OpMsg({"update": "coll"}, flags=OP_MSG_FLAGS['moreToCome']),
reply=None),
Operation(
'remove',
lambda coll: coll.remove({"_id": 1}),
request=OpMsg({"delete": "coll"}, flags=0),
reply={'ok': 1, 'n': 1}),
Operation(
'remove-w0',
lambda coll: coll.with_options(
write_concern=WriteConcern(w=0)).remove({"_id": 1}),
request=OpMsg({"delete": "coll"}, flags=OP_MSG_FLAGS['moreToCome']),
reply=None),
Operation(
'remove-w0-argument',
lambda coll: coll.remove({"_id": 1}, w=0),
request=OpMsg({"delete": "coll"}, flags=OP_MSG_FLAGS['moreToCome']),
reply=None),
Operation(
'bulk_write_insert',
lambda coll: coll.bulk_write([InsertOne({}), InsertOne({})]),
@ -303,8 +255,7 @@ class TestOpMsg(unittest.TestCase):
replies = [op.reply]
for expected_request in expected_requests:
request = self.server.receives()
request.assert_matches(expected_request)
request = self.server.receives(expected_request)
reply = None
if replies:
reply = replies.pop(0)
@ -317,24 +268,21 @@ class TestOpMsg(unittest.TestCase):
future() # No error.
def operation_test(op, decorator):
@decorator()
def operation_test(op):
def test(self):
self._test_operation(op)
return test
def create_tests(ops, decorator):
def create_tests(ops):
for op in ops:
test_name = "test_op_msg_%s" % (op.name,)
setattr(TestOpMsg, test_name, operation_test(op, decorator))
setattr(TestOpMsg, test_name, operation_test(op))
create_tests(operations, lambda: unittest.skipUnless(
version_tuple >= (3, 7), "requires PyMongo 3.7"))
create_tests(operations)
create_tests(operations_312, lambda: unittest.skipUnless(
version_tuple >= (3, 12), "requires PyMongo 3.12"))
create_tests(operations_312)
if __name__ == '__main__':
unittest.main()

View File

@ -16,7 +16,7 @@ import copy
import itertools
from mockupdb import MockupDB, going, CommandBase
from pymongo import MongoClient, ReadPreference, version_tuple
from pymongo import MongoClient, ReadPreference
from pymongo.read_preferences import (make_read_preference,
read_pref_mode_from_name,
_MONGOS_MODES)
@ -31,8 +31,6 @@ class OpMsgReadPrefBase(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(OpMsgReadPrefBase, cls).setUpClass()
if version_tuple < (3, 7):
raise unittest.SkipTest("requires PyMongo 3.7")
@classmethod
def add_test(cls, mode, test_name, test):
@ -159,11 +157,10 @@ def create_op_msg_read_mode_test(mode, operation):
expected_pref = pref
else:
self.fail('unrecognized op_type %r' % operation.op_type)
# For single mongod we send primaryPreferred instead of primary.
if expected_pref == ReadPreference.PRIMARY and self.single_mongod:
if (expected_pref == ReadPreference.PRIMARY and self.single_mongod
and operation.name != "command"):
expected_pref = ReadPreference.PRIMARY_PREFERRED
with going(operation.function, client) as future:
request = expected_server.receive()
request.reply(operation.reply)

View File

@ -1,56 +0,0 @@
# 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.
"""PyMongo shouldn't append projection fields to "find" command, PYTHON-1479."""
from bson import SON
from mockupdb import Command, MockupDB, OpQuery, going
from pymongo import MongoClient
import unittest
class TestProjection(unittest.TestCase):
def test_projection(self):
q = {}
fields = {'foo': True}
# OP_QUERY,
server = MockupDB(auto_ismaster=True,
min_wire_version=0, max_wire_version=3)
server.run()
self.addCleanup(server.stop)
client = MongoClient(server.uri)
cursor = client.test.collection.find(q, fields)
with going(next, cursor):
request = server.receives(OpQuery(q, fields=fields))
request.reply([], cursor_id=0)
# "find" command.
server = MockupDB(auto_ismaster=True,
min_wire_version=0, max_wire_version=4)
server.run()
self.addCleanup(server.stop)
client = MongoClient(server.uri)
cursor = client.test.collection.find(q, fields)
cmd = Command(SON([('find', 'collection'), ('filter', q),
('projection', fields)]))
with going(next, cursor):
request = server.receives(cmd)
request.ok(cursor={'id': 0, 'firstBatch': []})
if __name__ == '__main__':
unittest.main()

View File

@ -15,59 +15,18 @@
"""Test PyMongo query and read preference with a sharded cluster."""
from bson import SON
from pymongo import MongoClient, version_tuple
from pymongo import MongoClient
from pymongo.read_preferences import (Primary,
PrimaryPreferred,
Secondary,
SecondaryPreferred,
Nearest)
from mockupdb import MockupDB, going, Command, OpMsg
from mockupdb import MockupDB, going, OpMsg
import unittest
class TestQueryAndReadModeSharded(unittest.TestCase):
def test_query_and_read_mode_sharded_op_query(self):
server = MockupDB()
server.autoresponds('ismaster', ismaster=True, msg='isdbgrid',
minWireVersion=2, maxWireVersion=5)
server.run()
self.addCleanup(server.stop)
client = MongoClient(server.uri)
self.addCleanup(client.close)
modes_without_query = (
Primary(),
SecondaryPreferred(),)
modes_with_query = (
PrimaryPreferred(),
Secondary(),
Nearest(),
SecondaryPreferred([{'tag': 'value'}]),)
find_command = SON([('find', 'test'), ('filter', {'a': 1})])
for query in ({'a': 1}, {'$query': {'a': 1}},):
for mode in modes_with_query + modes_without_query:
collection = client.db.get_collection('test',
read_preference=mode)
cursor = collection.find(query.copy())
with going(next, cursor):
request = server.receives()
if mode in modes_without_query:
# Filter is hoisted out of $query.
request.assert_matches(Command(find_command))
self.assertFalse('$readPreference' in request)
else:
# Command is nested in $query.
request.assert_matches(Command(
SON([('$query', find_command),
('$readPreference', mode.document)])))
request.replies({'cursor': {'id': 0, 'firstBatch': [{}]}})
@unittest.skipUnless(version_tuple >= (3, 7), "requires PyMongo 3.7")
def test_query_and_read_mode_sharded_op_msg(self):
"""Test OP_MSG sends non-primary $readPreference and never $query."""
server = MockupDB()

View File

@ -18,7 +18,7 @@ import itertools
from mockupdb import MockupDB, going, wait_until
from pymongo.server_type import SERVER_TYPE
from pymongo.errors import ConnectionFailure
from pymongo import MongoClient, version_tuple
from pymongo import MongoClient
import unittest
from operations import operations
@ -44,8 +44,7 @@ class TestResetAndRequestCheck(unittest.TestCase):
kwargs = {'socketTimeoutMS': 100}
# Disable retryable reads when pymongo supports it.
if version_tuple[:3] >= (3, 9):
kwargs['retryReads'] = False
kwargs['retryReads'] = False
self.client = MongoClient(self.server.uri, **kwargs)
wait_until(lambda: self.client.nodes, 'connect to standalone')
@ -103,8 +102,9 @@ class TestResetAndRequestCheck(unittest.TestCase):
with self.assertRaises(ConnectionFailure):
with going(operation.function, self.client):
self.server.receives().replies(operation.not_master)
request = self.server.receives()
before = self.ismaster_time
request.replies(operation.not_master)
time.sleep(1)
# Server is rediscovered.
@ -139,6 +139,7 @@ def generate_reset_tests():
test.__name__ = test_name
setattr(TestResetAndRequestCheck, test_name, test)
generate_reset_tests()
if __name__ == '__main__':

View File

@ -67,11 +67,7 @@ def create_slave_ok_single_test(mode, server_type, ismaster, operation):
request = self.server.receive()
request.reply(operation.reply)
self.assertEqual(topology_type_name(client), 'Single')
if slave_ok:
self.assertTrue(request.slave_ok, 'SlaveOkay not set')
else:
self.assertFalse(request.slave_ok, 'SlaveOkay set')
self.assertIn(topology_type_name(client), ['Sharded', 'Single'])
return test

View File

@ -1,76 +0,0 @@
# Copyright 2015 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.
"""Test that PyMongo ignores the startingFrom field, PYTHON-945."""
from mockupdb import going, MockupDB, OpGetMore, OpQuery, Command
from pymongo import MongoClient
import unittest
class TestStartingFromOverflow(unittest.TestCase):
def test_query(self):
server = MockupDB(auto_ismaster=True,
min_wire_version=0, max_wire_version=3)
server.run()
self.addCleanup(server.stop)
client = MongoClient(server.uri)
cursor = client.test.collection.find()
with going(list, cursor) as docs:
request = server.receives(OpQuery)
request.reply({'a': 1}, cursor_id=123, starting_from=-7)
request = server.receives(OpGetMore, cursor_id=123)
request.reply({'a': 2}, starting_from=-3, cursor_id=0)
self.assertEqual([{'a': 1}, {'a': 2}], docs())
def test_aggregate(self):
server = MockupDB(auto_ismaster={'maxWireVersion': 3})
server.run()
self.addCleanup(server.stop)
client = MongoClient(server.uri)
with going(client.test.collection.aggregate, []) as cursor:
request = server.receives(Command)
request.reply({'cursor': {
'id': 123,
'firstBatch': [{'a': 1}]}})
with going(list, cursor()) as docs:
request = server.receives(OpGetMore, cursor_id=123)
request.reply({'a': 2}, starting_from=-3, cursor_id=0)
self.assertEqual([{'a': 1}, {'a': 2}], docs())
def test_find_command(self):
server = MockupDB(auto_ismaster={'maxWireVersion': 4})
server.run()
self.addCleanup(server.stop)
client = MongoClient(server.uri)
with going(list, client.test.collection.find()) as docs:
server.receives(Command).reply({'cursor': {
'id': 123,
'firstBatch': [{'a': 1}]}})
request = server.receives(Command("getMore", 123))
request.reply({'cursor': {
'id': 0,
'nextBatch': [{'a': 2}]}},
starting_from=-3)
self.assertEqual([{'a': 1}, {'a': 2}], docs())
if __name__ == '__main__':
unittest.main()