diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php index ce28102e1b8..73ffeefdfa8 100644 --- a/lib/dml/moodle_database.php +++ b/lib/dml/moodle_database.php @@ -2490,6 +2490,9 @@ abstract class moodle_database { // now enable transactions again $this->transactions = array(); $this->force_rollback = false; + + \core\event\manager::database_transaction_rolledback(); + \core\message\manager::database_transaction_rolledback(); } /** diff --git a/lib/tests/event_test.php b/lib/tests/event_test.php index ad84112678a..8d578c89cc7 100644 --- a/lib/tests/event_test.php +++ b/lib/tests/event_test.php @@ -458,6 +458,101 @@ class core_event_testcase extends advanced_testcase { \core_tests\event\unittest_observer::$info); } + public function test_rollback() { + global $DB; + + $this->resetAfterTest(); + $this->preventResetByRollback(); + + $observers = array( + array( + 'eventname' => '\core_tests\event\unittest_executed', + 'callback' => '\core_tests\event\unittest_observer::external_observer', + 'internal' => 0, + ), + ); + + \core\event\manager::phpunit_replace_observers($observers); + \core_tests\event\unittest_observer::reset(); + + $this->assertCount(0, \core_tests\event\unittest_observer::$event); + + \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger(); + $this->assertCount(1, \core_tests\event\unittest_observer::$event); + \core_tests\event\unittest_observer::reset(); + + $transaction1 = $DB->start_delegated_transaction(); + + \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger(); + $this->assertCount(0, \core_tests\event\unittest_observer::$event); + + $transaction2 = $DB->start_delegated_transaction(); + + \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger(); + $this->assertCount(0, \core_tests\event\unittest_observer::$event); + + try { + $transaction2->rollback(new Exception('x')); + $this->fail('Expecting exception'); + } catch (Exception $e) {} + $this->assertCount(0, \core_tests\event\unittest_observer::$event); + + $this->assertTrue($DB->is_transaction_started()); + + try { + $transaction1->rollback(new Exception('x')); + $this->fail('Expecting exception'); + } catch (Exception $e) {} + $this->assertCount(0, \core_tests\event\unittest_observer::$event); + + $this->assertFalse($DB->is_transaction_started()); + + \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger(); + $this->assertCount(1, \core_tests\event\unittest_observer::$event); + } + + public function test_forced_rollback() { + global $DB; + + $this->resetAfterTest(); + $this->preventResetByRollback(); + + $observers = array( + array( + 'eventname' => '\core_tests\event\unittest_executed', + 'callback' => '\core_tests\event\unittest_observer::external_observer', + 'internal' => 0, + ), + ); + + \core\event\manager::phpunit_replace_observers($observers); + \core_tests\event\unittest_observer::reset(); + + $this->assertCount(0, \core_tests\event\unittest_observer::$event); + + \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger(); + $this->assertCount(1, \core_tests\event\unittest_observer::$event); + \core_tests\event\unittest_observer::reset(); + + $transaction1 = $DB->start_delegated_transaction(); + + \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger(); + $this->assertCount(0, \core_tests\event\unittest_observer::$event); + + $transaction2 = $DB->start_delegated_transaction(); + + \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger(); + $this->assertCount(0, \core_tests\event\unittest_observer::$event); + + $DB->force_transaction_rollback(); + $this->assertCount(0, \core_tests\event\unittest_observer::$event); + + $this->assertFalse($DB->is_transaction_started()); + + \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger(); + $this->assertCount(1, \core_tests\event\unittest_observer::$event); + } + public function test_deprecated() { global $DB; diff --git a/lib/tests/messagelib_test.php b/lib/tests/messagelib_test.php index 61d97171b7d..2d076bea8c6 100644 --- a/lib/tests/messagelib_test.php +++ b/lib/tests/messagelib_test.php @@ -712,6 +712,104 @@ class core_messagelib_testcase extends advanced_testcase { $DB->delete_records('message_read', array()); } + public function test_rollback() { + global $DB; + + $this->resetAfterTest(); + $this->preventResetByRollback(); + set_config('noemailever', 1); + + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + + $message = new stdClass(); + $message->component = 'moodle'; + $message->name = 'instantmessage'; + $message->userfrom = $user1; + $message->userto = $user2; + $message->subject = 'message subject 1'; + $message->fullmessage = 'message body'; + $message->fullmessageformat = FORMAT_MARKDOWN; + $message->fullmessagehtml = '

message body

'; + $message->smallmessage = 'small message'; + $message->notification = '0'; + + message_send($message); + $this->assertDebuggingCalled('Not sending email due to $CFG->noemailever config setting'); + + $transaction1 = $DB->start_delegated_transaction(); + + message_send($message); + $this->assertDebuggingNotCalled(); + + $transaction2 = $DB->start_delegated_transaction(); + + message_send($message); + $this->assertDebuggingNotCalled(); + + try { + $transaction2->rollback(new Exception('x')); + $this->fail('Expecting exception'); + } catch (Exception $e) {} + $this->assertDebuggingNotCalled(); + + $this->assertTrue($DB->is_transaction_started()); + + try { + $transaction1->rollback(new Exception('x')); + $this->fail('Expecting exception'); + } catch (Exception $e) {} + $this->assertDebuggingNotCalled(); + + $this->assertFalse($DB->is_transaction_started()); + + message_send($message); + $this->assertDebuggingCalled('Not sending email due to $CFG->noemailever config setting'); + } + + public function test_forced_rollback() { + global $DB; + + $this->resetAfterTest(); + $this->preventResetByRollback(); + set_config('noemailever', 1); + + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + + $message = new stdClass(); + $message->component = 'moodle'; + $message->name = 'instantmessage'; + $message->userfrom = $user1; + $message->userto = $user2; + $message->subject = 'message subject 1'; + $message->fullmessage = 'message body'; + $message->fullmessageformat = FORMAT_MARKDOWN; + $message->fullmessagehtml = '

message body

'; + $message->smallmessage = 'small message'; + $message->notification = '0'; + + message_send($message); + $this->assertDebuggingCalled('Not sending email due to $CFG->noemailever config setting'); + + $transaction1 = $DB->start_delegated_transaction(); + + message_send($message); + $this->assertDebuggingNotCalled(); + + $transaction2 = $DB->start_delegated_transaction(); + + message_send($message); + $this->assertDebuggingNotCalled(); + + $DB->force_transaction_rollback(); + $this->assertFalse($DB->is_transaction_started()); + $this->assertDebuggingNotCalled(); + + message_send($message); + $this->assertDebuggingCalled('Not sending email due to $CFG->noemailever config setting'); + } + public function test_message_attachment_send() { global $CFG; $this->preventResetByRollback();