/** * Call this method from test if you want to make sure that * the resetting of database is done the slow way without transaction * rollback. * * This is useful especially when testing stuff that is not compatible with transactions. * * @return void */ public function preventResetByRollback() { if ($this->testdbtransaction and !$this->testdbtransaction->is_disposed()) { $this->testdbtransaction->allow_commit(); $this->testdbtransaction = null; } }
function test_wrong_transactions() { $DB = $this->tdb; $dbman = $DB->get_manager(); $table = $this->get_test_table(); $tablename = $table->getName(); $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0'); $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); $dbman->create_table($table); // wrong order of nested commits $transaction1 = $DB->start_delegated_transaction(); $data = (object) array('course' => 3); $DB->insert_record($tablename, $data); $transaction2 = $DB->start_delegated_transaction(); $data = (object) array('course' => 4); $DB->insert_record($tablename, $data); try { $transaction1->allow_commit(); $this->fail('wrong order of commits must throw exception'); } catch (Exception $e) { $this->assertEqual(get_class($e), 'dml_transaction_exception'); } try { $transaction2->allow_commit(); $this->fail('first wrong commit forces rollback'); } catch (Exception $e) { $this->assertEqual(get_class($e), 'dml_transaction_exception'); } // this is done in default exception handler usually $this->assertTrue($DB->is_transaction_started()); $this->assertEqual(2, $DB->count_records($tablename)); // not rolled back yet $DB->force_transaction_rollback(); $this->assertEqual(0, $DB->count_records($tablename)); $DB->delete_records($tablename); // wrong order of nested rollbacks $transaction1 = $DB->start_delegated_transaction(); $data = (object) array('course' => 3); $DB->insert_record($tablename, $data); $transaction2 = $DB->start_delegated_transaction(); $data = (object) array('course' => 4); $DB->insert_record($tablename, $data); try { // this first rollback should prevent all other rollbacks $transaction1->rollback(new Exception('test')); } catch (Exception $e) { $this->assertEqual(get_class($e), 'Exception'); } try { $transaction2->rollback(new Exception('test')); } catch (Exception $e) { $this->assertEqual(get_class($e), 'Exception'); } try { $transaction1->rollback(new Exception('test')); } catch (Exception $e) { // the rollback was used already once, no way to use it again $this->assertEqual(get_class($e), 'dml_transaction_exception'); } // this is done in default exception handler usually $this->assertTrue($DB->is_transaction_started()); $DB->force_transaction_rollback(); $DB->delete_records($tablename); // unknown transaction object $transaction1 = $DB->start_delegated_transaction(); $data = (object) array('course' => 3); $DB->insert_record($tablename, $data); $transaction2 = new moodle_transaction($DB); try { $transaction2->allow_commit(); $this->fail('foreign transaction must fail'); } catch (Exception $e) { $this->assertEqual(get_class($e), 'dml_transaction_exception'); } try { $transaction1->allow_commit(); $this->fail('first wrong commit forces rollback'); } catch (Exception $e) { $this->assertEqual(get_class($e), 'dml_transaction_exception'); } $DB->force_transaction_rollback(); $DB->delete_records($tablename); }