2008-11-10 00:56:24 +01:00
|
|
|
<?php
|
2016-06-15 06:03:16 +02:00
|
|
|
|
|
|
|
use SilverStripe\ORM\DB;
|
|
|
|
use SilverStripe\ORM\Connect\MySQLDatabase;
|
|
|
|
use SilverStripe\ORM\Connect\MySQLSchemaManager;
|
|
|
|
use SilverStripe\ORM\DataObject;
|
2008-11-10 00:56:24 +01:00
|
|
|
/**
|
2012-04-12 08:02:46 +02:00
|
|
|
* @package framework
|
2008-11-10 00:56:24 +01:00
|
|
|
* @subpackage Testing
|
|
|
|
*/
|
|
|
|
class DatabaseTest extends SapphireTest {
|
2010-04-12 04:03:16 +02:00
|
|
|
|
|
|
|
protected $extraDataObjects = array(
|
|
|
|
'DatabaseTest_MyObject',
|
|
|
|
);
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2009-11-30 02:56:05 +01:00
|
|
|
protected $usesDatabase = true;
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2012-09-19 12:07:39 +02:00
|
|
|
public function testDontRequireField() {
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema = DB::get_schema();
|
2008-11-10 00:56:24 +01:00
|
|
|
$this->assertArrayHasKey(
|
|
|
|
'MyField',
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema->fieldList('DatabaseTest_MyObject')
|
2008-11-10 00:56:24 +01:00
|
|
|
);
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema->dontRequireField('DatabaseTest_MyObject', 'MyField');
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2008-11-10 00:56:24 +01:00
|
|
|
$this->assertArrayHasKey(
|
|
|
|
'_obsolete_MyField',
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema->fieldList('DatabaseTest_MyObject'),
|
2008-11-10 00:56:24 +01:00
|
|
|
'Field is renamed to _obsolete_<fieldname> through dontRequireField()'
|
|
|
|
);
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2010-04-12 04:03:16 +02:00
|
|
|
$this->resetDBSchema(true);
|
2008-11-10 00:56:24 +01:00
|
|
|
}
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2012-09-19 12:07:39 +02:00
|
|
|
public function testRenameField() {
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema = DB::get_schema();
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema->clearCachedFieldlist();
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema->renameField('DatabaseTest_MyObject', 'MyField', 'MyRenamedField');
|
2008-11-10 00:56:24 +01:00
|
|
|
|
|
|
|
$this->assertArrayHasKey(
|
|
|
|
'MyRenamedField',
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema->fieldList('DatabaseTest_MyObject'),
|
2008-11-10 00:56:24 +01:00
|
|
|
'New fieldname is set through renameField()'
|
|
|
|
);
|
|
|
|
$this->assertArrayNotHasKey(
|
|
|
|
'MyField',
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema->fieldList('DatabaseTest_MyObject'),
|
2008-11-10 00:56:24 +01:00
|
|
|
'Old fieldname isnt preserved through renameField()'
|
|
|
|
);
|
2010-04-12 04:03:16 +02:00
|
|
|
|
|
|
|
$this->resetDBSchema(true);
|
2008-11-10 00:56:24 +01:00
|
|
|
}
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2012-09-19 12:07:39 +02:00
|
|
|
public function testMySQLCreateTableOptions() {
|
2013-06-21 00:32:08 +02:00
|
|
|
if(!(DB::get_conn() instanceof MySQLDatabase)) {
|
2012-11-23 14:55:19 +01:00
|
|
|
$this->markTestSkipped('MySQL only');
|
2009-05-19 05:55:14 +02:00
|
|
|
}
|
2012-11-23 14:55:19 +01:00
|
|
|
|
|
|
|
|
|
|
|
$ret = DB::query(sprintf(
|
|
|
|
'SHOW TABLE STATUS WHERE "Name" = \'%s\'',
|
|
|
|
'DatabaseTest_MyObject'
|
|
|
|
))->first();
|
|
|
|
$this->assertEquals($ret['Engine'],'InnoDB',
|
|
|
|
"MySQLDatabase tables can be changed to InnoDB through DataObject::\$create_table_options"
|
|
|
|
);
|
2010-04-13 01:43:10 +02:00
|
|
|
}
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2012-10-17 00:34:43 +02:00
|
|
|
function testIsSchemaUpdating() {
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema = DB::get_schema();
|
|
|
|
|
|
|
|
$this->assertFalse($schema->isSchemaUpdating(), 'Before the transaction the flag is false.');
|
|
|
|
|
|
|
|
// Test complete schema update
|
|
|
|
$test = $this;
|
|
|
|
$schema->schemaUpdate(function() use ($test, $schema) {
|
|
|
|
$test->assertTrue($schema->isSchemaUpdating(), 'During the transaction the flag is true.');
|
|
|
|
});
|
|
|
|
$this->assertFalse($schema->isSchemaUpdating(), 'After the transaction the flag is false.');
|
|
|
|
|
|
|
|
// Test cancelled schema update
|
|
|
|
$schema->schemaUpdate(function() use ($test, $schema) {
|
|
|
|
$schema->cancelSchemaUpdate();
|
|
|
|
$test->assertFalse($schema->doesSchemaNeedUpdating(), 'After cancelling the transaction the flag is false');
|
|
|
|
});
|
2012-10-17 00:34:43 +02:00
|
|
|
}
|
|
|
|
|
2012-09-19 12:07:39 +02:00
|
|
|
public function testSchemaUpdateChecking() {
|
2013-06-21 00:32:08 +02:00
|
|
|
$schema = DB::get_schema();
|
2010-04-13 01:43:10 +02:00
|
|
|
|
|
|
|
// Initially, no schema changes necessary
|
2013-06-21 00:32:08 +02:00
|
|
|
$test = $this;
|
|
|
|
$schema->schemaUpdate(function() use ($test, $schema) {
|
|
|
|
$test->assertFalse($schema->doesSchemaNeedUpdating());
|
|
|
|
|
|
|
|
// If we make a change, then the schema will need updating
|
|
|
|
$schema->transCreateTable("TestTable");
|
|
|
|
$test->assertTrue($schema->doesSchemaNeedUpdating());
|
|
|
|
|
|
|
|
// If we make cancel the change, then schema updates are no longer necessary
|
|
|
|
$schema->cancelSchemaUpdate();
|
|
|
|
$test->assertFalse($schema->doesSchemaNeedUpdating());
|
|
|
|
});
|
2009-05-19 05:55:14 +02:00
|
|
|
}
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2012-09-19 12:07:39 +02:00
|
|
|
public function testHasTable() {
|
2013-06-21 00:32:08 +02:00
|
|
|
$this->assertTrue(DB::get_schema()->hasTable('DatabaseTest_MyObject'));
|
|
|
|
$this->assertFalse(DB::get_schema()->hasTable('asdfasdfasdf'));
|
2010-10-15 04:57:14 +02:00
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-09-19 12:07:39 +02:00
|
|
|
public function testGetAndReleaseLock() {
|
2013-06-21 00:32:08 +02:00
|
|
|
$db = DB::get_conn();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2011-09-22 16:28:58 +02:00
|
|
|
if(!$db->supportsLocks()) {
|
|
|
|
return $this->markTestSkipped('Tested database doesn\'t support application locks');
|
|
|
|
}
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2012-09-26 23:34:00 +02:00
|
|
|
$this->assertTrue($db->getLock('DatabaseTest'),
|
|
|
|
'Can aquire lock');
|
2011-09-22 16:28:58 +02:00
|
|
|
// $this->assertFalse($db->getLock('DatabaseTest'), 'Can\'t repeatedly aquire the same lock');
|
2012-09-26 23:34:00 +02:00
|
|
|
$this->assertTrue($db->getLock('DatabaseTest'),
|
|
|
|
'The same lock can be aquired multiple times in the same connection');
|
2011-09-22 16:28:58 +02:00
|
|
|
|
2012-09-26 23:34:00 +02:00
|
|
|
$this->assertTrue($db->getLock('DatabaseTestOtherLock'),
|
|
|
|
'Can aquire different lock');
|
2011-09-22 16:28:58 +02:00
|
|
|
$db->releaseLock('DatabaseTestOtherLock');
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2011-09-22 16:28:58 +02:00
|
|
|
// Release potentially stacked locks from previous getLock() invocations
|
|
|
|
$db->releaseLock('DatabaseTest');
|
|
|
|
$db->releaseLock('DatabaseTest');
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-09-26 23:34:00 +02:00
|
|
|
$this->assertTrue($db->getLock('DatabaseTest'),
|
|
|
|
'Can aquire lock after releasing it');
|
2011-09-22 16:28:58 +02:00
|
|
|
$db->releaseLock('DatabaseTest');
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2012-09-19 12:07:39 +02:00
|
|
|
public function testCanLock() {
|
2013-06-21 00:32:08 +02:00
|
|
|
$db = DB::get_conn();
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2011-09-22 16:28:58 +02:00
|
|
|
if(!$db->supportsLocks()) {
|
|
|
|
return $this->markTestSkipped('Database doesn\'t support locks');
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2011-09-22 16:28:58 +02:00
|
|
|
if($db instanceof MSSQLDatabase) {
|
|
|
|
return $this->markTestSkipped('MSSQLDatabase doesn\'t support inspecting locks');
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2011-09-22 16:28:58 +02:00
|
|
|
$this->assertTrue($db->canLock('DatabaseTest'), 'Can lock before first aquiring one');
|
|
|
|
$db->getLock('DatabaseTest');
|
|
|
|
$this->assertFalse($db->canLock('DatabaseTest'), 'Can\'t lock after aquiring one');
|
|
|
|
$db->releaseLock('DatabaseTest');
|
|
|
|
$this->assertTrue($db->canLock('DatabaseTest'), 'Can lock again after releasing it');
|
|
|
|
}
|
2014-08-15 08:53:05 +02:00
|
|
|
|
2016-03-23 01:42:51 +01:00
|
|
|
public function testTransactions() {
|
|
|
|
$conn = DB::getConn();
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-10 00:56:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class DatabaseTest_MyObject extends DataObject implements TestOnly {
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2013-06-21 00:32:08 +02:00
|
|
|
private static $create_table_options = array(MySQLSchemaManager::ID => 'ENGINE=InnoDB');
|
2011-01-12 01:10:38 +01:00
|
|
|
|
2013-03-21 19:48:54 +01:00
|
|
|
private static $db = array(
|
2008-11-10 00:56:24 +01:00
|
|
|
'MyField' => 'Varchar'
|
|
|
|
);
|
|
|
|
}
|