deferred: Make MWCallableUpdate support a list of DB handles
authorAaron Schulz <aschulz@wikimedia.org>
Tue, 23 Jan 2018 15:06:32 +0000 (16:06 +0100)
committerStephane Bisson <sbisson@wikimedia.org>
Thu, 1 Feb 2018 01:04:48 +0000 (20:04 -0500)
Change-Id: I0371ecd20101c5e622497e5912676300b040865e

includes/deferred/MWCallableUpdate.php
tests/phpunit/includes/deferred/MWCallableUpdateTest.php

index 5b822af..9803b7a 100644 (file)
@@ -14,14 +14,18 @@ class MWCallableUpdate implements DeferrableUpdate, DeferrableCallback {
        /**
         * @param callable $callback
         * @param string $fname Calling method
-        * @param IDatabase|null $dbw Abort if this DB is rolled back [optional] (since 1.28)
+        * @param IDatabase|IDatabase[]|null $dbws Abort if any of the specified DB handles have
+        *   a currently pending transaction which later gets rolled back [optional] (since 1.28)
         */
-       public function __construct( callable $callback, $fname = 'unknown', IDatabase $dbw = null ) {
+       public function __construct( callable $callback, $fname = 'unknown', $dbws = [] ) {
                $this->callback = $callback;
                $this->fname = $fname;
 
-               if ( $dbw && $dbw->trxLevel() ) {
-                       $dbw->onTransactionResolution( [ $this, 'cancelOnRollback' ], $fname );
+               $dbws = is_array( $dbws ) ? $dbws : [ $dbws ];
+               foreach ( $dbws as $dbw ) {
+                       if ( $dbw && $dbw->trxLevel() ) {
+                               $dbw->onTransactionResolution( [ $this, 'cancelOnRollback' ], $fname );
+                       }
                }
        }
 
index 088ab4f..6977aef 100644 (file)
@@ -29,8 +29,54 @@ class MWCallableUpdateTest extends PHPUnit_Framework_TestCase {
                // Emulate rollback
                $db->rollback( __METHOD__ );
 
+               $update->doUpdate();
+
+               // Ensure it was cancelled
+               $this->assertSame( 0, $ran );
+       }
+
+       public function testCancelSome() {
+               // Prepare update and DB
+               $db1 = new DatabaseTestHelper( __METHOD__ );
+               $db1->begin( __METHOD__ );
+               $db2 = new DatabaseTestHelper( __METHOD__ );
+               $db2->begin( __METHOD__ );
+               $ran = 0;
+               $update = new MWCallableUpdate( function () use ( &$ran ) {
+                       $ran++;
+               }, __METHOD__, [ $db1, $db2 ] );
+
+               // Emulate rollback
+               $db1->rollback( __METHOD__ );
+
+               $update->doUpdate();
+
+               // Prevents: "Notice: DB transaction writes or callbacks still pending"
+               $db2->rollback( __METHOD__ );
+
                // Ensure it was cancelled
+               $this->assertSame( 0, $ran );
+       }
+
+       public function testCancelAll() {
+               // Prepare update and DB
+               $db1 = new DatabaseTestHelper( __METHOD__ );
+               $db1->begin( __METHOD__ );
+               $db2 = new DatabaseTestHelper( __METHOD__ );
+               $db2->begin( __METHOD__ );
+               $ran = 0;
+               $update = new MWCallableUpdate( function () use ( &$ran ) {
+                       $ran++;
+               }, __METHOD__, [ $db1, $db2 ] );
+
+               // Emulate rollbacks
+               $db1->rollback( __METHOD__ );
+               $db2->rollback( __METHOD__ );
+
                $update->doUpdate();
+
+               // Ensure it was cancelled
                $this->assertSame( 0, $ran );
        }
+
 }