Update the test matrix to reflect what's supported in 2019 (#2066)

Previously, we were running the test suite for several combinations of MongoDB,
Python, and PyMongo:
- PyPy, MongoDB v2.6, PyMongo v3.x (which really means v3.6.1 at the moment)
- Python v2.7, MongoDB v2.6, PyMongo v3.x
- Python v3.5, MongoDB v2.6, PyMongo v3.x
- Python v3.6, MongoDB v2.6, PyMongo v3.x
- Python v2.7, MongoDB v3.0, PyMongo v3.5.0
- Python v3.6, MongoDB v3.0, PyMongo v3.5.0
- Python v3.5, MongoDB v3.2, PyMongo v3.x
- Python v3.6, MongoDB v3.2, PyMongo v3.x
- Python v3.6, MongoDB v3.4, PyMongo v3.x
- Python v3.6, MongoDB v3.6, PyMongo v3.x

There were a couple issues with this setup:
1. MongoDB v2.6 – v3.2 have reached their End of Life already (v2.6 almost 3
   years ago!). See the "MongoDB Server" section on
   https://www.mongodb.com/support-policy.
2. We were only testing two recent-ish PyMongo versions (v3.5.0 & v3.6.1).
   We were not testing the oldest actively supported MongoDB/PyMongo/Python
   setup.

This PR updates the test matrix so that these problems are solved. For the
sake of simplicity, it does not yet attempt to cover MongoDB v4.0:
- PyPy, MongoDB v3.4, PyMongo v3.x (aka v3.6.1 at the moment)
- Python v2.7, MongoDB v3.4, PyMongo v3.x
- Python v3.5, MongoDB v3.4, PyMongo v3.x
- Python v3.6, MongoDB v3.4, PyMongo v3.x
- Python v2.7, MongoDB v3.4, PyMongo v3.4
- Python v3.6, MongoDB v3.6, PyMongo v3.x
This commit is contained in:
Stefan Wójcik 2019-05-31 11:01:15 +02:00 committed by GitHub
parent da3773bfe8
commit 4334955e39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 105 additions and 161 deletions

View File

@ -2,11 +2,18 @@
# PyMongo combinations. However, that would result in an overly long build # PyMongo combinations. However, that would result in an overly long build
# with a very large number of jobs, hence we only test a subset of all the # with a very large number of jobs, hence we only test a subset of all the
# combinations: # combinations:
# * MongoDB v2.6 is currently the "main" version tested against Python v2.7, # * MongoDB v3.4 & the latest PyMongo v3.x is currently the "main" setup,
# v3.5, v3.6, PyPy, and PyMongo v3.x. # tested against Python v2.7, v3.5, v3.6, and PyPy.
# * MongoDB v3.0 & v3.2 are tested against Python v2.7, v3.5 & v3.6 # * Besides that, we test the lowest actively supported Python/MongoDB/PyMongo
# and Pymongo v3.5 & v3.x # combination: MongoDB v3.4, PyMongo v3.4, Python v2.7.
# * MongoDB v3.4 is tested against v3.6 and Pymongo v3.x # * MongoDB v3.6 is tested against Python v3.6, and PyMongo v3.6, v3.7, v3.8.
#
# We should periodically check MongoDB Server versions supported by MongoDB
# Inc., add newly released versions to the test matrix, and remove versions
# which have reached their End of Life. See:
# 1. https://www.mongodb.com/support-policy.
# 2. https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#python-driver-compatibility
#
# Reminder: Update README.rst if you change MongoDB versions we test. # Reminder: Update README.rst if you change MongoDB versions we test.
language: python language: python
@ -18,7 +25,7 @@ python:
- pypy - pypy
env: env:
- MONGODB=2.6 PYMONGO=3.x - MONGODB=3.4 PYMONGO=3.x
matrix: matrix:
# Finish the build as soon as one job fails # Finish the build as soon as one job fails
@ -26,15 +33,7 @@ matrix:
include: include:
- python: 2.7 - python: 2.7
env: MONGODB=3.0 PYMONGO=3.5 env: MONGODB=3.4 PYMONGO=3.4.x
- python: 3.5
env: MONGODB=3.2 PYMONGO=3.x
- python: 3.6
env: MONGODB=3.0 PYMONGO=3.5
- python: 3.6
env: MONGODB=3.2 PYMONGO=3.x
- python: 3.6
env: MONGODB=3.4 PYMONGO=3.x
- python: 3.6 - python: 3.6
env: MONGODB=3.6 PYMONGO=3.x env: MONGODB=3.6 PYMONGO=3.x
@ -86,15 +85,15 @@ deploy:
password: password:
secure: QMyatmWBnC6ZN3XLW2+fTBDU4LQcp1m/LjR2/0uamyeUzWKdlOoh/Wx5elOgLwt/8N9ppdPeG83ose1jOz69l5G0MUMjv8n/RIcMFSpCT59tGYqn3kh55b0cIZXFT9ar+5cxlif6a5rS72IHm5li7QQyxexJIII6Uxp0kpvUmek= secure: QMyatmWBnC6ZN3XLW2+fTBDU4LQcp1m/LjR2/0uamyeUzWKdlOoh/Wx5elOgLwt/8N9ppdPeG83ose1jOz69l5G0MUMjv8n/RIcMFSpCT59tGYqn3kh55b0cIZXFT9ar+5cxlif6a5rS72IHm5li7QQyxexJIII6Uxp0kpvUmek=
# create a source distribution and a pure python wheel for faster installs # Create a source distribution and a pure python wheel for faster installs.
distributions: "sdist bdist_wheel" distributions: "sdist bdist_wheel"
# only deploy on tagged commits (aka GitHub releases) and only for the # Only deploy on tagged commits (aka GitHub releases) and only for the parent
# parent repo's builds running Python 2.7 along with PyMongo v3.x (we run # repo's builds running Python v2.7 along with PyMongo v3.x and MongoDB v3.4.
# Travis against many different Python and PyMongo versions and we don't # We run Travis against many different Python, PyMongo, and MongoDB versions
# want the deploy to occur multiple times). # and we don't want the deploy to occur multiple times).
on: on:
tags: true tags: true
repo: MongoEngine/mongoengine repo: MongoEngine/mongoengine
condition: "$PYMONGO = 3.x" condition: ($PYMONGO = 3.x) AND ($MONGODB = 3.4)
python: 2.7 python: 2.7

