#33410: captureOnCommitCallbacks executes callbacks multiple times
-------------------------------------+-------------------------------------
               Reporter:  flaeppe    |          Owner:  flaeppe
                   Type:  Bug        |         Status:  assigned
              Component:  Testing    |        Version:  dev
  framework                          |       Keywords:
               Severity:  Normal     |  captureOnCommitCallbacks
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 When recursively adding multiple on commit callbacks,
 `captureOnCommitCallbacks` executes some callbacks multiple times. Below
 is a test case to reproduce the error.

 {{{
 #!div style="font-size: 80%"
   {{{#!python
     def test_execute_tree(self):
         """
         A visualisation of the callback tree tested. Each node is expected
 to be visited
         only once. The child count of a node symbolises the amount of on
 commit
         callbacks.

         root
         └── branch_1
             ├── branch_2
             │   ├── leaf_1
             │   └── leaf_2
             └── leaf_3
         """
         (
             branch_1_call_counter,
             branch_2_call_counter,
             leaf_1_call_counter,
             leaf_2_call_counter,
             leaf_3_call_counter,
         ) = [itertools.count(start=1) for _ in range(5)]

         def leaf_3():
             next(leaf_3_call_counter)

         def leaf_2():
             next(leaf_2_call_counter)

         def leaf_1():
             next(leaf_1_call_counter)

         def branch_2():
             next(branch_2_call_counter)
             transaction.on_commit(leaf_1)
             transaction.on_commit(leaf_2)

         def branch_1():
             next(branch_1_call_counter)
             transaction.on_commit(branch_2)
             transaction.on_commit(leaf_3)

         with self.captureOnCommitCallbacks(execute=True) as callbacks:
             with transaction.atomic():
                 transaction.on_commit(branch_1)

         # Every counter shall only have been called once, starting at 1;
 next value then
         # has to be 2
         self.assertEqual(next(branch_1_call_counter), 2)
         self.assertEqual(next(branch_2_call_counter), 2)
         self.assertEqual(next(leaf_1_call_counter), 2)
         self.assertEqual(next(leaf_2_call_counter), 2)
         self.assertEqual(next(leaf_3_call_counter), 2)
         # Make sure all calls can be seen and the execution order is
 correct
         self.assertEqual(
             [(id(callback), callback.__name__) for callback in callbacks],
             [
                 (id(branch_1), "branch_1"),
                 (id(branch_2), "branch_2"),
                 (id(leaf_3), "leaf_3"),
                 (id(leaf_1), "leaf_1"),
                 (id(leaf_2), "leaf_2"),
             ],
         )
   }}}
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33410>
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 django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/050.e65f414f3dfd085519bac60decae4c8d%40djangoproject.com.

Reply via email to