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
		
			
				
	
	
		
			369 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			369 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # -*- coding: utf-8 -*-
 | |
| import unittest
 | |
| 
 | |
| from mongoengine import *
 | |
| from mongoengine.pymongo_support import list_collection_names
 | |
| 
 | |
| from mongoengine.queryset import NULLIFY, PULL
 | |
| from mongoengine.connection import get_db
 | |
| 
 | |
| __all__ = ("ClassMethodsTest", )
 | |
| 
 | |
| 
 | |
| class ClassMethodsTest(unittest.TestCase):
 | |
| 
 | |
|     def setUp(self):
 | |
|         connect(db='mongoenginetest')
 | |
|         self.db = get_db()
 | |
| 
 | |
|         class Person(Document):
 | |
|             name = StringField()
 | |
|             age = IntField()
 | |
| 
 | |
|             non_field = True
 | |
| 
 | |
|             meta = {"allow_inheritance": True}
 | |
| 
 | |
|         self.Person = Person
 | |
| 
 | |
|     def tearDown(self):
 | |
|         for collection in list_collection_names(self.db):
 | |
|             self.db.drop_collection(collection)
 | |
| 
 | |
|     def test_definition(self):
 | |
|         """Ensure that document may be defined using fields.
 | |
|         """
 | |
|         self.assertEqual(['_cls', 'age', 'id', 'name'],
 | |
|                          sorted(self.Person._fields.keys()))
 | |
|         self.assertEqual(["IntField", "ObjectIdField", "StringField", "StringField"],
 | |
|                         sorted([x.__class__.__name__ for x in
 | |
|                                 self.Person._fields.values()]))
 | |
| 
 | |
|     def test_get_db(self):
 | |
|         """Ensure that get_db returns the expected db.
 | |
|         """
 | |
|         db = self.Person._get_db()
 | |
|         self.assertEqual(self.db, db)
 | |
| 
 | |
|     def test_get_collection_name(self):
 | |
|         """Ensure that get_collection_name returns the expected collection
 | |
|         name.
 | |
|         """
 | |
|         collection_name = 'person'
 | |
|         self.assertEqual(collection_name, self.Person._get_collection_name())
 | |
| 
 | |
|     def test_get_collection(self):
 | |
|         """Ensure that get_collection returns the expected collection.
 | |
|         """
 | |
|         collection_name = 'person'
 | |
|         collection = self.Person._get_collection()
 | |
|         self.assertEqual(self.db[collection_name], collection)
 | |
| 
 | |
|     def test_drop_collection(self):
 | |
|         """Ensure that the collection may be dropped from the database.
 | |
|         """
 | |
|         collection_name = 'person'
 | |
|         self.Person(name='Test').save()
 | |
|         self.assertIn(collection_name, list_collection_names(self.db))
 | |
| 
 | |
|         self.Person.drop_collection()
 | |
|         self.assertNotIn(collection_name, list_collection_names(self.db))
 | |
| 
 | |
|     def test_register_delete_rule(self):
 | |
|         """Ensure that register delete rule adds a delete rule to the document
 | |
|         meta.
 | |
|         """
 | |
|         class Job(Document):
 | |
|             employee = ReferenceField(self.Person)
 | |
| 
 | |
|         self.assertEqual(self.Person._meta.get('delete_rules'), None)
 | |
| 
 | |
|         self.Person.register_delete_rule(Job, 'employee', NULLIFY)
 | |
|         self.assertEqual(self.Person._meta['delete_rules'],
 | |
|                          {(Job, 'employee'): NULLIFY})
 | |
| 
 | |
|     def test_compare_indexes(self):
 | |
|         """ Ensure that the indexes are properly created and that
 | |
|         compare_indexes identifies the missing/extra indexes
 | |
|         """
 | |
| 
 | |
|         class BlogPost(Document):
 | |
|             author = StringField()
 | |
|             title = StringField()
 | |
|             description = StringField()
 | |
|             tags = StringField()
 | |
| 
 | |
|             meta = {
 | |
|                 'indexes': [('author', 'title')]
 | |
|             }
 | |
