diff --git a/test/mockupdb/operations.py b/test/mockupdb/operations.py index 2c8701ae8..9fb0ca16b 100644 --- a/test/mockupdb/operations.py +++ b/test/mockupdb/operations.py @@ -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), ] diff --git a/test/mockupdb/test_auth_recovering_member.py b/test/mockupdb/test_auth_recovering_member.py index 360c593a0..6fb983b37 100755 --- a/test/mockupdb/test_auth_recovering_member.py +++ b/test/mockupdb/test_auth_recovering_member.py @@ -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() diff --git a/test/mockupdb/test_cluster_time.py b/test/mockupdb/test_cluster_time.py index fae6c3faa..858e32a0f 100644 --- a/test/mockupdb/test_cluster_time.py +++ b/test/mockupdb/test_cluster_time.py @@ -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. diff --git a/test/mockupdb/test_cursor_namespace.py b/test/mockupdb/test_cursor_namespace.py index 600f7bca6..10605601c 100644 --- a/test/mockupdb/test_cursor_namespace.py +++ b/test/mockupdb/test_cursor_namespace.py @@ -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() diff --git a/test/mockupdb/test_handshake.py b/test/mockupdb/test_handshake.py index 9dbdec305..621f01728 100644 --- a/test/mockupdb/test_handshake.py +++ b/test/mockupdb/test_handshake.py @@ -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() diff --git a/test/mockupdb/test_legacy_crud.py b/test/mockupdb/test_legacy_crud.py deleted file mode 100755 index 508313dbb..000000000 --- a/test/mockupdb/test_legacy_crud.py +++ /dev/null @@ -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() diff --git a/test/mockupdb/test_list_indexes.py b/test/mockupdb/test_list_indexes.py index 7483e80df..b4787ff62 100644 --- a/test/mockupdb/test_list_indexes.py +++ b/test/mockupdb/test_list_indexes.py @@ -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}) diff --git a/test/mockupdb/test_max_staleness.py b/test/mockupdb/test_max_staleness.py index 89d17a133..9bd65a176 100644 --- a/test/mockupdb/test_max_staleness.py +++ b/test/mockupdb/test_max_staleness.py @@ -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) diff --git a/test/mockupdb/test_mixed_version_sharded.py b/test/mockupdb/test_mixed_version_sharded.py index 9f57dd0f4..d13af3562 100644 --- a/test/mockupdb/test_mixed_version_sharded.py +++ b/test/mockupdb/test_mixed_version_sharded.py @@ -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 diff --git a/test/mockupdb/test_mongos_command_read_mode.py b/test/mockupdb/test_mongos_command_read_mode.py index 1fe2ea586..ccd40c2cd 100644 --- a/test/mockupdb/test_mongos_command_read_mode.py +++ b/test/mockupdb/test_mongos_command_read_mode.py @@ -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) diff --git a/test/mockupdb/test_op_msg.py b/test/mockupdb/test_op_msg.py index dc574226b..35e70cebf 100755 --- a/test/mockupdb/test_op_msg.py +++ b/test/mockupdb/test_op_msg.py @@ -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() diff --git a/test/mockupdb/test_op_msg_read_preference.py b/test/mockupdb/test_op_msg_read_preference.py index 925a00f6a..ba359a5e0 100644 --- a/test/mockupdb/test_op_msg_read_preference.py +++ b/test/mockupdb/test_op_msg_read_preference.py @@ -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) diff --git a/test/mockupdb/test_projection.py b/test/mockupdb/test_projection.py deleted file mode 100644 index 0b74c22cb..000000000 --- a/test/mockupdb/test_projection.py +++ /dev/null @@ -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() diff --git a/test/mockupdb/test_query_read_pref_sharded.py b/test/mockupdb/test_query_read_pref_sharded.py index 033cdeff1..21813f7b8 100644 --- a/test/mockupdb/test_query_read_pref_sharded.py +++ b/test/mockupdb/test_query_read_pref_sharded.py @@ -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() diff --git a/test/mockupdb/test_reset_and_request_check.py b/test/mockupdb/test_reset_and_request_check.py index 27b55f318..86c2085e3 100755 --- a/test/mockupdb/test_reset_and_request_check.py +++ b/test/mockupdb/test_reset_and_request_check.py @@ -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__': diff --git a/test/mockupdb/test_slave_okay_single.py b/test/mockupdb/test_slave_okay_single.py index 4a0725a86..83c0f925a 100644 --- a/test/mockupdb/test_slave_okay_single.py +++ b/test/mockupdb/test_slave_okay_single.py @@ -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 diff --git a/test/mockupdb/test_starting_from_overflow.py b/test/mockupdb/test_starting_from_overflow.py deleted file mode 100644 index d94cab0ff..000000000 --- a/test/mockupdb/test_starting_from_overflow.py +++ /dev/null @@ -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()