PYTHON-2773 Mockupdb test failures (#796)
This commit is contained in:
parent
12a6af7ab6
commit
9cf88cfdc1
@ -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),
|
||||
]
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
@ -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})
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
@ -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()
|
||||
|
||||
@ -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__':
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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()
|
||||
Loading…
Reference in New Issue
Block a user