| 
 | |
|         BlogPost.drop_collection()
 | |
| 
 | |
|         BlogPost.ensure_indexes()
 | |
|         self.assertEqual(BlogPost.compare_indexes(), {'missing': [], 'extra': []})
 | |
| 
 | |
|         BlogPost.ensure_index(['author', 'description'])
 | |
|         self.assertEqual(BlogPost.compare_indexes(), {'missing': [], 'extra': [[('author', 1), ('description', 1)]]})
 | |
| 
 | |
|         BlogPost._get_collection().drop_index('author_1_description_1')
 | |
|         self.assertEqual(BlogPost.compare_indexes(), {'missing': [], 'extra': []})
 | |
| 
 | |
|         BlogPost._get_collection().drop_index('author_1_title_1')
 | |
|         self.assertEqual(BlogPost.compare_indexes(), {'missing': [[('author', 1), ('title', 1)]], 'extra': []})
 | |
| 
 | |
|     def test_compare_indexes_inheritance(self):
 | |
|         """ Ensure that the indexes are properly created and that
 | |
|         compare_indexes identifies the missing/extra indexes for subclassed
 | |
|         documents (_cls included)
 | |
|         """
 | |
| 
 | |
|         class BlogPost(Document):
 | |
|             author = StringField()
 | |
|             title = StringField()
 | |
|             description = StringField()
 | |
| 
 | |
|             meta = {
 | |
|                 'allow_inheritance': True
 | |
|             }
 | |
| 
 | |
|         class BlogPostWithTags(BlogPost):
 | |
|             tags = StringField()
 | |
|             tag_list = ListField(StringField())
 | |
| 
 | |
|             meta = {
 | |
|                 'indexes': [('author', 'tags')]
 | |
|             }
 | |
| 
 | |
|         BlogPost.drop_collection()
 | |
| 
 | |
|         BlogPost.ensure_indexes()
 | |
|         BlogPostWithTags.ensure_indexes()
 | |
|         self.assertEqual(BlogPost.compare_indexes(), {'missing': [], 'extra': []})
 | |
| 
 | |
|         BlogPostWithTags.ensure_index(['author', 'tag_list'])
 | |
|         self.assertEqual(BlogPost.compare_indexes(), {'missing': [], 'extra': [[('_cls', 1), ('author', 1), ('tag_list', 1)]]})
 | |
| 
 | |
|         BlogPostWithTags._get_collection().drop_index('_cls_1_author_1_tag_list_1')
 | |
|         self.assertEqual(BlogPost.compare_indexes(), {'missing': [], 'extra': []})
 | |
| 
 | |
|         BlogPostWithTags._get_collection().drop_index('_cls_1_author_1_tags_1')
 | |
|         self.assertEqual(BlogPost.compare_indexes(), {'missing': [[('_cls', 1), ('author', 1), ('tags', 1)]], 'extra': []})
 | |
| 
 | |
|     def test_compare_indexes_multiple_subclasses(self):
 | |
|         """ Ensure that compare_indexes behaves correctly if called from a
 | |
|         class, which base class has multiple subclasses
 | |
|         """
 | |
| 
 | |
|         class BlogPost(Document):
 | |
|             author = StringField()
 | |
|             title = StringField()
 | |
|             description = StringField()
 | |
| 
 | |
|             meta = {
 | |
|                 'allow_inheritance': True
 | |
|             }
 | |
| 
 | |
|         class BlogPostWithTags(BlogPost):
 | |
|             tags = StringField()
 | |
|             tag_list = ListField(StringField())
 | |
| 
 | |
|             meta = {
 | |
|                 'indexes': [('author', 'tags')]
 | |
|             }
 | |
| 
 | |
|         class BlogPostWithCustomField(BlogPost):
 | |
|             custom = DictField()
 | |
| 
 | |
|             meta = {
 | |
|                 'indexes': [('author', 'custom')]
 | |
|             }
 | |
| 
 | |
|         BlogPost.ensure_indexes()
 | |
|         BlogPostWithTags.ensure_indexes()
 | |
|         BlogPostWithCustomField.ensure_indexes()
 | |
