FIX: Introduce readonly transaction test to all database.

This should work on MySQL and PDO; let’s test this.
This commit is contained in:
Sam Minnee 2018-10-18 20:19:39 +13:00
parent a7b5de5de4
commit 5531baa87f
2 changed files with 104 additions and 51 deletions

View File

@ -21,11 +21,6 @@ class DatabaseTest extends SapphireTest
protected $usesDatabase = true; protected $usesDatabase = true;
/**
* Disable transactions so that we can test them
*/
protected $usesTransactions = false;
public function testDontRequireField() public function testDontRequireField()
{ {
$schema = DB::get_schema(); $schema = DB::get_schema();
@ -192,52 +187,6 @@ class DatabaseTest extends SapphireTest
$this->assertTrue($db->canLock('DatabaseTest'), 'Can lock again after releasing it'); $this->assertTrue($db->canLock('DatabaseTest'), 'Can lock again after releasing it');
} }
public function testTransactions()
{
$conn = DB::get_conn();
if (!$conn->supportsTransactions()) {
$this->markTestSkipped("DB Doesn't support transactions");
return;
}
// Test that successful transactions are comitted
$obj = new DatabaseTest\MyObject();
$failed = false;
$conn->withTransaction(
function () use (&$obj) {
$obj->MyField = 'Save 1';
$obj->write();
},
function () use (&$failed) {
$failed = true;
}
);
$this->assertEquals('Save 1', DatabaseTest\MyObject::get()->first()->MyField);
$this->assertFalse($failed);
// Test failed transactions are rolled back
$ex = null;
$failed = false;
try {
$conn->withTransaction(
function () use (&$obj) {
$obj->MyField = 'Save 2';
$obj->write();
throw new Exception("error");
},
function () use (&$failed) {
$failed = true;
}
);
} catch (Exception $ex) {
}
$this->assertTrue($failed);
$this->assertEquals('Save 1', DatabaseTest\MyObject::get()->first()->MyField);
$this->assertInstanceOf('Exception', $ex);
$this->assertEquals('error', $ex->getMessage());
}
public function testFieldTypes() public function testFieldTypes()
{ {
// Scaffold some data // Scaffold some data

View File

@ -5,6 +5,7 @@ namespace SilverStripe\ORM\Tests;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\Tests\TransactionTest\TestObject; use SilverStripe\ORM\Tests\TransactionTest\TestObject;
class TransactionTest extends SapphireTest class TransactionTest extends SapphireTest
@ -17,6 +18,20 @@ class TransactionTest extends SapphireTest
TransactionTest\TestObject::class, TransactionTest\TestObject::class,
]; ];
private static $originalVersionInfo;
protected function setUp()
{
parent::setUp();
self::$originalVersionInfo = Deprecation::dump_settings();
}
protected function tearDown()
{
Deprecation::restore_settings(self::$originalVersionInfo);
parent::tearDown();
}
public static function setUpBeforeClass() public static function setUpBeforeClass()
{ {
parent::setUpBeforeClass(); parent::setUpBeforeClass();
@ -25,8 +40,57 @@ class TransactionTest extends SapphireTest
} }
} }
public function testTransactions()
{
$conn = DB::get_conn();
if (!$conn->supportsTransactions()) {
$this->markTestSkipped("DB Doesn't support transactions");
return;
}
// Test that successful transactions are comitted
$obj = new TestObject();
$failed = false;
$conn->withTransaction(
function () use (&$obj) {
$obj->Title = 'Save 1';
$obj->write();
},
function () use (&$failed) {
$failed = true;
}
);
$this->assertEquals('Save 1', TestObject::get()->first()->Title);
$this->assertFalse($failed);
// Test failed transactions are rolled back
$ex = null;
$failed = false;
try {
$conn->withTransaction(
function () use (&$obj) {
$obj->Title = 'Save 2';
$obj->write();
throw new \Exception("error");
},
function () use (&$failed) {
$failed = true;
}
);
} catch (\Exception $ex) {
}
$this->assertTrue($failed);
$this->assertEquals('Save 1', TestObject::get()->first()->Title);
$this->assertInstanceOf('Exception', $ex);
$this->assertEquals('error', $ex->getMessage());
}
public function testNestedTransaction() public function testNestedTransaction()
{ {
if (!DB::get_conn()->supportsSavepoints()) {
static::markTestSkipped('Current database does not support savepoints');
}
$this->assertCount(0, TestObject::get()); $this->assertCount(0, TestObject::get());
try { try {
DB::get_conn()->withTransaction(function () { DB::get_conn()->withTransaction(function () {
@ -89,4 +153,44 @@ class TransactionTest extends SapphireTest
$this->assertFalse(is_object($third) && $third->exists()); $this->assertFalse(is_object($third) && $third->exists());
$this->assertFalse(is_object($fourth) && $fourth->exists()); $this->assertFalse(is_object($fourth) && $fourth->exists());
} }
public function testReadOnlyTransaction()
{
if (!DB::get_conn()->supportsTransactions()) {
$this->markTestSkipped('Current database is doesn\'t support transactions');
return;
}
// This feature is deprecated in 4.4, but we're still testing it.
Deprecation::notification_version('4.3.0');
$page = new TestObject();
$page->Title = 'Read only success';
$page->write();
DB::get_conn()->transactionStart('READ ONLY');
try {
$page = new TestObject();
$page->Title = 'Read only page failed';
$page->write();
DB::get_conn()->transactionEnd();
} catch (\Exception $e) {
//could not write this record
//We need to do a rollback or a commit otherwise we'll get error messages
DB::get_conn()->transactionRollback();
}
DataObject::flush_and_destroy_cache();
$success = DataObject::get_one(TestObject::class, "\"Title\"='Read only success'");
$fail = DataObject::get_one(TestObject::class, "\"Title\"='Read only page failed'");
//This page should be in the system
$this->assertInternalType('object', $success);
$this->assertTrue($success->exists());
//This page should NOT exist, we had 'read only' permissions
$this->assertNull($fail);
}
} }