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:
		
							
								
								
									
										41
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -2,11 +2,18 @@ | ||||
| # 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 | ||||
| # combinations: | ||||
| # * MongoDB v2.6 is currently the "main" version tested against Python v2.7, | ||||
| #   v3.5, v3.6, PyPy, and PyMongo v3.x. | ||||
| # * MongoDB v3.0 & v3.2 are tested against Python v2.7, v3.5 & v3.6 | ||||
| #   and Pymongo v3.5 & v3.x | ||||
| # * MongoDB v3.4 is tested against v3.6 and Pymongo v3.x | ||||
| # * MongoDB v3.4 & the latest PyMongo v3.x is currently the "main" setup, | ||||
| #   tested against Python v2.7, v3.5, v3.6, and PyPy. | ||||
| # * Besides that, we test the lowest actively supported Python/MongoDB/PyMongo | ||||
| #   combination: MongoDB v3.4, PyMongo v3.4, Python v2.7. | ||||
| # * 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. | ||||
|  | ||||
| language: python | ||||
| @@ -18,7 +25,7 @@ python: | ||||
| - pypy | ||||
|  | ||||
| env: | ||||
| - MONGODB=2.6 PYMONGO=3.x | ||||
| - MONGODB=3.4 PYMONGO=3.x | ||||
|  | ||||
| matrix: | ||||
|   # Finish the build as soon as one job fails | ||||
| @@ -26,15 +33,7 @@ matrix: | ||||
|  | ||||
|   include: | ||||
|   - python: 2.7 | ||||
|     env: MONGODB=3.0 PYMONGO=3.5 | ||||
|   - 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 | ||||
|     env: MONGODB=3.4 PYMONGO=3.4.x | ||||
|   - python: 3.6 | ||||
|     env: MONGODB=3.6 PYMONGO=3.x | ||||
|  | ||||
| @@ -86,15 +85,15 @@ deploy: | ||||
|   password: | ||||
|     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" | ||||
|  | ||||
|   # only deploy on tagged commits (aka GitHub releases) and only for the | ||||
|   # parent repo's builds running Python 2.7 along with PyMongo v3.x (we run | ||||
|   # Travis against many different Python and PyMongo versions and we don't | ||||
|   # want the deploy to occur multiple times). | ||||
|   # Only deploy on tagged commits (aka GitHub releases) and only for the parent | ||||
|   # repo's builds running Python v2.7 along with PyMongo v3.x and MongoDB v3.4. | ||||
|   # We run Travis against many different Python, PyMongo, and MongoDB versions | ||||
|   # and we don't want the deploy to occur multiple times). | ||||
|   on: | ||||
|     tags: true | ||||
|     repo: MongoEngine/mongoengine | ||||
|     condition: "$PYMONGO = 3.x" | ||||
|     condition: ($PYMONGO = 3.x) AND ($MONGODB = 3.4) | ||||
|     python: 2.7 | ||||
|   | ||||
| @@ -26,10 +26,10 @@ an `API reference <https://mongoengine-odm.readthedocs.io/apireference.html>`_. | ||||
|  | ||||
| Supported MongoDB Versions | ||||
| ========================== | ||||
| MongoEngine is currently tested against MongoDB v2.6, v3.0, v3.2, v3.4 and v3.6. Future | ||||
| versions should be supported as well, but aren't actively tested at the moment. | ||||
| Make sure to open an issue or submit a pull request if you experience any | ||||
| problems with MongoDB v3.6+. | ||||
| MongoEngine is currently tested against MongoDB v3.4 and v3.6. Future versions | ||||
| should be supported as well, but aren't actively tested at the moment. Make | ||||
| sure to open an issue or submit a pull request if you experience any problems | ||||
| with MongoDB version > 3.6. | ||||
|  | ||||
| Installation | ||||
| ============ | ||||
|   | ||||
| @@ -117,10 +117,22 @@ def _get_connection_settings( | ||||
|                     ReadPreference.PRIMARY, | ||||
|                     ReadPreference.PRIMARY_PREFERRED, | ||||
|                     ReadPreference.SECONDARY, | ||||
|                     ReadPreference.SECONDARY_PREFERRED) | ||||
|                 read_pf_mode = uri_options['readpreference'].lower() | ||||
|                     ReadPreference.SECONDARY_PREFERRED, | ||||
|                 ) | ||||
|  | ||||
|                 # 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: | ||||
|                     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 | ||||
|                         break | ||||
|         else: | ||||
|   | ||||
| @@ -7,10 +7,6 @@ from mongoengine.connection import get_connection | ||||
| # Constant that can be used to compare the version retrieved with | ||||
| # get_mongodb_version() | ||||
| MONGODB_36 = (3, 6) | ||||
| MONGODB_34 = (3, 4) | ||||
| MONGODB_32 = (3, 2) | ||||
| MONGODB_3 = (3, 0) | ||||
| MONGODB_26 = (2, 6) | ||||
|  | ||||
|  | ||||
| def get_mongodb_version(): | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| nose | ||||
| pymongo>=3.5 | ||||
| pymongo>=3.4 | ||||
| six==1.10.0 | ||||
| flake8 | ||||
| flake8-import-order | ||||
|   | ||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							| @@ -80,7 +80,7 @@ setup( | ||||
|     long_description=LONG_DESCRIPTION, | ||||
|     platforms=['any'], | ||||
|     classifiers=CLASSIFIERS, | ||||
|     install_requires=['pymongo>=3.5', 'six'], | ||||
|     install_requires=['pymongo>=3.4', 'six'], | ||||
|     test_suite='nose.collector', | ||||
|     **extra_opts | ||||
| ) | ||||
|   | ||||
| @@ -6,7 +6,6 @@ from mongoengine.pymongo_support import list_collection_names | ||||
|  | ||||
| from mongoengine.queryset import NULLIFY, PULL | ||||
| from mongoengine.connection import get_db | ||||
| from tests.utils import requires_mongodb_gte_26 | ||||
|  | ||||
| __all__ = ("ClassMethodsTest", ) | ||||
|  | ||||
| @@ -187,7 +186,6 @@ class ClassMethodsTest(unittest.TestCase): | ||||
|         self.assertEqual(BlogPostWithTags.compare_indexes(), {'missing': [], 'extra': []}) | ||||
|         self.assertEqual(BlogPostWithCustomField.compare_indexes(), {'missing': [], 'extra': []}) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_compare_indexes_for_text_indexes(self): | ||||
|         """ Ensure that compare_indexes behaves correctly for text indexes """ | ||||
|  | ||||
|   | ||||
| @@ -9,8 +9,7 @@ from six import iteritems | ||||
|  | ||||
| from mongoengine import * | ||||
| from mongoengine.connection import get_db | ||||
| from mongoengine.mongodb_support import get_mongodb_version, MONGODB_32, MONGODB_3 | ||||
| from tests.utils import requires_mongodb_gte_26, requires_mongodb_lte_32, requires_mongodb_gte_34 | ||||
| from mongoengine.mongodb_support import get_mongodb_version | ||||
|  | ||||
| __all__ = ("IndexesTest", ) | ||||
|  | ||||
| @@ -478,8 +477,6 @@ class IndexesTest(unittest.TestCase): | ||||
|     def test_covered_index(self): | ||||
|         """Ensure that covered indexes can be used | ||||
|         """ | ||||
|         IS_MONGODB_3 = get_mongodb_version() >= MONGODB_3 | ||||
|  | ||||
|         class Test(Document): | ||||
|             a = IntField() | ||||
|             b = IntField() | ||||
| @@ -497,33 +494,38 @@ class IndexesTest(unittest.TestCase): | ||||
|         # Need to be explicit about covered indexes as mongoDB doesn't know if | ||||
|         # the documents returned might have more keys in that here. | ||||
|         query_plan = Test.objects(id=obj.id).exclude('a').explain() | ||||
|         if not IS_MONGODB_3: | ||||
|             self.assertFalse(query_plan['indexOnly']) | ||||
|         else: | ||||
|             self.assertEqual(query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'), 'IDHACK') | ||||
|         self.assertEqual( | ||||
|             query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'), | ||||
|             'IDHACK' | ||||
|         ) | ||||
|  | ||||
|         query_plan = Test.objects(id=obj.id).only('id').explain() | ||||
|         if not IS_MONGODB_3: | ||||
|             self.assertTrue(query_plan['indexOnly']) | ||||
|         else: | ||||
|             self.assertEqual(query_plan.get('queryPlanner').get('winningPlan').get('inputStage').get('stage'), '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() | ||||
|         if not IS_MONGODB_3: | ||||
|             self.assertTrue(query_plan['indexOnly']) | ||||
|         else: | ||||
|             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('inputStage').get('stage'), | ||||
|             'IXSCAN' | ||||
|         ) | ||||
|         self.assertEqual( | ||||
|             query_plan.get('queryPlanner').get('winningPlan').get('stage'), | ||||
|             'PROJECTION' | ||||
|         ) | ||||
|  | ||||
|         query_plan = Test.objects(a=1).explain() | ||||
|         if not IS_MONGODB_3: | ||||
|             self.assertFalse(query_plan['indexOnly']) | ||||
|         else: | ||||
|             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('inputStage').get('stage'), | ||||
|             'IXSCAN' | ||||
|         ) | ||||
|         self.assertEqual( | ||||
|             query_plan.get('queryPlanner').get('winningPlan').get('stage'), | ||||
|             'FETCH' | ||||
|         ) | ||||
|  | ||||
|     def test_index_on_id(self): | ||||
|  | ||||
|         class BlogPost(Document): | ||||
|             meta = { | ||||
|                 'indexes': [ | ||||
| @@ -565,13 +567,10 @@ class IndexesTest(unittest.TestCase): | ||||
|         self.assertEqual(BlogPost.objects.count(), 10) | ||||
|         self.assertEqual(BlogPost.objects.hint().count(), 10) | ||||
|  | ||||
|         if MONGO_VER >= MONGODB_32: | ||||
|             # Mongo32 throws an error if an index exists (i.e `tags` in our case) | ||||
|             # and you use hint on an index name that does not exist | ||||
|             with self.assertRaises(OperationFailure): | ||||
|                 BlogPost.objects.hint([('ZZ', 1)]).count() | ||||
|         else: | ||||
|             self.assertEqual(BlogPost.objects.hint([('ZZ', 1)]).count(), 10) | ||||
|         # MongoDB v3.2+ throws an error if an index exists (i.e `tags` in our | ||||
|         # case) and you use hint on an index name that does not exist. | ||||
|         with self.assertRaises(OperationFailure): | ||||
|             BlogPost.objects.hint([('ZZ', 1)]).count() | ||||
|  | ||||
|         self.assertEqual(BlogPost.objects.hint(TAGS_INDEX_NAME).count(), 10) | ||||
|  | ||||
| @@ -598,9 +597,8 @@ class IndexesTest(unittest.TestCase): | ||||
|         # Ensure backwards compatibility for errors | ||||
|         self.assertRaises(OperationError, post2.save) | ||||
|  | ||||
|     @requires_mongodb_gte_34 | ||||
|     def test_primary_key_unique_not_working_under_mongo_34(self): | ||||
|         """Relates to  #1445""" | ||||
|     def test_primary_key_unique_not_working(self): | ||||
|         """Relates to #1445""" | ||||
|         class Blog(Document): | ||||
|             id = StringField(primary_key=True, unique=True) | ||||
|  | ||||
| @@ -608,21 +606,17 @@ class IndexesTest(unittest.TestCase): | ||||
|  | ||||
|         with self.assertRaises(OperationFailure) as ctx_err: | ||||
|             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 | ||||
|     def test_primary_key_unique_working_under_mongo_32(self): | ||||
|         """Relates to  #1445""" | ||||
|         class Blog(Document): | ||||
|             id = StringField(primary_key=True, unique=True) | ||||
|  | ||||
|         Blog.drop_collection() | ||||
|  | ||||
|         Blog(id='garbage').save() | ||||
|         # One of the errors below should happen. Which one depends on the | ||||
|         # PyMongo version and dict order. | ||||
|         err_msg = str(ctx_err.exception) | ||||
|         self.assertTrue( | ||||
|             any([ | ||||
|                 "The field 'unique' is not valid for an _id index specification" in err_msg, | ||||
|                 "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, | ||||
|             ]) | ||||
|         ) | ||||
|  | ||||
|     def test_unique_with(self): | ||||
|         """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']) | ||||
|         self.assertTrue(info['provider_ids.foo_1_provider_ids.bar_1']['sparse']) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_text_indexes(self): | ||||
|         class Book(Document): | ||||
|             title = DictField() | ||||
|   | ||||
| @@ -28,8 +28,6 @@ from mongoengine.queryset import NULLIFY, Q | ||||
| from mongoengine.context_managers import switch_db, query_counter | ||||
| from mongoengine import signals | ||||
|  | ||||
| from tests.utils import requires_mongodb_gte_26 | ||||
|  | ||||
| TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__), | ||||
|                                '../fields/mongoengine.png') | ||||
|  | ||||
| @@ -850,7 +848,6 @@ class InstanceTest(MongoDBTestCase): | ||||
|  | ||||
|         self.assertDbEqual([dict(other_doc.to_mongo()), dict(doc.to_mongo())]) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_modify_with_positional_push(self): | ||||
|         class Content(EmbeddedDocument): | ||||
|             keywords = ListField(StringField()) | ||||
| @@ -3368,7 +3365,6 @@ class InstanceTest(MongoDBTestCase): | ||||
|  | ||||
|         person.update(set__height=2.0) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_push_with_position(self): | ||||
|         """Ensure that push with position works properly for an instance.""" | ||||
|         class BlogPost(Document): | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import unittest | ||||
|  | ||||
| from mongoengine import * | ||||
|  | ||||
| from tests.utils import MongoDBTestCase, requires_mongodb_gte_3 | ||||
| from tests.utils import MongoDBTestCase | ||||
|  | ||||
|  | ||||
| __all__ = ("GeoQueriesTest",) | ||||
| @@ -70,9 +70,6 @@ class GeoQueriesTest(MongoDBTestCase): | ||||
|         self.assertEqual(events.count(), 1) | ||||
|         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): | ||||
|         """Ensure the "min_distance" operator works alongside the "near" | ||||
|         operator. | ||||
| @@ -243,9 +240,6 @@ class GeoQueriesTest(MongoDBTestCase): | ||||
|         events = self.Event.objects(location__geo_within_polygon=polygon2) | ||||
|         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): | ||||
|         """Ensure "min_distace" and "max_distance" operators work well | ||||
|         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.""" | ||||
|         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): | ||||
|         """Ensure that spherical geospatial queries are working.""" | ||||
|         class Point(Document): | ||||
|   | ||||
| @@ -2,8 +2,6 @@ import unittest | ||||
|  | ||||
| from mongoengine import connect, Document, IntField, StringField, ListField | ||||
|  | ||||
| from tests.utils import requires_mongodb_gte_26 | ||||
|  | ||||
| __all__ = ("FindAndModifyTest",) | ||||
|  | ||||
|  | ||||
| @@ -96,7 +94,6 @@ class FindAndModifyTest(unittest.TestCase): | ||||
|         self.assertEqual(old_doc.to_mongo(), {"_id": 1}) | ||||
|         self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": -1}]) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_modify_with_push(self): | ||||
|         class BlogPost(Document): | ||||
|             tags = ListField(StringField()) | ||||
|   | ||||
| @@ -17,10 +17,9 @@ from mongoengine import * | ||||
| from mongoengine.connection import get_connection, get_db | ||||
| from mongoengine.context_managers import query_counter, switch_db | ||||
| 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, | ||||
|                                   QuerySet, QuerySetManager, queryset_manager) | ||||
| from tests.utils import requires_mongodb_gte_26 | ||||
|  | ||||
|  | ||||
| class db_ops_tracker(query_counter): | ||||
| @@ -32,7 +31,7 @@ class db_ops_tracker(query_counter): | ||||
|  | ||||
|  | ||||
| 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' | ||||
|     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].votes.score, 4) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_update_min_max(self): | ||||
|         class Scores(Document): | ||||
|             high_score = IntField() | ||||
| @@ -616,7 +614,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|         Scores.objects(id=scores.id).update(max__high_score=500) | ||||
|         self.assertEqual(Scores.objects.get(id=scores.id).high_score, 1000) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_update_multiple(self): | ||||
|         class Product(Document): | ||||
|             item = StringField() | ||||
| @@ -868,11 +865,7 @@ class QuerySetTest(unittest.TestCase): | ||||
|         with query_counter() as q: | ||||
|             self.assertEqual(q, 0) | ||||
|             Blog.objects.insert(blogs, load_bulk=False) | ||||
|  | ||||
|             if MONGO_VER >= MONGODB_32: | ||||
|                 self.assertEqual(q, 1)      # 1 entry containing the list of inserts | ||||
|             else: | ||||
|                 self.assertEqual(q, len(blogs))     # 1 entry per doc inserted | ||||
|             self.assertEqual(q, 1)  # 1 entry containing the list of inserts | ||||
|  | ||||
|         self.assertEqual(Blog.objects.count(), len(blogs)) | ||||
|  | ||||
| @@ -885,11 +878,7 @@ class QuerySetTest(unittest.TestCase): | ||||
|         with query_counter() as q: | ||||
|             self.assertEqual(q, 0) | ||||
|             Blog.objects.insert(blogs) | ||||
|  | ||||
|             if MONGO_VER >= MONGODB_32: | ||||
|                 self.assertEqual(q, 2)              # 1 for insert 1 for fetch | ||||
|             else: | ||||
|                 self.assertEqual(q, len(blogs)+1)       # + 1 to fetch all docs | ||||
|             self.assertEqual(q, 2)  # 1 for insert 1 for fetch | ||||
|  | ||||
|         Blog.drop_collection() | ||||
|  | ||||
| @@ -2030,7 +2019,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|         pymongo_doc = BlogPost.objects.as_pymongo().first() | ||||
|         self.assertNotIn('title', pymongo_doc) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_update_push_with_position(self): | ||||
|         """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""" | ||||
|         MONGO_VER = self.mongodb_version | ||||
|         _, CMD_QUERY_KEY = get_key_compat(MONGO_VER) | ||||
|         QUERY_KEY = 'filter' if MONGO_VER >= MONGODB_32 else '$query' | ||||
|         COMMENT_KEY = 'comment' if MONGO_VER >= MONGODB_32 else '$comment' | ||||
|         QUERY_KEY = 'filter' | ||||
|         COMMENT_KEY = 'comment' | ||||
|  | ||||
|         class User(Document): | ||||
|             age = IntField() | ||||
| @@ -3370,7 +3358,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|  | ||||
|         self.assertEqual(Foo.objects.distinct("bar"), [bar]) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_text_indexes(self): | ||||
|         class News(Document): | ||||
|             title = StringField() | ||||
| @@ -3454,7 +3441,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|             'brasil').order_by('$text_score').first() | ||||
|         self.assertEqual(item.get_text_score(), max_text_score) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_distinct_handles_references_to_alias(self): | ||||
|         register_connection('testdb', 'mongoenginetest2') | ||||
|  | ||||
| @@ -4586,7 +4572,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|         self.assertEqual(bars._cursor._Cursor__read_preference, | ||||
|                          ReadPreference.SECONDARY_PREFERRED) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_read_preference_aggregation_framework(self): | ||||
|         class Bar(Document): | ||||
|             txt = StringField() | ||||
| @@ -5354,7 +5339,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|             self.assertTrue(Person.objects._has_data(), | ||||
|                             'Cursor has data and returned False') | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_queryset_aggregation_framework(self): | ||||
|         class Person(Document): | ||||
|             name = StringField() | ||||
| @@ -5396,7 +5380,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|             {'_id': None, 'avg': 29, 'total': 2} | ||||
|         ]) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_queryset_aggregation_with_skip(self): | ||||
|         class Person(Document): | ||||
|             name = StringField() | ||||
| @@ -5418,7 +5401,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|             {'_id': p3.pk, 'name': "SANDRA MARA"} | ||||
|         ]) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_queryset_aggregation_with_limit(self): | ||||
|         class Person(Document): | ||||
|             name = StringField() | ||||
| @@ -5439,7 +5421,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|             {'_id': p1.pk, 'name': "ISABELLA LUANNA"} | ||||
|         ]) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_queryset_aggregation_with_sort(self): | ||||
|         class Person(Document): | ||||
|             name = StringField() | ||||
| @@ -5462,7 +5443,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|             {'_id': p2.pk, 'name': "WILSON JUNIOR"} | ||||
|         ]) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_queryset_aggregation_with_skip_with_limit(self): | ||||
|         class Person(Document): | ||||
|             name = StringField() | ||||
| @@ -5492,7 +5472,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|  | ||||
|         self.assertEqual(data, list(data2)) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_queryset_aggregation_with_sort_with_limit(self): | ||||
|         class Person(Document): | ||||
|             name = StringField() | ||||
| @@ -5534,7 +5513,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|             {'_id': p3.pk, 'name': "SANDRA MARA"}, | ||||
|         ]) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_queryset_aggregation_with_sort_with_skip(self): | ||||
|         class Person(Document): | ||||
|             name = StringField() | ||||
| @@ -5555,7 +5533,6 @@ class QuerySetTest(unittest.TestCase): | ||||
|             {'_id': p2.pk, 'name': "WILSON JUNIOR"} | ||||
|         ]) | ||||
|  | ||||
|     @requires_mongodb_gte_26 | ||||
|     def test_queryset_aggregation_with_sort_with_skip_with_limit(self): | ||||
|         class Person(Document): | ||||
|             name = StringField() | ||||
|   | ||||
| @@ -5,7 +5,7 @@ from nose.plugins.skip import SkipTest | ||||
|  | ||||
| from mongoengine import connect | ||||
| 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 | ||||
| @@ -35,8 +35,20 @@ def get_as_pymongo(doc): | ||||
|  | ||||
|  | ||||
| def _decorated_with_ver_requirement(func, mongo_version_req, oper): | ||||
|     """Return a given function decorated with the version requirement | ||||
|     for a particular MongoDB version tuple. | ||||
|     """Return a MongoDB version requirement decorator. | ||||
|  | ||||
|     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 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.__doc__ = func.__doc__ | ||||
|     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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user