| 
 | |
|         self.assertEqual(BlogPost.compare_indexes(), {'missing': [], 'extra': []})
 | |
|         self.assertEqual(BlogPostWithTags.compare_indexes(), {'missing': [], 'extra': []})
 | |
|         self.assertEqual(BlogPostWithCustomField.compare_indexes(), {'missing': [], 'extra': []})
 | |
| 
 | |
|     def test_compare_indexes_for_text_indexes(self):
 | |
|         """ Ensure that compare_indexes behaves correctly for text indexes """
 | |
| 
 | |
|         class Doc(Document):
 | |
|             a = StringField()
 | |
|             b = StringField()
 | |
|             meta = {'indexes': [
 | |
|                 {'fields': ['$a', "$b"],
 | |
|                  'default_language': 'english',
 | |
|                  'weights': {'a': 10, 'b': 2}
 | |
|                 }
 | |
|             ]}
 | |
| 
 | |
|         Doc.drop_collection()
 | |
|         Doc.ensure_indexes()
 | |
|         actual = Doc.compare_indexes()
 | |
|         expected = {'missing': [], 'extra': []}
 | |
|         self.assertEqual(actual, expected)
 | |
| 
 | |
|     def test_list_indexes_inheritance(self):
 | |
|         """ ensure that all of the indexes are listed regardless of the super-
 | |
|         or sub-class that we call it from
 | |
|         """
 | |
| 
 | |
|         class BlogPost(Document):
 | |
|             author = StringField()
 | |
|             title = StringField()
 | |
|             description = StringField()
 | |
| 
 | |
|             meta = {
 | |
|                 'allow_inheritance': True
 | |
|             }
 | |
| 
 | |
|         class BlogPostWithTags(BlogPost):
 | |
|             tags = StringField()
 | |
| 
 | |
|             meta = {
 | |
|                 'indexes': [('author', 'tags')]
 | |
|             }
 | |
| 
 | |
|         class BlogPostWithTagsAndExtraText(BlogPostWithTags):
 | |
|             extra_text = StringField()
 | |
| 
 | |
|             meta = {
 | |
|                 'indexes': [('author', 'tags', 'extra_text')]
 | |
|             }
 | |
| 
 | |
|         BlogPost.drop_collection()
 | |
| 
 | |
|         BlogPost.ensure_indexes()
 | |
|         BlogPostWithTags.ensure_indexes()
 | |
|         BlogPostWithTagsAndExtraText.ensure_indexes()
 | |
| 
 | |
|         self.assertEqual(BlogPost.list_indexes(),
 | |
|                          BlogPostWithTags.list_indexes())
 | |
|         self.assertEqual(BlogPost.list_indexes(),
 | |
|                          BlogPostWithTagsAndExtraText.list_indexes())
 | |
|         self.assertEqual(BlogPost.list_indexes(),
 | |
|                          [[('_cls', 1), ('author', 1), ('tags', 1)],
 | |
|                          [('_cls', 1), ('author', 1), ('tags', 1), ('extra_text', 1)],
 | |
|                          [(u'_id', 1)], [('_cls', 1)]])
 | |
| 
 | |
|     def test_register_delete_rule_inherited(self):
 | |
| 
 | |
|         class Vaccine(Document):
 | |
|             name = StringField(required=True)
 | |
| 
 | |
|             meta = {"indexes": ["name"]}
 | |
| 
 | |
|         class Animal(Document):
 | |
|             family = StringField(required=True)
 | |
|             vaccine_made = ListField(ReferenceField("Vaccine", reverse_delete_rule=PULL))
 | |
| 
 | |
|             meta = {"allow_inheritance": True, "indexes": ["family"]}
 | |
| 
 | |
|         class Cat(Animal):
 | |
|             name = StringField(required=True)
 | |
| 
 | |
|         self.assertEqual(Vaccine._meta['delete_rules'][(Animal, 'vaccine_made')], PULL)
 | |
|         self.assertEqual(Vaccine._meta['delete_rules'][(Cat, 'vaccine_made')], PULL)
 | |
| 
 | |
