summaryrefslogtreecommitdiff
path: root/tests/appcachetests/runtests.py
blob: 8b62e7e0dc8e101c15ca9db84a9bfb847601f1f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
import copy
import sys
import unittest
import threading
from django.conf import settings
from django.utils.datastructures import SortedDict
from django.core.exceptions import ImproperlyConfigured
from django.core.apps import cache, MultipleInstancesReturned

# remove when tests are integrated into the django testsuite
settings.configure()


class AppCacheTestCase(unittest.TestCase):
    """
    TestCase that resets the AppCache after each test.
    """

    def setUp(self):
        self.old_installed_apps = settings.INSTALLED_APPS
        settings.INSTALLED_APPS = ()

    def tearDown(self):
        settings.INSTALLED_APPS = self.old_installed_apps

        # The appcache imports models modules. We need to delete the
        # imported module from sys.modules after the test has run. 
        # If the module is imported again, the ModelBase.__new__ can 
        # register the models with the appcache anew.
        # Some models modules import other models modules (for example 
        # django.contrib.auth relies on django.contrib.contenttypes). 
        # To detect which model modules have been imported, we go through
        # all loaded model classes and remove their respective module 
        # from sys.modules
        for app in cache.app_models.itervalues():
            for name in app.itervalues():
                module = name.__module__
                if module in sys.modules:
                    del sys.modules[module]

        # we cannot copy() the whole cache.__dict__ in the setUp function
        # because thread.RLock is un(deep)copyable
        cache.app_models = SortedDict()
        cache.app_instances = []
        cache.installed_apps = []

        cache.loaded = False
        cache.handled = {}
        cache.postponed = []
        cache.nesting_level = 0
        cache.write_lock = threading.RLock()
        cache._get_models_cache = {}

class AppCacheReadyTests(AppCacheTestCase):
    """
    Tests for the app_cache_ready function that indicates if the cache
    is fully populated.
    """

    def test_not_initialized(self):
        """Should return False if the AppCache hasn't been initialized"""
        self.assertFalse(cache.app_cache_ready())

    def test_load_app(self):
        """Should return False after executing the load_app function"""
        cache.load_app('nomodel_app')
        self.assertFalse(cache.app_cache_ready())
        cache.load_app('nomodel_app', can_postpone=True)
        self.assertFalse(cache.app_cache_ready())

class GetAppsTests(AppCacheTestCase):
    """Tests for the get_apps function"""

    def test_get_apps(self):
        """Test that the correct models modules are returned"""
        settings.INSTALLED_APPS = ('django.contrib.sites',
                                   'django.contrib.contenttypes',
                                   'django.contrib.auth',
                                   'django.contrib.flatpages',)
        apps = cache.get_apps()
        self.assertEqual(len(apps), 4)
        self.assertTrue(apps[0], 'django.contrib.auth.models')
        self.assertTrue(apps[1], 'django.contrib.flatpages.models')
        self.assertTrue(apps[2], 'django.contrib.sites.models')
        self.assertTrue(apps[3], 'django.contrib.contenttypes.models')
        self.assertTrue(cache.app_cache_ready())

    def test_empty_models(self):
        """Test that modules that don't contain models are not returned"""
        settings.INSTALLED_APPS = ('django.contrib.csrf',)
        self.assertEqual(cache.get_apps(), [])
        self.assertTrue(cache.app_cache_ready())

class GetAppTests(AppCacheTestCase):
    """Tests for the get_app function"""

    def test_get_app(self):
        """Test that the correct module is returned"""
        settings.INSTALLED_APPS = ('django.contrib.contenttypes',
                                   'django.contrib.auth',)
        module = cache.get_app('auth')
        self.assertTrue(module, 'django.contrib.auth.models')
        self.assertTrue(cache.app_cache_ready())

    def test_not_found_exception(self):
        """
        Test that an ImproperlyConfigured exception is raised if an app
        could not be found
        """
        self.assertRaises(ImproperlyConfigured, cache.get_app,
                          'django.contrib.auth')
        self.assertTrue(cache.app_cache_ready())

    def test_emptyOK(self):
        """
        Test that None is returned if emptyOK is True and the module
        has no models
        """
        settings.INSTALLED_APPS = ('django.contrib.csrf',)
        module = cache.get_app('csrf', emptyOK=True)
        self.failUnless(module is None)
        self.assertTrue(cache.app_cache_ready())

    def test_load_app_modules(self):
        """
        Test that only apps that are listed in the INSTALLED_APPS setting 
        are searched (unlike the get_apps function, which also searches
        apps that are loaded via load_app)
        """
        cache.load_app('django.contrib.sites')
        self.assertRaises(ImproperlyConfigured, cache.get_app, 'sites')
        self.assertTrue(cache.app_cache_ready())

class GetAppErrorsTests(AppCacheTestCase):
    """Tests for the get_app_errors function"""

    def test_get_app_errors(self):
        """Test that the function returns an empty dict"""
        self.assertEqual(cache.get_app_errors(), {})
        self.assertTrue(cache.app_cache_ready())