View File

@ -26,10 +26,10 @@ an `API reference <https://mongoengine-odm.readthedocs.io/apireference.html>`_.
Supported MongoDB Versions Supported MongoDB Versions
========================== ==========================
MongoEngine is currently tested against MongoDB v2.6, v3.0, v3.2, v3.4 and v3.6. Future MongoEngine is currently tested against MongoDB v3.4 and v3.6. Future versions
versions should be supported as well, but aren't actively tested at the moment. should be supported as well, but aren't actively tested at the moment. Make
Make sure to open an issue or submit a pull request if you experience any sure to open an issue or submit a pull request if you experience any problems
problems with MongoDB v3.6+. with MongoDB version > 3.6.
Installation Installation
============ ============

View File

@ -117,10 +117,22 @@ def _get_connection_settings(
ReadPreference.PRIMARY, ReadPreference.PRIMARY,
ReadPreference.PRIMARY_PREFERRED, ReadPreference.PRIMARY_PREFERRED,
ReadPreference.SECONDARY, ReadPreference.SECONDARY,
ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED,
read_pf_mode = uri_options['readpreference'].lower() )
# Starting with PyMongo v3.5, the "readpreference" option is
# returned as a string (e.g. "secondaryPreferred") and not an
# int (e.g. 3).
# TODO simplify the code below once we drop support for
# PyMongo v3.4.
read_pf_mode = uri_options['readpreference']
if isinstance(read_pf_mode, six.string_types):
read_pf_mode = read_pf_mode.lower()
for preference in read_preferences: for preference in read_preferences:
if preference.name.lower() == read_pf_mode: if (
preference.name.lower() == read_pf_mode or
preference.mode == read_pf_mode
):
conn_settings['read_preference'] = preference conn_settings['read_preference'] = preference
break break
else: else:

View File

@ -7,10 +7,6 @@ from mongoengine.connection import get_connection
# Constant that can be used to compare the version retrieved with # Constant that can be used to compare the version retrieved with
# get_mongodb_version() # get_mongodb_version()
MONGODB_36 = (3, 6) MONGODB_36 = (3, 6)
MONGODB_34 = (3, 4)
MONGODB_32 = (3, 2)
MONGODB_3 = (3, 0)
MONGODB_26 = (2, 6)
def get_mongodb_version(): def get_mongodb_version():

