API CHANGE: Don't generate TestOnly DataObjects in the database immediately; instead let test developers specify them in SapphireTest::$extraDataObjects.

API CHANGE: Added SapphireTest::resetDBSchema() (from r90054) (from r96734)

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@102356 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2010-04-12 02:03:16 +00:00
parent 1dec4a33f8
commit e921b376bc
28 changed files with 228 additions and 48 deletions

View File

@ -46,6 +46,10 @@ class ClassInfo {
}
}
static function reset_db_cache() {
self::$_cache_all_tables = null;
}
/**
* Returns the manifest of all classes which are present in the database.
*/
@ -70,15 +74,15 @@ class ClassInfo {
if(!$_ALL_CLASSES['parents'][$class]) user_error("ClassInfo::dataClassesFor() no parents for $class", E_USER_WARNING);
foreach($_ALL_CLASSES['parents'][$class] as $subclass) {
if(DataObject::has_own_table($subclass)) $dataClasses[] = $subclass;
if(self::hasTable($subclass)) $dataClasses[] = $subclass;
}
if(DataObject::has_own_table($class)) $dataClasses[] = $class;
if(self::hasTable($class)) $dataClasses[] = $class;
if(isset($_ALL_CLASSES['children'][$class]))
foreach($_ALL_CLASSES['children'][$class] as $subclass)
{
if(DataObject::has_own_table($subclass)) $dataClasses[] = $subclass;
if(self::hasTable($subclass)) $dataClasses[] = $subclass;
}
return $dataClasses;

View File

@ -225,6 +225,7 @@ class DatabaseAdmin extends Controller {
}
if(!$quiet) echo "<p>Database build completed!</p>";
ClassInfo::reset_db_cache();
}
/**

View File

@ -38,12 +38,12 @@ class CliTestReporter extends SapphireTestReporter {
// Use sake dev/tests/all --showslow to show slow tests
if((isset($_GET['args']) && is_array($_GET['args']) && in_array('--showslow', $_GET['args'])) || isset($_GET['showslow'])) {
$avgSpeed = round(array_sum($this->testSpeeds) / count($this->testSpeeds), 3);
echo "Slow tests (more than twice the average $avgSpeed seconds):\n";
echo "Slow tests (more than the average $avgSpeed seconds):\n";
arsort($this->testSpeeds);
foreach($this->testSpeeds as $k => $v) {
// Ignore below-average speeds
if($v < $avgSpeed*2) break;
if($v < $avgSpeed) break;
echo " - $k: " . round($v,3) . "\n";
}

View File

@ -59,6 +59,13 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
protected $requiredExtensions = array(
);
/**
* By default, the test database won't contain any DataObjects that have the interface TestOnly.
* This variable lets you define additional TestOnly DataObjects to set up for this test.
* Set it to an array of DataObject subclass names.
*/
protected $extraDataObjects = array();
/**
* We need to disabling backing up of globals to avoid overriding
* the few globals SilverStripe relies on, like $lang for the i18n subsystem.
@ -174,15 +181,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
}
// If we have made changes to the extensions present, then migrate the database schema.
if($this->extensionsToReapply || $this->extensionsToRemove) {
// clear singletons, they're caching old extension info which is used in DatabaseAdmin->doBuild()
global $_SINGLETONS;
$_SINGLETONS = array();
// rebuild the db schema
$dbadmin = new DatabaseAdmin();
$dbadmin->doBuild(true, false, true);
singleton('DataObject')->flushCache();
if($this->extensionsToReapply || $this->extensionsToRemove || $this->extraDataObjects) {
$this->resetDBSchema(true);
}
// clear singletons, they're caching old extension info
// which is used in DatabaseAdmin->doBuild()
@ -209,14 +209,10 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
Object::add_extension($class, $extension);
}
}
// clear singletons, they're caching old extension info which is used in DatabaseAdmin->doBuild()
global $_SINGLETONS;
$_SINGLETONS = array();
// rebuild the db schema
$dbadmin = new DatabaseAdmin();
$dbadmin->doBuild(true, false, true);
}
if($this->extensionsToReapply || $this->extensionsToRemove || $this->extraDataObjects) {
$this->resetDBSchema();
}
}
@ -576,9 +572,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
$dbConn->selectDatabase($dbname);
$dbConn->createDatabase();
$dbadmin = new DatabaseAdmin();
$dbadmin->doBuild(true, false, true);
singleton('SapphireTest')->resetDBSchema();
return $dbname;
}
@ -593,6 +588,46 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
}
}
/**
* Reset the testing database's schema.
* @param $includeExtraDataObjects If true, the extraDataObjects tables will also be included
*/
function resetDBSchema($includeExtraDataObjects = false) {
if(self::using_temp_db()) {
// clear singletons, they're caching old extension info which is used in DatabaseAdmin->doBuild()
global $_SINGLETONS;
$_SINGLETONS = array();
$dataClasses = ClassInfo::subclassesFor('DataObject');
array_shift($dataClasses);
$conn = DB::getConn();
$conn->beginSchemaUpdate();
DB::quiet();
foreach($dataClasses as $dataClass) {
// Check if class exists before trying to instantiate - this sidesteps any manifest weirdness
if(class_exists($dataClass)) {
$SNG = singleton($dataClass);
if(!($SNG instanceof TestOnly)) $SNG->requireTable();
}
}
// If we have additional dataobjects which need schema, do so here:
if($includeExtraDataObjects && $this->extraDataObjects) {
foreach($this->extraDataObjects as $dataClass) {
$SNG = singleton($dataClass);
if(singleton($dataClass) instanceof DataObject) $SNG->requireTable();
}
}
$conn->endSchemaUpdate();
ClassInfo::reset_db_cache();
singleton('DataObject')->flushCache();
}
}
/**
* Create a member and group with the given permission code, and log in with it.
* Returns the member ID.

View File

@ -1,7 +1,15 @@
<?php
class DataObjectDecoratorTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/DataObjectDecoratorTest.yml';
protected $extraDataObjects = array(
'DataObjectDecoratorTest_Member',
'DataObjectDecoratorTest_Player',
'DataObjectDecoratorTest_RelatedObject',
'DataObjectDecoratorTest_MyObject',
);
function testOneToManyAssociationWithDecorator() {
// Fails in RestfulServerTest
// Error: Object::__call() Method 'RelatedObjects' not found in class 'RestfulServerTest_Comment'
@ -66,8 +74,7 @@ class DataObjectDecoratorTest extends SapphireTest {
Object::add_extension('DataObjectDecoratorTest_Player', 'DataObjectDecoratorTest_PlayerDecorator');
// Now that we've just added the decorator, we need to rebuild the database
$da = new DatabaseAdmin();
$da->doBuild(true, false, true);
$this->resetDBSchema(true);
// Create a test record with decorated fields, writing to the DB
$player = new DataObjectDecoratorTest_Player();

View File

@ -8,6 +8,12 @@
class DataObjectSetTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/DataObjectTest.yml';
protected $extraDataObjects = array(
'DataObjectTest_Team',
'DataObjectTest_SubTeam',
'DataObjectTest_Player',
);
function testArrayAccessExists() {
$set = new DataObjectSet(array(

View File

@ -7,6 +7,17 @@ class DataObjectTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/DataObjectTest.yml';
protected $extraDataObjects = array(
'DataObjectTest_Team',
'DataObjectTest_Fixture',
'DataObjectTest_SubTeam',
'OtherSubclassWithSameField',
'DataObjectTest_FieldlessTable',
'DataObjectTest_FieldlessSubTable',
'DataObjectTest_ValidatedObject',
'DataObjectTest_Player',
);
/**
* Test deletion of DataObjects
* - Deleting using delete() on the DataObject
@ -949,7 +960,7 @@ class DataObjectTest_SubTeam extends DataObjectTest_Team implements TestOnly {
'SubclassDatabaseField' => 'Varchar'
);
}
class OtherSubclassWithSameField extends DataObjectTest_Team {
class OtherSubclassWithSameField extends DataObjectTest_Team implements TestOnly {
static $db = array(
'SubclassDatabaseField' => 'Varchar',
);

View File

@ -3,6 +3,10 @@
class SQLQueryTest extends SapphireTest {
static $fixture_file = null;
protected $extraDataObjects = array(
'SQLQueryTest_DO',
);
function testEmptyQueryReturnsNothing() {
$query = new SQLQuery();

View File

@ -4,6 +4,16 @@ class SearchContextTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/SearchContextTest.yml';
protected $extraDataObjects = array(
'SearchContextTest_Person',
'SearchContextTest_Book',
'SearchContextTest_Company',
'SearchContextTest_Project',
'SearchContextTest_Deadline',
'SearchContextTest_Action',
'SearchContextTest_AllFilterTypes',
);
function testResultSetFilterReturnsExpectedCount() {
$person = singleton('SearchContextTest_Person');
$context = $person->getDefaultSearchContext();

View File

@ -12,6 +12,11 @@ class SoapModelAccessTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/SoapModelAccessTest.yml';
protected $extraDataObjects = array(
'SoapModelAccessTest_Comment',
'SoapModelAccessTest_Page',
);
public function getTestSoapConnection() {
// We can't actually test the SOAP server itself because there's not currently a way of putting it into "test mode"
return new SOAPModelAccess();

View File

@ -10,6 +10,14 @@ class RestfulServerTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/api/RestfulServerTest.yml';
protected $extraDataObjects = array(
'RestfulServerTest_Comment',
'RestfulServerTest_SecretThing',
'RestfulServerTest_Page',
'RestfulServerTest_Author',
'RestfulServerTest_AuthorRating',
);
public function testApiAccess() {
$comment1 = $this->objFromFixture('RestfulServerTest_Comment', 'comment1');
$page1 = $this->objFromFixture('RestfulServerTest_Page', 'page1');

View File

@ -7,6 +7,12 @@
class CsvBulkLoaderTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/dev/CsvBulkLoaderTest.yml';
protected $extraDataObjects = array(
'CsvBulkLoaderTest_Team',
'CsvBulkLoaderTest_Player',
'CsvBulkLoaderTest_PlayerContract',
);
/**
* Test plain import with column auto-detection
*/