class GetModelsTests(AppCacheTestCase):
    """Tests for the get_models function"""

    def test_get_models(self):
        """Test that the correct model classes are returned"""
        settings.INSTALLED_APPS = ('django.contrib.sites',
                                   'django.contrib.flatpages',) 
        models = cache.get_models()
        from django.contrib.flatpages.models import Site, FlatPage
        self.assertEqual(len(models), 2)
        self.assertEqual(models[0], Site)
        self.assertEqual(models[1], FlatPage)
        self.assertTrue(cache.app_cache_ready())
    
    def test_app_mod(self):
        """
        Test that the correct model classes are returned if an
        app module is specified
        """
        settings.INSTALLED_APPS = ('django.contrib.sites',
                                   'django.contrib.flatpages',)
        # populate cache
        cache.get_app_errors()

        from django.contrib.flatpages import models
        from django.contrib.flatpages.models import FlatPage
        rv = cache.get_models(app_mod=models)
        self.assertEqual(len(rv), 1)
        self.assertEqual(rv[0], FlatPage)
        self.assertTrue(cache.app_cache_ready())

    def test_include_auto_created(self):
        """Test that auto created models are included if specified"""
        settings.INSTALLED_APPS = ('django.contrib.sites',
                                   'django.contrib.flatpages',)
        models = cache.get_models(include_auto_created=True)
        from django.contrib.flatpages.models import Site, FlatPage
        self.assertEqual(len(models), 3)
        self.assertEqual(models[0], Site)
        self.assertEqual(models[1].__name__, 'FlatPage_sites')
        self.assertEqual(models[2], FlatPage)
        self.assertTrue(cache.app_cache_ready())

    def test_include_deferred(self):
        """TODO!"""

class GetModelTests(AppCacheTestCase):
    """Tests for the get_model function"""

    def test_get_model(self):
        """Test that the correct model is returned"""
        settings.INSTALLED_APPS = ('django.contrib.sites',
                                   'django.contrib.flatpages',)
        rv = cache.get_model('flatpages', 'FlatPage')
        from django.contrib.flatpages.models import FlatPage
        self.assertEqual(rv, FlatPage)
        self.assertTrue(cache.app_cache_ready())

    def test_invalid(self):
        """Test that None is returned if an app/model does not exist"""
        self.assertEqual(cache.get_model('foo', 'bar'), None)
        self.assertTrue(cache.app_cache_ready())

    def test_without_seeding(self):
        """Test that None is returned if the cache is not seeded"""
        settings.INSTALLED_APPS = ('django.contrib.flatpages',)
        rv = cache.get_model('flatpages', 'FlatPage', seed_cache=False)
        self.assertEqual(rv, None)
        self.assertFalse(cache.app_cache_ready())

class LoadAppTests(AppCacheTestCase):
    """Tests for the load_app function"""

    def test_with_models(self):
        """
        Test that an app instance is created and the models
        module is returned
        """
        rv = cache.load_app('model_app')
        app = cache.app_instances[0]
        self.assertEqual(len(cache.app_instances), 1)
        self.assertEqual(app.name, 'model_app')
        self.assertEqual(app.models_module.__name__, 'model_app.models')
        self.assertEqual(rv.__name__, 'model_app.models')

    def test_without_models(self):
        """
        Test that an app instance is created when there are no models
        """
        rv = cache.load_app('nomodel_app')
        app = cache.app_instances[0]
        self.assertEqual(len(cache.app_instances), 1)
        self.assertEqual(app.name, 'nomodel_app')
        self.assertEqual(rv, None)

    def test_custom_app(self):
        """
        Test that a custom app instance is created if the function
        gets passed a classname
        """
        from nomodel_app import MyApp
        rv = cache.load_app('nomodel_app.MyApp')
        app = cache.app_instances[0]
        self.assertEqual(len(cache.app_instances), 1)
        self.assertEqual(app.name, 'nomodel_app')
        self.assertTrue(isinstance(app, MyApp))
        self.assertEqual(rv, None)

    def test_custom_models_path(self):
        """
        Test that custom models are imported correctly 
        """
        rv = cache.load_app('model_app.MyApp')
        app = cache.app_instances[0]
        self.assertEqual(app.models_module.__name__, 'model_app.othermodels')
        self.assertEqual(rv.__name__, 'model_app.othermodels')

    def test_twice(self):
        """
        Test that loading an app twice results in only one app instance
        """
        rv = cache.load_app('model_app')
        rv2 = cache.load_app('model_app')
        self.assertEqual(len(cache.app_instances), 1)
        self.assertEqual(rv.__name__, 'model_app.models')
        self.assertEqual(rv2.__name__, 'model_app.models')

    def test_importerror(self):
        """
        Test that an ImportError exception is raised if a package cannot
        be imported
        """
        self.assertRaises(ImportError, cache.load_app, 'garageland')

    def test_installed_apps(self):
        """
        Test that the installed_apps attribute is populated correctly
        """
        settings.INSTALLED_APPS = ('model_app', 'nomodel_app.MyApp',)
        # populate cache
        cache.get_app_errors()
        self.assertEqual(cache.installed_apps, ['model_app', 'nomodel_app',])

class RegisterModelsTests(AppCacheTestCase):
    """Tests for the register_models function"""

    def test_register_models(self):
        """
        Test that register_models attaches the models to an existing
        app instance
        """
        # We don't need to call the register_models method. Importing the 
        # models.py file will suffice. This is done in the load_app function
        # The ModelBase will call the register_models method
        cache.load_app('model_app')
        app = cache.app_instances[0]
        self.assertEqual(len(cache.app_instances), 1)
        self.assertEqual(app.models[0].__name__, 'Person')

    def test_app_not_installed(self):
        """
        Test that an exception is raised if models are tried to be registered
        to an app that isn't listed in INSTALLED_APPS.
        """
        try:
            from model_app.models import Person
        except ImproperlyConfigured:
            pass
        else:
            self.fail('ImproperlyConfigured not raised')

if __name__ == '__main__':
    unittest.main()