View File

@ -1,5 +1,5 @@
nose nose
pymongo>=3.5 pymongo>=3.4
six==1.10.0 six==1.10.0
flake8 flake8
flake8-import-order flake8-import-order

View File

@ -80,7 +80,7 @@ setup(
long_description=LONG_DESCRIPTION, long_description=LONG_DESCRIPTION,
platforms=['any'], platforms=['any'],
classifiers=CLASSIFIERS, classifiers=CLASSIFIERS,
install_requires=['pymongo>=3.5', 'six'], install_requires=['pymongo>=3.4', 'six'],
test_suite='nose.collector', test_suite='nose.collector',
**extra_opts **extra_opts
) )

View File

@ -6,7 +6,6 @@ from mongoengine.pymongo_support import list_collection_names
from mongoengine.queryset import NULLIFY, PULL from mongoengine.queryset import NULLIFY, PULL
from mongoengine.connection import get_db from mongoengine.connection import get_db
from tests.utils import requires_mongodb_gte_26
__all__ = ("ClassMethodsTest", ) __all__ = ("ClassMethodsTest", )
@ -187,7 +186,6 @@ class ClassMethodsTest(unittest.TestCase):
self.assertEqual(BlogPostWithTags.compare_indexes(), {'missing': [], 'extra': []}) self.assertEqual(BlogPostWithTags.compare_indexes(), {'missing': [], 'extra': []})
self.assertEqual(BlogPostWithCustomField.compare_indexes(), {'missing': [], 'extra': []}) self.assertEqual(BlogPostWithCustomField.compare_indexes(), {'missing': [], 'extra': []})
@requires_mongodb_gte_26
def test_compare_indexes_for_text_indexes(self): def test_compare_indexes_for_text_indexes(self):
""" Ensure that compare_indexes behaves correctly for text indexes """ """ Ensure that compare_indexes behaves correctly for text indexes """

View File

