#30457: on_commit should be triggered in a TestCase
------------------------------------+-------------------------------------
     Reporter:  Bernhard Mäder      |                    Owner:  Swatantra
         Type:  New feature         |                   Status:  assigned
    Component:  Documentation       |                  Version:  master
     Severity:  Normal              |               Resolution:
     Keywords:  on_commit TestCase  |             Triage Stage:  Accepted
    Has patch:  0                   |      Needs documentation:  0
  Needs tests:  0                   |  Patch needs improvement:  1
Easy pickings:  0                   |                    UI/UX:  0
------------------------------------+-------------------------------------

Comment (by Simon Charette):

 FWIW we switched to an approach that defers hooks execution to the end of
 the context manager instead of executing immediately by default to
 properly mimic what an atomic block would do.

 {{{#!python
 @contextmanager
 def execute_on_commit(immediately=False, using=None):
     """
     Context manager capturing transaction.on_commit() calls and executing
     them on exit or immediately if specified.

     This is required when using a subclass of django.test.TestCase as all
     tests are wrapped in a transaction that never gets committed.
     """
     for_alias = DEFAULT_DB_ALIAS if using is None else using
     deferred = []

     def side_effect(func, using=None):
         alias = DEFAULT_DB_ALIAS if using is None else using
         if alias != for_alias:
             return
         if immediately:
             return func()
         deferred.append(func)

     with mock.patch('django.db.transaction.on_commit') as patch:
         patch.side_effect = side_effect
         yield patch
     for func in deferred:
         func()
 }}}

 For example this was necessary to test edge cases such as lazy loading
 failure of deleted objects

 {{{#!python
 parent = Node.objects.create()
 node = Node.objects.create(parent=parent)
 with self.immediate_on_commit():
     # imagine a pre-delete signal scheduling the following hook.
     transaction.on_commit(lambda: node.parent.something())
     parent.delete()
 }}}

 Would fail in a normal scenario because `parent` doesn't exist anymore one
 the transaction commits. This is covered by `execute_on_commit`.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/30457#comment:10>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/064.79e377e855845948157822ee6cdbb8c0%40djangoproject.com.

Reply via email to