|     def test_collection_naming(self):
 | |
|         """Ensure that a collection with a specified name may be used.
 | |
|         """
 | |
| 
 | |
|         class DefaultNamingTest(Document):
 | |
|             pass
 | |
|         self.assertEqual('default_naming_test',
 | |
|                          DefaultNamingTest._get_collection_name())
 | |
| 
 | |
|         class CustomNamingTest(Document):
 | |
|             meta = {'collection': 'pimp_my_collection'}
 | |
| 
 | |
|         self.assertEqual('pimp_my_collection',
 | |
|                          CustomNamingTest._get_collection_name())
 | |
| 
 | |
|         class DynamicNamingTest(Document):
 | |
|             meta = {'collection': lambda c: "DYNAMO"}
 | |
|         self.assertEqual('DYNAMO', DynamicNamingTest._get_collection_name())
 | |
| 
 | |
|         # Use Abstract class to handle backwards compatibility
 | |
|         class BaseDocument(Document):
 | |
|             meta = {
 | |
|                 'abstract': True,
 | |
|                 'collection': lambda c: c.__name__.lower()
 | |
|             }
 | |
| 
 | |
|         class OldNamingConvention(BaseDocument):
 | |
|             pass
 | |
|         self.assertEqual('oldnamingconvention',
 | |
|                          OldNamingConvention._get_collection_name())
 | |
| 
 | |
|         class InheritedAbstractNamingTest(BaseDocument):
 | |
|             meta = {'collection': 'wibble'}
 | |
|         self.assertEqual('wibble',
 | |
|                          InheritedAbstractNamingTest._get_collection_name())
 | |
| 
 | |
|         # Mixin tests
 | |
|         class BaseMixin(object):
 | |
|             meta = {
 | |
|                 'collection': lambda c: c.__name__.lower()
 | |
|             }
 | |
| 
 | |
|         class OldMixinNamingConvention(Document, BaseMixin):
 | |
|             pass
 | |
|         self.assertEqual('oldmixinnamingconvention',
 | |
|                           OldMixinNamingConvention._get_collection_name())
 | |
| 
 | |
|         class BaseMixin(object):
 | |
|             meta = {
 | |
|                 'collection': lambda c: c.__name__.lower()
 | |
|             }
 | |
| 
 | |
|         class BaseDocument(Document, BaseMixin):
 | |
|             meta = {'allow_inheritance': True}
 | |
| 
 | |
|         class MyDocument(BaseDocument):
 | |
|             pass
 | |
| 
 | |
|         self.assertEqual('basedocument', MyDocument._get_collection_name())
 | |
| 
 | |
|     def test_custom_collection_name_operations(self):
 | |
|         """Ensure that a collection with a specified name is used as expected.
 | |
|         """
 | |
|         collection_name = 'personCollTest'
 | |
| 
 | |
|         class Person(Document):
 | |
|             name = StringField()
 | |
|             meta = {'collection': collection_name}
 | |
| 
 | |
|         Person(name="Test User").save()
 | |
|         self.assertIn(collection_name, list_collection_names(self.db))
 | |
| 
 | |
|         user_obj = self.db[collection_name].find_one()
 | |
|         self.assertEqual(user_obj['name'], "Test User")
 | |
| 
 | |
|         user_obj = Person.objects[0]
 | |
|         self.assertEqual(user_obj.name, "Test User")
 | |
| 
 | |
|         Person.drop_collection()
 | |
|         self.assertNotIn(collection_name, list_collection_names(self.db))
 | |
| 
 | |
|     def test_collection_name_and_primary(self):
 | |
|         """Ensure that a collection with a specified name may be used.
 | |
|         """
 | |
| 
 | |
|         class Person(Document):
 | |
|             name = StringField(primary_key=True)
 | |
|             meta = {'collection': 'app'}
 | |
| 
 | |
|         Person(name="Test User").save()
 | |
| 
 | |
|         user_obj = Person.objects.first()
 | |
|         self.assertEqual(user_obj.name, "Test User")
 | |
| 
 | |
|         Person.drop_collection()
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     unittest.main()
 |