@ -9,8 +9,7 @@ from six import iteritems
from mongoengine import * from mongoengine import *
from mongoengine.connection import get_db from mongoengine.connection import get_db
from mongoengine.mongodb_support import get_mongodb_version, MONGODB_32, MONGODB_3 from mongoengine.mongodb_support import get_mongodb_version
from tests.utils import requires_mongodb_gte_26, requires_mongodb_lte_32, requires_mongodb_gte_34
__all__ = ("IndexesTest", ) __all__ = ("IndexesTest", )
@ -478,8 +477,6 @@ class IndexesTest(unittest.TestCase):
def test_covered_index(self): def test_covered_index(self):
"""Ensure that covered indexes can be used """Ensure that covered indexes can be used
""" """
IS_MONGODB_3 = get_mongodb_version() >= MONGODB_3
class Test(Document): class Test(Document):
a = IntField() a = IntField()
b = IntField() b = IntField()
@ -497,33 +494,38 @@ class IndexesTest(unittest.TestCase):
# Need to be explicit about covered indexes as mongoDB doesn't know if # Need to be explicit about covered indexes as mongoDB doesn't know if
# the documents returned might have more keys in that here. # the documents returned might have more keys in that here.
query_plan = Test.objects(id=obj.id).exclude('a').explain() query_plan = Test.objects(id=obj.id).exclude('a').explain()
if not IS_MONGODB_3: self.assertEqual(
self.assertFalse(query_plan['indexOnly']) query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'),
else: 'IDHACK'
self.assertEqual(query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'), 'IDHACK') )
query_plan = Test.objects(id=obj.id).only('id').explain() query_plan = Test.objects(id=obj.id).only('id').explain()
if not IS_MONGODB_3: self.assertEqual(
self.assertTrue(query_plan['indexOnly']) query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'),
else: 'IDHACK'
self.assertEqual(query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'), 'IDHACK') )
query_plan = Test.objects(a=1).only('a').exclude('id').explain() query_plan = Test.objects(a=1).only('a').exclude('id').explain()
if not IS_MONGODB_3: self.assertEqual(
self.assertTrue(query_plan['indexOnly']) query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'),
else: 'IXSCAN'
self.assertEqual(query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'), 'IXSCAN') )
self.assertEqual(query_plan.get('queryPlanner').get('winningPlan').get('stage'), 'PROJECTION') self.assertEqual(
query_plan.get('queryPlanner').get('winningPlan').get('stage'),
'PROJECTION'
)
query_plan = Test.objects(a=1).explain() query_plan = Test.objects(a=1).explain()
if not IS_MONGODB_3: self.assertEqual(
self.assertFalse(query_plan['indexOnly']) query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'),
else: 'IXSCAN'
self.assertEqual(query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'), 'IXSCAN') )
self.assertEqual(query_plan.get('queryPlanner').get('winningPlan').get('stage'), 'FETCH') self.assertEqual(
query_plan.get('queryPlanner').get('winningPlan').get('stage'),
'FETCH'
)
def test_index_on_id(self): def test_index_on_id(self):
class BlogPost(Document): class BlogPost(Document):
meta = { meta = {
'indexes': [ 'indexes': [
@ -565,13 +567,10 @@ class IndexesTest(unittest.TestCase):
self.assertEqual(BlogPost.objects.count(), 10) self.assertEqual(BlogPost.objects.count(), 10)
self.assertEqual(BlogPost.objects.hint().count(), 10) self.assertEqual(BlogPost.objects.hint().count(), 10)
if MONGO_VER >= MONGODB_32: # MongoDB v3.2+ throws an error if an index exists (i.e `tags` in our
# Mongo32 throws an error if an index exists (i.e `tags` in our case) # case) and you use hint on an index name that does not exist.
# and you use hint on an index name that does not exist
with self.assertRaises(OperationFailure): with self.assertRaises(OperationFailure):
BlogPost.objects.hint([('ZZ', 1)]).count() BlogPost.objects.hint([('ZZ', 1)]).count()
else:
self.assertEqual(BlogPost.objects.hint([('ZZ', 1)]).count(), 10)
self.assertEqual(BlogPost.objects.hint(TAGS_INDEX_NAME).count(), 10) self.assertEqual(BlogPost.objects.hint(TAGS_INDEX_NAME).count(), 10)
@ -598,8 +597,7 @@ class IndexesTest(unittest.TestCase):
# Ensure backwards compatibility for errors # Ensure backwards compatibility for errors
self.assertRaises(OperationError, post2.save) self.assertRaises(OperationError, post2.save)
@requires_mongodb_gte_34 def test_primary_key_unique_not_working(self):
def test_primary_key_unique_not_working_under_mongo_34(self):
"""Relates to #1445""" """Relates to #1445"""
class Blog(Document): class Blog(Document):
id = StringField(primary_key=True, unique=True) id = StringField(primary_key=True, unique=True)
@ -608,21 +606,17 @@ class IndexesTest(unittest.TestCase):
with self.assertRaises(OperationFailure) as ctx_err: with self.assertRaises(OperationFailure) as ctx_err:
Blog(id='garbage').save() Blog(id='garbage').save()
try:
self.assertIn("The field 'unique' is not valid for an _id index specification", str(ctx_err.exception))
except AssertionError:
# error is slightly different on python 3.6
self.assertIn("The field 'background' is not valid for an _id index specification", str(ctx_err.exception))
@requires_mongodb_lte_32 # One of the errors below should happen. Which one depends on the
def test_primary_key_unique_working_under_mongo_32(self): # PyMongo version and dict order.
"""Relates to #1445""" err_msg = str(ctx_err.exception)
class Blog(Document): self.assertTrue(
id = StringField(primary_key=True, unique=True) any([
"The field 'unique' is not valid for an _id index specification" in err_msg,
Blog.drop_collection() "The field 'background' is not valid for an _id index specification" in err_msg,
"The field 'sparse' is not valid for an _id index specification" in err_msg,
Blog(id='garbage').save() ])
)
def test_unique_with(self): def test_unique_with(self):
"""Ensure that unique_with constraints are applied to fields. """Ensure that unique_with constraints are applied to fields.
@ -984,7 +978,6 @@ class IndexesTest(unittest.TestCase):
info['provider_ids.foo_1_provider_ids.bar_1']['key']) info['provider_ids.foo_1_provider_ids.bar_1']['key'])
self.assertTrue(info['provider_ids.foo_1_provider_ids.bar_1']['sparse']) self.assertTrue(info['provider_ids.foo_1_provider_ids.bar_1']['sparse'])
@requires_mongodb_gte_26
def test_text_indexes(self): def test_text_indexes(self):
class Book(Document): class Book(Document):
title = DictField() title = DictField()

View File

@ -28,8 +28,6 @@ from mongoengine.queryset import NULLIFY, Q
from mongoengine.context_managers import switch_db, query_counter from mongoengine.context_managers import switch_db, query_counter
from mongoengine import signals from mongoengine import signals
from tests.utils import requires_mongodb_gte_26
TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__), TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__),
'../fields/mongoengine.png') '../fields/mongoengine.png')
@ -850,7 +848,6 @@ class InstanceTest(MongoDBTestCase):
self.assertDbEqual([dict(other_doc.to_mongo()), dict(doc.to_mongo())]) self.assertDbEqual([dict(other_doc.to_mongo()), dict(doc.to_mongo())])
@requires_mongodb_gte_26
def test_modify_with_positional_push(self): def test_modify_with_positional_push(self):
class Content(EmbeddedDocument): class Content(EmbeddedDocument):
keywords = ListField(StringField()) keywords = ListField(StringField())
@ -3368,7 +3365,6 @@ class InstanceTest(MongoDBTestCase):
person.update(set__height=2.0) person.update(set__height=2.0)
@requires_mongodb_gte_26
def test_push_with_position(self): def test_push_with_position(self):
"""Ensure that push with position works properly for an instance.""" """Ensure that push with position works properly for an instance."""
class BlogPost(Document): class BlogPost(Document):

View File

@ -3,7 +3,7 @@ import unittest
from mongoengine import * from mongoengine import *
from tests.utils import MongoDBTestCase, requires_mongodb_gte_3 from tests.utils import MongoDBTestCase
__all__ = ("GeoQueriesTest",) __all__ = ("GeoQueriesTest",)
@ -70,9 +70,6 @@ class GeoQueriesTest(MongoDBTestCase):
self.assertEqual(events.count(), 1) self.assertEqual(events.count(), 1)
self.assertEqual(events[0], event2) self.assertEqual(events[0], event2)
# $minDistance was added in MongoDB v2.6, but continued being buggy
# until v3.0; skip for older versions
@requires_mongodb_gte_3
def test_near_and_min_distance(self): def test_near_and_min_distance(self):
"""Ensure the "min_distance" operator works alongside the "near" """Ensure the "min_distance" operator works alongside the "near"
operator. operator.
@ -243,9 +240,6 @@ class GeoQueriesTest(MongoDBTestCase):
events = self.Event.objects(location__geo_within_polygon=polygon2) events = self.Event.objects(location__geo_within_polygon=polygon2)
self.assertEqual(events.count(), 0) self.assertEqual(events.count(), 0)
# $minDistance was added in MongoDB v2.6, but continued being buggy
# until v3.0; skip for older versions
@requires_mongodb_gte_3
def test_2dsphere_near_and_min_max_distance(self): def test_2dsphere_near_and_min_max_distance(self):
"""Ensure "min_distace" and "max_distance" operators work well """Ensure "min_distace" and "max_distance" operators work well
together with the "near" operator in a 2dsphere index. together with the "near" operator in a 2dsphere index.
@ -328,8 +322,6 @@ class GeoQueriesTest(MongoDBTestCase):
"""Make sure PointField works properly in an embedded document.""" """Make sure PointField works properly in an embedded document."""
self._test_embedded(point_field_class=PointField) self._test_embedded(point_field_class=PointField)
# Needs MongoDB > 2.6.4 https://jira.mongodb.org/browse/SERVER-14039
@requires_mongodb_gte_3
def test_spherical_geospatial_operators(self): def test_spherical_geospatial_operators(self):
"""Ensure that spherical geospatial queries are working.""" """Ensure that spherical geospatial queries are working."""
class Point(Document): class Point(Document):

View File

@ -2,8 +2,6 @@ import unittest
from mongoengine import connect, Document, IntField, StringField, ListField from mongoengine import connect, Document, IntField, StringField, ListField
from tests.utils import requires_mongodb_gte_26
__all__ = ("FindAndModifyTest",) __all__ = ("FindAndModifyTest",)
@ -96,7 +94,6 @@ class FindAndModifyTest(unittest.TestCase):
self.assertEqual(old_doc.to_mongo(), {"_id": 1}) self.assertEqual(old_doc.to_mongo(), {"_id": 1})
self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": -1}]) self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": -1}])
@requires_mongodb_gte_26
def test_modify_with_push(self): def test_modify_with_push(self):
class BlogPost(Document): class BlogPost(Document):
tags = ListField(StringField()) tags = ListField(StringField())

View File

@ -17,10 +17,9 @@ from mongoengine import *
from mongoengine.connection import get_connection, get_db from mongoengine.connection import get_connection, get_db
from mongoengine.context_managers import query_counter, switch_db from mongoengine.context_managers import query_counter, switch_db
from mongoengine.errors import InvalidQueryError from mongoengine.errors import InvalidQueryError
from mongoengine.mongodb_support import get_mongodb_version, MONGODB_32, MONGODB_36 from mongoengine.mongodb_support import get_mongodb_version, MONGODB_36
from mongoengine.queryset import (DoesNotExist, MultipleObjectsReturned, from mongoengine.queryset import (DoesNotExist, MultipleObjectsReturned,
QuerySet, QuerySetManager, queryset_manager) QuerySet, QuerySetManager, queryset_manager)
from tests.utils import requires_mongodb_gte_26
class db_ops_tracker(query_counter): class db_ops_tracker(query_counter):
@ -32,7 +31,7 @@ class db_ops_tracker(query_counter):
def get_key_compat(mongo_ver): def get_key_compat(mongo_ver):
ORDER_BY_KEY = 'sort' if mongo_ver >= MONGODB_32 else '$orderby' ORDER_BY_KEY = 'sort'
CMD_QUERY_KEY = 'command' if mongo_ver >= MONGODB_36 else 'query' CMD_QUERY_KEY = 'command' if mongo_ver >= MONGODB_36 else 'query'
return ORDER_BY_KEY, CMD_QUERY_KEY return ORDER_BY_KEY, CMD_QUERY_KEY
@ -598,7 +597,6 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(post.comments[0].by, 'joe') self.assertEqual(post.comments[0].by, 'joe')
self.assertEqual(post.comments[0].votes.score, 4) self.assertEqual(post.comments[0].votes.score, 4)
@requires_mongodb_gte_26
def test_update_min_max(self): def test_update_min_max(self):
class Scores(Document): class Scores(Document):
high_score = IntField() high_score = IntField()
@ -616,7 +614,6 @@ class QuerySetTest(unittest.TestCase):
Scores.objects(id=scores.id).update(max__high_score=500) Scores.objects(id=scores.id).update(max__high_score=500)
self.assertEqual(Scores.objects.get(id=scores.id).high_score, 1000) self.assertEqual(Scores.objects.get(id=scores.id).high_score, 1000)
@requires_mongodb_gte_26
def test_update_multiple(self): def test_update_multiple(self):
class Product(Document): class Product(Document):
item = StringField() item = StringField()
@ -868,11 +865,7 @@ class QuerySetTest(unittest.TestCase):
with query_counter() as q: with query_counter() as q:
self.assertEqual(q, 0) self.assertEqual(q, 0)
Blog.objects.insert(blogs, load_bulk=False) Blog.objects.insert(blogs, load_bulk=False)
if MONGO_VER >= MONGODB_32:
self.assertEqual(q, 1) # 1 entry containing the list of inserts self.assertEqual(q, 1) # 1 entry containing the list of inserts
else:
self.assertEqual(q, len(blogs)) # 1 entry per doc inserted
self.assertEqual(Blog.objects.count(), len(blogs)) self.assertEqual(Blog.objects.count(), len(blogs))
@ -885,11 +878,7 @@ class QuerySetTest(unittest.TestCase):
with query_counter() as q: with query_counter() as q:
self.assertEqual(q, 0) self.assertEqual(q, 0)
Blog.objects.insert(blogs) Blog.objects.insert(blogs)
if MONGO_VER >= MONGODB_32:
self.assertEqual(q, 2) # 1 for insert 1 for fetch self.assertEqual(q, 2) # 1 for insert 1 for fetch
else:
self.assertEqual(q, len(blogs)+1) # + 1 to fetch all docs
Blog.drop_collection() Blog.drop_collection()
@ -2030,7 +2019,6 @@ class QuerySetTest(unittest.TestCase):
pymongo_doc = BlogPost.objects.as_pymongo().first() pymongo_doc = BlogPost.objects.as_pymongo().first()
self.assertNotIn('title', pymongo_doc) self.assertNotIn('title', pymongo_doc)
@requires_mongodb_gte_26
def test_update_push_with_position(self): def test_update_push_with_position(self):
"""Ensure that the 'push' update with position works properly. """Ensure that the 'push' update with position works properly.
""" """
@ -2555,8 +2543,8 @@ class QuerySetTest(unittest.TestCase):
"""Make sure adding a comment to the query gets added to the query""" """Make sure adding a comment to the query gets added to the query"""
MONGO_VER = self.mongodb_version MONGO_VER = self.mongodb_version
_, CMD_QUERY_KEY = get_key_compat(MONGO_VER) _, CMD_QUERY_KEY = get_key_compat(MONGO_VER)
QUERY_KEY = 'filter' if MONGO_VER >= MONGODB_32 else '$query' QUERY_KEY = 'filter'
COMMENT_KEY = 'comment' if MONGO_VER >= MONGODB_32 else '$comment' COMMENT_KEY = 'comment'
class User(Document): class User(Document):
age = IntField() age = IntField()
@ -3370,7 +3358,6 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(Foo.objects.distinct("bar"), [bar]) self.assertEqual(Foo.objects.distinct("bar"), [bar])
@requires_mongodb_gte_26
def test_text_indexes(self): def test_text_indexes(self):
class News(Document): class News(Document):
title = StringField() title = StringField()
@ -3454,7 +3441,6 @@ class QuerySetTest(unittest.TestCase):
'brasil').order_by('$text_score').first() 'brasil').order_by('$text_score').first()
self.assertEqual(item.get_text_score(), max_text_score) self.assertEqual(item.get_text_score(), max_text_score)
@requires_mongodb_gte_26
def test_distinct_handles_references_to_alias(self): def test_distinct_handles_references_to_alias(self):
register_connection('testdb', 'mongoenginetest2') register_connection('testdb', 'mongoenginetest2')
@ -4586,7 +4572,6 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(bars._cursor._Cursor__read_preference, self.assertEqual(bars._cursor._Cursor__read_preference,
ReadPreference.SECONDARY_PREFERRED) ReadPreference.SECONDARY_PREFERRED)
@requires_mongodb_gte_26
def test_read_preference_aggregation_framework(self): def test_read_preference_aggregation_framework(self):
class Bar(Document): class Bar(Document):
txt = StringField() txt = StringField()
@ -5354,7 +5339,6 @@ class QuerySetTest(unittest.TestCase):
self.assertTrue(Person.objects._has_data(), self.assertTrue(Person.objects._has_data(),
'Cursor has data and returned False') 'Cursor has data and returned False')
@requires_mongodb_gte_26
def test_queryset_aggregation_framework(self): def test_queryset_aggregation_framework(self):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
@ -5396,7 +5380,6 @@ class QuerySetTest(unittest.TestCase):
{'_id': None, 'avg': 29, 'total': 2} {'_id': None, 'avg': 29, 'total': 2}
]) ])
@requires_mongodb_gte_26
def test_queryset_aggregation_with_skip(self): def test_queryset_aggregation_with_skip(self):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
@ -5418,7 +5401,6 @@ class QuerySetTest(unittest.TestCase):
{'_id': p3.pk, 'name': "SANDRA MARA"} {'_id': p3.pk, 'name': "SANDRA MARA"}
]) ])
@requires_mongodb_gte_26
def test_queryset_aggregation_with_limit(self): def test_queryset_aggregation_with_limit(self):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
@ -5439,7 +5421,6 @@ class QuerySetTest(unittest.TestCase):
{'_id': p1.pk, 'name': "ISABELLA LUANNA"} {'_id': p1.pk, 'name': "ISABELLA LUANNA"}
]) ])
@requires_mongodb_gte_26
def test_queryset_aggregation_with_sort(self): def test_queryset_aggregation_with_sort(self):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
@ -5462,7 +5443,6 @@ class QuerySetTest(unittest.TestCase):
{'_id': p2.pk, 'name': "WILSON JUNIOR"} {'_id': p2.pk, 'name': "WILSON JUNIOR"}
]) ])
@requires_mongodb_gte_26
def test_queryset_aggregation_with_skip_with_limit(self): def test_queryset_aggregation_with_skip_with_limit(self):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
@ -5492,7 +5472,6 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(data, list(data2)) self.assertEqual(data, list(data2))
@requires_mongodb_gte_26
def test_queryset_aggregation_with_sort_with_limit(self): def test_queryset_aggregation_with_sort_with_limit(self):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
@ -5534,7 +5513,6 @@ class QuerySetTest(unittest.TestCase):
{'_id': p3.pk, 'name': "SANDRA MARA"}, {'_id': p3.pk, 'name': "SANDRA MARA"},
]) ])
@requires_mongodb_gte_26
def test_queryset_aggregation_with_sort_with_skip(self): def test_queryset_aggregation_with_sort_with_skip(self):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
@ -5555,7 +5533,6 @@ class QuerySetTest(unittest.TestCase):
{'_id': p2.pk, 'name': "WILSON JUNIOR"} {'_id': p2.pk, 'name': "WILSON JUNIOR"}
]) ])
@requires_mongodb_gte_26
def test_queryset_aggregation_with_sort_with_skip_with_limit(self): def test_queryset_aggregation_with_sort_with_skip_with_limit(self):
class Person(Document): class Person(Document):
name = StringField() name = StringField()

