PageRenderTime 114ms CodeModel.GetById 89ms app.highlight 19ms RepoModel.GetById 2ms app.codeStats 0ms

/tests/regressiontests/fixtures_regress/tests.py

https://code.google.com/p/mango-py/
Python | 620 lines | 582 code | 10 blank | 28 comment | 5 complexity | 74dd7a0d5e5cb13262412e4353992b50 MD5 | raw file
  1# -*- coding: utf-8 -*-
  2# Unittests for fixtures.
  3import os
  4import re
  5import sys
  6try:
  7    from cStringIO import StringIO
  8except ImportError:
  9    from StringIO import StringIO
 10
 11from django.core import management
 12from django.core.management.commands.dumpdata import sort_dependencies
 13from django.core.management.base import CommandError
 14from django.db.models import signals
 15from django.db import transaction
 16from django.test import TestCase, TransactionTestCase, skipIfDBFeature, \
 17    skipUnlessDBFeature
 18
 19from models import Animal, Stuff
 20from models import Absolute, Parent, Child
 21from models import Article, Widget
 22from models import Store, Person, Book
 23from models import NKChild, RefToNKChild
 24from models import Circle1, Circle2, Circle3
 25from models import ExternalDependency
 26from models import Thingy
 27
 28
 29pre_save_checks = []
 30def animal_pre_save_check(signal, sender, instance, **kwargs):
 31    "A signal that is used to check the type of data loaded from fixtures"
 32    pre_save_checks.append(
 33        (
 34            'Count = %s (%s)' % (instance.count, type(instance.count)),
 35            'Weight = %s (%s)' % (instance.weight, type(instance.weight)),
 36        )
 37    )
 38
 39
 40class TestFixtures(TestCase):
 41    def test_duplicate_pk(self):
 42        """
 43        This is a regression test for ticket #3790.
 44        """
 45        # Load a fixture that uses PK=1
 46        management.call_command(
 47            'loaddata',
 48            'sequence',
 49            verbosity=0,
 50            commit=False
 51        )
 52
 53        # Create a new animal. Without a sequence reset, this new object
 54        # will take a PK of 1 (on Postgres), and the save will fail.
 55
 56        animal = Animal(
 57            name='Platypus',
 58            latin_name='Ornithorhynchus anatinus',
 59            count=2,
 60            weight=2.2
 61        )
 62        animal.save()
 63        self.assertGreater(animal.id, 1)
 64
 65    @skipIfDBFeature('interprets_empty_strings_as_nulls')
 66    def test_pretty_print_xml(self):
 67        """
 68        Regression test for ticket #4558 -- pretty printing of XML fixtures
 69        doesn't affect parsing of None values.
 70        """
 71        # Load a pretty-printed XML fixture with Nulls.
 72        management.call_command(
 73            'loaddata',
 74            'pretty.xml',
 75            verbosity=0,
 76            commit=False
 77        )
 78        self.assertEqual(Stuff.objects.all()[0].name, None)
 79        self.assertEqual(Stuff.objects.all()[0].owner, None)
 80
 81    @skipUnlessDBFeature('interprets_empty_strings_as_nulls')
 82    def test_pretty_print_xml_empty_strings(self):
 83        """
 84        Regression test for ticket #4558 -- pretty printing of XML fixtures
 85        doesn't affect parsing of None values.
 86        """
 87        # Load a pretty-printed XML fixture with Nulls.
 88        management.call_command(
 89            'loaddata',
 90            'pretty.xml',
 91            verbosity=0,
 92            commit=False
 93        )
 94        self.assertEqual(Stuff.objects.all()[0].name, u'')
 95        self.assertEqual(Stuff.objects.all()[0].owner, None)
 96
 97    def test_absolute_path(self):
 98        """
 99        Regression test for ticket #6436 --
100        os.path.join will throw away the initial parts of a path if it
101        encounters an absolute path.
102        This means that if a fixture is specified as an absolute path,
103        we need to make sure we don't discover the absolute path in every
104        fixture directory.
105        """
106        load_absolute_path = os.path.join(
107            os.path.dirname(__file__),
108            'fixtures',
109            'absolute.json'
110        )
111        management.call_command(
112            'loaddata',
113            load_absolute_path,
114            verbosity=0,
115            commit=False
116        )
117        self.assertEqual(Absolute.load_count, 1)
118
119
120    def test_unknown_format(self):
121        """
122        Test for ticket #4371 -- Loading data of an unknown format should fail
123        Validate that error conditions are caught correctly
124        """
125        stderr = StringIO()
126        management.call_command(
127            'loaddata',
128            'bad_fixture1.unkn',
129            verbosity=0,
130            commit=False,
131            stderr=stderr,
132        )
133        self.assertEqual(
134            stderr.getvalue(),
135            "Problem installing fixture 'bad_fixture1': unkn is not a known serialization format.\n"
136        )
137
138    def test_invalid_data(self):
139        """
140        Test for ticket #4371 -- Loading a fixture file with invalid data
141        using explicit filename.
142        Validate that error conditions are caught correctly
143        """
144        stderr = StringIO()
145        management.call_command(
146            'loaddata',
147            'bad_fixture2.xml',
148            verbosity=0,
149            commit=False,
150            stderr=stderr,
151        )
152        self.assertEqual(
153            stderr.getvalue(),
154            "No fixture data found for 'bad_fixture2'. (File format may be invalid.)\n"
155        )
156
157    def test_invalid_data_no_ext(self):
158        """
159        Test for ticket #4371 -- Loading a fixture file with invalid data
160        without file extension.
161        Validate that error conditions are caught correctly
162        """
163        stderr = StringIO()
164        management.call_command(
165            'loaddata',
166            'bad_fixture2',
167            verbosity=0,
168            commit=False,
169            stderr=stderr,
170        )
171        self.assertEqual(
172            stderr.getvalue(),
173            "No fixture data found for 'bad_fixture2'. (File format may be invalid.)\n"
174        )
175
176    def test_empty(self):
177        """
178        Test for ticket #4371 -- Loading a fixture file with no data returns an error.
179        Validate that error conditions are caught correctly
180        """
181        stderr = StringIO()
182        management.call_command(
183            'loaddata',
184            'empty',
185            verbosity=0,
186            commit=False,
187            stderr=stderr,
188        )
189        self.assertEqual(
190            stderr.getvalue(),
191            "No fixture data found for 'empty'. (File format may be invalid.)\n"
192        )
193
194    def test_abort_loaddata_on_error(self):
195        """
196        Test for ticket #4371 -- If any of the fixtures contain an error,
197        loading is aborted.
198        Validate that error conditions are caught correctly
199        """
200        stderr = StringIO()
201        management.call_command(
202            'loaddata',
203            'empty',
204            verbosity=0,
205            commit=False,
206            stderr=stderr,
207        )
208        self.assertEqual(
209            stderr.getvalue(),
210            "No fixture data found for 'empty'. (File format may be invalid.)\n"
211        )
212
213    def test_error_message(self):
214        """
215        (Regression for #9011 - error message is correct)
216        """
217        stderr = StringIO()
218        management.call_command(
219            'loaddata',
220            'bad_fixture2',
221            'animal',
222            verbosity=0,
223            commit=False,
224            stderr=stderr,
225        )
226        self.assertEqual(
227            stderr.getvalue(),
228            "No fixture data found for 'bad_fixture2'. (File format may be invalid.)\n"
229        )
230
231    def test_pg_sequence_resetting_checks(self):
232        """
233        Test for ticket #7565 -- PostgreSQL sequence resetting checks shouldn't
234        ascend to parent models when inheritance is used
235        (since they are treated individually).
236        """
237        management.call_command(
238            'loaddata',
239            'model-inheritance.json',
240            verbosity=0,
241            commit=False
242        )
243        self.assertEqual(Parent.objects.all()[0].id, 1)
244        self.assertEqual(Child.objects.all()[0].id, 1)
245
246    def test_close_connection_after_loaddata(self):
247        """
248        Test for ticket #7572 -- MySQL has a problem if the same connection is
249        used to create tables, load data, and then query over that data.
250        To compensate, we close the connection after running loaddata.
251        This ensures that a new connection is opened when test queries are
252        issued.
253        """
254        management.call_command(
255            'loaddata',
256            'big-fixture.json',
257            verbosity=0,
258            commit=False
259        )
260        articles = Article.objects.exclude(id=9)
261        self.assertEqual(
262            list(articles.values_list('id', flat=True)),
263            [1, 2, 3, 4, 5, 6, 7, 8]
264        )
265        # Just for good measure, run the same query again.
266        # Under the influence of ticket #7572, this will
267        # give a different result to the previous call.
268        self.assertEqual(
269            list(articles.values_list('id', flat=True)),
270            [1, 2, 3, 4, 5, 6, 7, 8]
271        )
272
273    def test_field_value_coerce(self):
274        """
275        Test for tickets #8298, #9942 - Field values should be coerced into the
276        correct type by the deserializer, not as part of the database write.
277        """
278        global pre_save_checks
279        pre_save_checks = []
280        signals.pre_save.connect(animal_pre_save_check)
281        management.call_command(
282            'loaddata',
283            'animal.xml',
284            verbosity=0,
285            commit=False,
286        )
287        self.assertEqual(
288            pre_save_checks,
289            [
290                ("Count = 42 (<type 'int'>)", "Weight = 1.2 (<type 'float'>)")
291            ]
292        )
293        signals.pre_save.disconnect(animal_pre_save_check)
294
295    def test_dumpdata_uses_default_manager(self):
296        """
297        Regression for #11286
298        Ensure that dumpdata honors the default manager
299        Dump the current contents of the database as a JSON fixture
300        """
301        management.call_command(
302            'loaddata',
303            'animal.xml',
304            verbosity=0,
305            commit=False,
306        )
307        management.call_command(
308            'loaddata',
309            'sequence.json',
310            verbosity=0,
311            commit=False,
312        )
313        animal = Animal(
314            name='Platypus',
315            latin_name='Ornithorhynchus anatinus',
316            count=2,
317            weight=2.2
318        )
319        animal.save()
320
321        stdout = StringIO()
322        management.call_command(
323            'dumpdata',
324            'fixtures_regress.animal',
325            format='json',
326            stdout=stdout
327        )
328
329        # Output order isn't guaranteed, so check for parts
330        data = stdout.getvalue()
331
332        # Get rid of artifacts like '000000002' to eliminate the differences
333        # between different Python versions.
334        data = re.sub('0{6,}\d', '', data)
335
336        lion_json = '{"pk": 1, "model": "fixtures_regress.animal", "fields": {"count": 3, "weight": 1.2, "name": "Lion", "latin_name": "Panthera leo"}}'
337        emu_json = '{"pk": 10, "model": "fixtures_regress.animal", "fields": {"count": 42, "weight": 1.2, "name": "Emu", "latin_name": "Dromaius novaehollandiae"}}'
338        platypus_json = '{"pk": %d, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}}'
339        platypus_json = platypus_json % animal.pk
340
341        self.assertEqual(len(data), len('[%s]' % ', '.join([lion_json, emu_json, platypus_json])))
342        self.assertTrue(lion_json in data)
343        self.assertTrue(emu_json in data)
344        self.assertTrue(platypus_json in data)
345
346    def test_proxy_model_included(self):
347        """
348        Regression for #11428 - Proxy models aren't included when you dumpdata
349        """
350        stdout = StringIO()
351        # Create an instance of the concrete class
352        widget = Widget.objects.create(name='grommet')
353        management.call_command(
354            'dumpdata',
355            'fixtures_regress.widget',
356            'fixtures_regress.widgetproxy',
357            format='json',
358            stdout=stdout
359        )
360        self.assertEqual(
361            stdout.getvalue(),
362            """[{"pk": %d, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]"""
363            % widget.pk
364            )
365
366
367class NaturalKeyFixtureTests(TestCase):
368    def assertRaisesMessage(self, exc, msg, func, *args, **kwargs):
369        try:
370            func(*args, **kwargs)
371        except Exception, e:
372            self.assertEqual(msg, str(e))
373            self.assertTrue(isinstance(e, exc), "Expected %s, got %s" % (exc, type(e)))
374
375    def test_nk_deserialize(self):
376        """
377        Test for ticket #13030 - Python based parser version
378        natural keys deserialize with fk to inheriting model
379        """
380        management.call_command(
381            'loaddata',
382            'model-inheritance.json',
383            verbosity=0,
384            commit=False
385        )
386        management.call_command(
387            'loaddata',
388            'nk-inheritance.json',
389            verbosity=0,
390            commit=False
391        )
392        self.assertEqual(
393            NKChild.objects.get(pk=1).data,
394            'apple'
395        )
396
397        self.assertEqual(
398            RefToNKChild.objects.get(pk=1).nk_fk.data,
399            'apple'
400        )
401
402    def test_nk_deserialize_xml(self):
403        """
404        Test for ticket #13030 - XML version
405        natural keys deserialize with fk to inheriting model
406        """
407        management.call_command(
408            'loaddata',
409            'model-inheritance.json',
410            verbosity=0,
411            commit=False
412        )
413        management.call_command(
414            'loaddata',
415            'nk-inheritance.json',
416            verbosity=0,
417            commit=False
418        )
419        management.call_command(
420            'loaddata',
421            'nk-inheritance2.xml',
422            verbosity=0,
423            commit=False
424        )
425        self.assertEqual(
426            NKChild.objects.get(pk=2).data,
427            'banana'
428        )
429        self.assertEqual(
430            RefToNKChild.objects.get(pk=2).nk_fk.data,
431            'apple'
432        )
433
434    def test_nk_on_serialize(self):
435        """
436        Check that natural key requirements are taken into account
437        when serializing models
438        """
439        management.call_command(
440            'loaddata',
441            'forward_ref_lookup.json',
442            verbosity=0,
443            commit=False
444            )
445
446        stdout = StringIO()
447        management.call_command(
448            'dumpdata',
449            'fixtures_regress.book',
450            'fixtures_regress.person',
451            'fixtures_regress.store',
452            verbosity=0,
453            format='json',
454            use_natural_keys=True,
455            stdout=stdout,
456        )
457        self.assertEqual(
458            stdout.getvalue(),
459            """[{"pk": 2, "model": "fixtures_regress.store", "fields": {"name": "Amazon"}}, {"pk": 3, "model": "fixtures_regress.store", "fields": {"name": "Borders"}}, {"pk": 4, "model": "fixtures_regress.person", "fields": {"name": "Neal Stephenson"}}, {"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]], "name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]"""
460        )
461
462    def test_dependency_sorting(self):
463        """
464        Now lets check the dependency sorting explicitly
465        It doesn't matter what order you mention the models
466        Store *must* be serialized before then Person, and both
467        must be serialized before Book.
468        """
469        sorted_deps = sort_dependencies(
470            [('fixtures_regress', [Book, Person, Store])]
471        )
472        self.assertEqual(
473            sorted_deps,
474            [Store, Person, Book]
475        )
476
477    def test_dependency_sorting_2(self):
478        sorted_deps = sort_dependencies(
479            [('fixtures_regress', [Book, Store, Person])]
480        )
481        self.assertEqual(
482            sorted_deps,
483            [Store, Person, Book]
484        )
485
486    def test_dependency_sorting_3(self):
487        sorted_deps = sort_dependencies(
488            [('fixtures_regress', [Store, Book, Person])]
489        )
490        self.assertEqual(
491            sorted_deps,
492            [Store, Person, Book]
493        )
494
495    def test_dependency_sorting_4(self):
496        sorted_deps = sort_dependencies(
497            [('fixtures_regress', [Store, Person, Book])]
498        )
499        self.assertEqual(
500            sorted_deps,
501            [Store, Person, Book]
502        )
503
504    def test_dependency_sorting_5(self):
505        sorted_deps = sort_dependencies(
506            [('fixtures_regress', [Person, Book, Store])]
507        )
508        self.assertEqual(
509            sorted_deps,
510            [Store, Person, Book]
511        )
512
513    def test_dependency_sorting_6(self):
514        sorted_deps = sort_dependencies(
515            [('fixtures_regress', [Person, Store, Book])]
516        )
517        self.assertEqual(
518            sorted_deps,
519            [Store, Person, Book]
520        )
521
522    def test_dependency_sorting_dangling(self):
523        sorted_deps = sort_dependencies(
524            [('fixtures_regress', [Person, Circle1, Store, Book])]
525        )
526        self.assertEqual(
527            sorted_deps,
528            [Circle1, Store, Person, Book]
529        )
530
531    def test_dependency_sorting_tight_circular(self):
532        self.assertRaisesMessage(
533            CommandError,
534            """Can't resolve dependencies for fixtures_regress.Circle1, fixtures_regress.Circle2 in serialized app list.""",
535            sort_dependencies,
536            [('fixtures_regress', [Person, Circle2, Circle1, Store, Book])],
537        )
538
539    def test_dependency_sorting_tight_circular_2(self):
540        self.assertRaisesMessage(
541            CommandError,
542            """Can't resolve dependencies for fixtures_regress.Circle1, fixtures_regress.Circle2 in serialized app list.""",
543            sort_dependencies,
544            [('fixtures_regress', [Circle1, Book, Circle2])],
545        )
546
547    def test_dependency_self_referential(self):
548        self.assertRaisesMessage(
549            CommandError,
550            """Can't resolve dependencies for fixtures_regress.Circle3 in serialized app list.""",
551            sort_dependencies,
552            [('fixtures_regress', [Book, Circle3])],
553        )
554
555    def test_dependency_sorting_long(self):
556        self.assertRaisesMessage(
557            CommandError,
558            """Can't resolve dependencies for fixtures_regress.Circle1, fixtures_regress.Circle2, fixtures_regress.Circle3 in serialized app list.""",
559            sort_dependencies,
560            [('fixtures_regress', [Person, Circle2, Circle1, Circle3, Store, Book])],
561        )
562
563    def test_dependency_sorting_normal(self):
564        sorted_deps = sort_dependencies(
565            [('fixtures_regress', [Person, ExternalDependency, Book])]
566        )
567        self.assertEqual(
568            sorted_deps,
569            [Person, Book, ExternalDependency]
570        )
571
572    def test_normal_pk(self):
573        """
574        Check that normal primary keys still work
575        on a model with natural key capabilities
576        """
577        management.call_command(
578            'loaddata',
579            'non_natural_1.json',
580            verbosity=0,
581            commit=False
582        )
583        management.call_command(
584            'loaddata',
585            'forward_ref_lookup.json',
586            verbosity=0,
587            commit=False
588        )
589        management.call_command(
590            'loaddata',
591            'non_natural_2.xml',
592            verbosity=0,
593            commit=False
594        )
595        books = Book.objects.all()
596        self.assertEqual(
597            books.__repr__(),
598            """[<Book: Cryptonomicon by Neal Stephenson (available at Amazon, Borders)>, <Book: Ender's Game by Orson Scott Card (available at Collins Bookstore)>, <Book: Permutation City by Greg Egan (available at Angus and Robertson)>]"""
599        )
600
601
602class TestTicket11101(TransactionTestCase):
603
604    def ticket_11101(self):
605        management.call_command(
606            'loaddata',
607            'thingy.json',
608            verbosity=0,
609            commit=False
610        )
611        self.assertEqual(Thingy.objects.count(), 1)
612        transaction.rollback()
613        self.assertEqual(Thingy.objects.count(), 0)
614        transaction.commit()
615
616    @skipUnlessDBFeature('supports_transactions')
617    def test_ticket_11101(self):
618        """Test that fixtures can be rolled back (ticket #11101)."""
619        ticket_11101 = transaction.commit_manually(self.ticket_11101)
620        ticket_11101()