View File

@ -7,6 +7,10 @@ class CheckboxFieldTest extends SapphireTest {
protected $usesDatabase = true;
protected $extraDataObjects = array(
'CheckboxFieldTest_Article',
);
function testFieldValueTrue() {
/* Create the field, and set the value as boolean true */
$field = new CheckboxField('IsChecked', 'Checked');

View File

@ -4,8 +4,12 @@
* @subpackage tests
*/
class CheckboxSetFieldTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/forms/CheckboxSetFieldTest.yml';
protected $extraDataObjects = array(
'CheckboxSetFieldTest_Article',
'CheckboxSetFieldTest_Tag',
);
function testSetDefaultItems() {
$f = new CheckboxSetField(

View File

@ -8,6 +8,12 @@ class ComplexTableFieldTest extends FunctionalTest {
static $fixture_file = 'sapphire/tests/forms/ComplexTableFieldTest.yml';
static $use_draft_site = true;
protected $extraDataObjects = array(
'ComplexTableFieldTest_Player',
'ComplexTableFieldTest_Team',
'ComplexTableFieldTest_Sponsor',
);
/**
* An instance of {@link Controller} used for
* running tests against.

View File

@ -10,6 +10,13 @@
class FormScaffolderTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/forms/FormScaffolderTest.yml';
protected $extraDataObjects = array(
'FormScaffolderTest_Article',
'FormScaffolderTest_Tag',
'FormScaffolderTest_Author',
);
function testGetCMSFieldsSingleton() {
$fields = singleton('FormScaffolderTest_Article')->getCMSFields();

View File

@ -6,6 +6,11 @@
class FormTest extends FunctionalTest {
static $fixture_file = 'sapphire/tests/forms/FormTest.yml';
protected $extraDataObjects = array(
'FormTest_Player',
'FormTest_Team',
);
public function testLoadDataFromRequest() {
$form = new Form(

View File

@ -4,6 +4,12 @@
* @subpackage tests
*/
class MoneyFieldTest extends SapphireTest {
protected $extraDataObjects = array(
'MoneyFieldTest_Object',
'MoneyFieldTest_CustomSetter_Object',
);
function testSaveInto() {
$o = new MoneyFieldTest_Object();

View File

@ -3,6 +3,11 @@
class TableFieldTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/forms/TableFieldTest.yml';
protected $extraDataObjects = array(
'TableFieldTest_Object',
'TableFieldTest_HasManyRelation',
);
function testAdd() {
$group = $this->objFromFixture('Group','group1_no_perms');

View File

@ -2,6 +2,11 @@
class TableListFieldTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/forms/TableListFieldTest.yml';
protected $extraDataObjects = array(
'TableListFieldTest_Obj',
'TableListFieldTest_CsvExport',
);
function testCanReferenceCustomMethodsAndFieldsOnObject() {
$table = new TableListField("Tester", "TableListFieldTest_Obj", array(

View File

@ -17,6 +17,11 @@ class i18nTest extends SapphireTest {
* /i18ntestmodule which contains some files with _t() calls.
*/
protected $alternateBasePath;
protected $extraDataObjects = array(
'i18nTest_DataObject'
);
function setUp() {
parent::setUp();

View File

@ -4,6 +4,12 @@
* @subpackage tests
*/
class CompositeDBFieldTest extends SapphireTest {
protected $extraDataObjects = array(
'CompositeDBFieldTest_DataObject',
'SubclassedDBFieldObject',
);
function testHasDatabaseFieldOnDataObject() {
$obj = singleton('CompositeDBFieldTest_DataObject');

View File

@ -4,6 +4,10 @@
* @subpackage Testing
*/
class DatabaseTest extends SapphireTest {
protected $extraDataObjects = array(
'DatabaseTest_MyObject',
);
protected $usesDatabase = true;
@ -21,9 +25,7 @@ class DatabaseTest extends SapphireTest {
'Field is renamed to _obsolete_<fieldname> through dontRequireField()'
);
// tested schema updates, so need to rebuild the database
self::kill_temp_db();
self::create_temp_db();
$this->resetDBSchema(true);
}
function testRenameField() {
@ -41,10 +43,8 @@ class DatabaseTest extends SapphireTest {
$conn->fieldList('DatabaseTest_MyObject'),
'Old fieldname isnt preserved through renameField()'
);
// tested schema updates, so need to rebuild the database
self::kill_temp_db();
self::create_temp_db();
$this->resetDBSchema(true);
}
function testMySQLCreateTableOptions() {

View File

@ -14,6 +14,10 @@
class MoneyTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/model/MoneyTest.yml';
protected $extraDataObjects = array(
'MoneyTest_DataObject',
);
function testMoneyFieldsReturnedAsObjects() {
$obj = $this->objFromFixture('MoneyTest_DataObject', 'test1');

View File

@ -8,6 +8,11 @@
class TranslatableTest extends FunctionalTest {
static $fixture_file = 'sapphire/tests/model/TranslatableTest.yml';
protected $extraDataObjects = array(
'TranslatableTest_DataObject',
'TranslatableTest_Page',
);
protected $requiredExtensions = array(
'SiteTree' => array('Translatable'),

View File

@ -2,6 +2,10 @@
class VersionedTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/model/VersionedTest.yml';
protected $extraDataObjects = array(
'VersionedTest_DataObject',
);
function testForceChangeUpdatesVersion() {
$page = $this->objFromFixture('Page', 'page3');
@ -52,7 +56,7 @@ class VersionedTest extends SapphireTest {
}
class VersionedTest_DataObject extends DataObject {
class VersionedTest_DataObject extends DataObject implements TestOnly {
static $db = array(
"Name" => "Varchar",
);
@ -62,7 +66,7 @@ class VersionedTest_DataObject extends DataObject {
);
}
class VersionedTest_Subclass extends VersionedTest_DataObject {
class VersionedTest_Subclass extends VersionedTest_DataObject implements TestOnly {
static $db = array(
"ExtraField" => "Varchar",
);

View File

@ -11,6 +11,18 @@
class SearchFilterApplyRelationTest extends SapphireTest{
static $fixture_file = 'sapphire/tests/search/SearchFilterApplyRelationTest.yml';
protected $extraDataObjects = array(
'SearchFilterApplyRelationTest_DO',
'SearchFilterApplyRelationTest_HasOneParent',
'SearchFilterApplyRelationTest_HasOneChild',
'SearchFilterApplyRelationTest_HasOneGrantChild',
'SearchFilterApplyRelationTest_HasManyParent',
'SearchFilterApplyRelationTest_HasManyChild',
'SearchFilterApplyRelationTest_HasManyGrantChild',
'SearchFilterApplyRelationTest_ManyManyParent',
'SearchFilterApplyRelationTest_ManyManyChild',
'SearchFilterApplyRelationTest_ManyManyGrantChild',
);
function testApplyRelationHasOne(){
@ -97,7 +109,7 @@ class SearchFilterApplyRelationTest extends SapphireTest{
}
}
class SearchFilterApplyRelationTest_DO extends DataObject implements TestOnly{
class SearchFilterApplyRelationTest_DO extends DataObject implements TestOnly {
static $has_one = array(
'SearchFilterApplyRelationTest_HasOneGrantChild' => 'SearchFilterApplyRelationTest_HasOneGrantChild'
);
@ -111,20 +123,20 @@ class SearchFilterApplyRelationTest_DO extends DataObject implements TestOnly{
);
}
class SearchFilterApplyRelationTest_HasOneParent extends DataObject implements TestOnly{
class SearchFilterApplyRelationTest_HasOneParent extends DataObject implements TestOnly {
static $db = array(
"Title" => "Varchar"
);
}
class SearchFilterApplyRelationTest_HasOneChild extends SearchFilterApplyRelationTest_HasOneParent{
class SearchFilterApplyRelationTest_HasOneChild extends SearchFilterApplyRelationTest_HasOneParent implements TestOnly {
// This is to create an seperate Table only.
static $db = array(
"ChildField" => "Varchar"
);
}
class SearchFilterApplyRelationTest_HasOneGrantChild extends SearchFilterApplyRelationTest_HasOneChild{
class SearchFilterApplyRelationTest_HasOneGrantChild extends SearchFilterApplyRelationTest_HasOneChild implements TestOnly {
// This is to create an seperate Table only.
static $db = array(
"GrantChildField" => "Varchar"
@ -134,13 +146,13 @@ class SearchFilterApplyRelationTest_HasOneGrantChild extends SearchFilterApplyRe
);
}
class SearchFilterApplyRelationTest_HasManyParent extends DataObject implements TestOnly{
class SearchFilterApplyRelationTest_HasManyParent extends DataObject implements TestOnly {
static $db = array(
"Title" => "Varchar"
);
}
class SearchFilterApplyRelationTest_HasManyChild extends SearchFilterApplyRelationTest_HasManyParent{
class SearchFilterApplyRelationTest_HasManyChild extends SearchFilterApplyRelationTest_HasManyParent implements TestOnly {
// This is to create an seperate Table only.
static $db = array(
"ChildField" => "Varchar"
@ -159,14 +171,14 @@ class SearchFilterApplyRelationTest_ManyManyParent extends DataObject implements
);
}
class SearchFilterApplyRelationTest_ManyManyChild extends SearchFilterApplyRelationTest_ManyManyParent{
class SearchFilterApplyRelationTest_ManyManyChild extends SearchFilterApplyRelationTest_ManyManyParent implements TestOnly {
// This is to create an seperate Table only.
static $db = array(
"ChildField" => "Varchar"
);
}
class SearchFilterApplyRelationTest_ManyManyGrantChild extends SearchFilterApplyRelationTest_ManyManyChild{
class SearchFilterApplyRelationTest_ManyManyGrantChild extends SearchFilterApplyRelationTest_ManyManyChild implements TestOnly {
// This is to create an seperate Table only.
static $db = array(
"GrantChildField" => "Varchar"

View File

@ -2,6 +2,11 @@
class YamlFixtureTest extends SapphireTest {
static $fixture_file = 'sapphire/tests/testing/YamlFixtureTest.yml';
protected $extraDataObjects = array(
'YamlFixtureTest_DataObject',
'YamlFixtureTest_DataObjectRelation',
);
function testSQLInsert() {
$object1 = DataObject::get_by_id("YamlFixtureTest_DataObject", $this->idFromFixture("YamlFixtureTest_DataObject", "testobject1"));
@ -11,7 +16,7 @@ class YamlFixtureTest extends SapphireTest {
}
}
class YamlFixtureTest_DataObject extends DataObject {
class YamlFixtureTest_DataObject extends DataObject implements TestOnly {
static $db = array(
"Name" => "Varchar"
);
@ -20,7 +25,7 @@ class YamlFixtureTest_DataObject extends DataObject {
);
}
class YamlFixtureTest_DataObjectRelation extends DataObject {
class YamlFixtureTest_DataObjectRelation extends DataObject implements TestOnly {
static $db = array(
"Name" => "Varchar"
);