View File

@ -5,7 +5,7 @@ from nose.plugins.skip import SkipTest
from mongoengine import connect from mongoengine import connect
from mongoengine.connection import get_db, disconnect_all from mongoengine.connection import get_db, disconnect_all
from mongoengine.mongodb_support import get_mongodb_version, MONGODB_26, MONGODB_3, MONGODB_32, MONGODB_34 from mongoengine.mongodb_support import get_mongodb_version
MONGO_TEST_DB = 'mongoenginetest' # standard name for the test database MONGO_TEST_DB = 'mongoenginetest' # standard name for the test database
@ -35,8 +35,20 @@ def get_as_pymongo(doc):
def _decorated_with_ver_requirement(func, mongo_version_req, oper): def _decorated_with_ver_requirement(func, mongo_version_req, oper):
"""Return a given function decorated with the version requirement """Return a MongoDB version requirement decorator.
for a particular MongoDB version tuple.
The resulting decorator will raise a SkipTest exception if the current
MongoDB version doesn't match the provided version/operator.
For example, if you define a decorator like so:
def requires_mongodb_gte_36(func):
return _decorated_with_ver_requirement(
func, (3.6), oper=operator.ge
)
Then tests decorated with @requires_mongodb_gte_36 will be skipped if
ran against MongoDB < v3.6.
:param mongo_version_req: The mongodb version requirement (tuple(int, int)) :param mongo_version_req: The mongodb version requirement (tuple(int, int))
:param oper: The operator to apply (e.g: operator.ge) :param oper: The operator to apply (e.g: operator.ge)
@ -51,31 +63,3 @@ def _decorated_with_ver_requirement(func, mongo_version_req, oper):
_inner.__name__ = func.__name__ _inner.__name__ = func.__name__
_inner.__doc__ = func.__doc__ _inner.__doc__ = func.__doc__
return _inner return _inner
def requires_mongodb_gte_34(func):
"""Raise a SkipTest exception if we're working with MongoDB version
lower than v3.4
"""
return _decorated_with_ver_requirement(func, MONGODB_34, oper=operator.ge)
def requires_mongodb_lte_32(func):
"""Raise a SkipTest exception if we're working with MongoDB version
greater than v3.2.
"""
return _decorated_with_ver_requirement(func, MONGODB_32, oper=operator.le)
def requires_mongodb_gte_26(func):
"""Raise a SkipTest exception if we're working with MongoDB version
lower than v2.6.
"""
return _decorated_with_ver_requirement(func, MONGODB_26, oper=operator.ge)
def requires_mongodb_gte_3(func):
"""Raise a SkipTest exception if we're working with MongoDB version
lower than v3.0.
"""
return _decorated_with_ver_requirement(func, MONGODB_3, oper=operator.ge)

View File

@ -6,7 +6,7 @@ commands =
python setup.py nosetests {posargs} python setup.py nosetests {posargs}
deps = deps =
nose nose
mg35: PyMongo==3.5 mg34x: PyMongo>=3.4,<3.5
mg3x: PyMongo>=3.0,<3.7 mg3x: PyMongo>=3.0,<3.7
setenv = setenv =
PYTHON_EGG_CACHE = {envdir}/python-eggs PYTHON_EGG_CACHE = {envdir}/python-eggs