mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
More documentation
Fix up remaining tests Refactor temp DB into TempDatabase class so it’s available outside of unit tests.
This commit is contained in:
parent
5d235e64f3
commit
e2c4a18f63
@ -1295,6 +1295,9 @@ After (`mysite/_config/config.yml`):
|
||||
* `Configurable` Provides Config API helper methods
|
||||
* `Injectable` Provides Injector API helper methods
|
||||
* `Extensible` Allows extensions to be applied
|
||||
* `Convert` class has extra methods for formatting file sizes in php_ini compatible format
|
||||
* `Convert::memstring2bytes()` will parse a php_ini memory size.
|
||||
* `Convert::bytes2memstring()` will format the memory size with the appropriate scale.
|
||||
* `SiteTree.alternatePreviewLink` is deprecated. Use `updatePreviewLink` instead.
|
||||
* `Injector` dependencies no longer automatically inherit from parent classes.
|
||||
* `$action` parameter to `Controller::Link()` method is standardised.
|
||||
@ -1545,6 +1548,17 @@ A very small number of methods were chosen for deprecation, and will be removed
|
||||
* `DBMoney` values are now treated as empty only if `Amount` field is null. If an `Amount` value
|
||||
is provided without a `Currency` specified, it will be formatted as per the current locale.
|
||||
* Removed `DatabaseAdmin#clearAllData()`. Use `DB::get_conn()->clearAllData()` instead
|
||||
* `SapphireTest` temp DB methods have been removed and put into a new `TempDatabase` class.
|
||||
This allows applications to create temp databases when not running tests.
|
||||
This class now takes a connection name as a constructor class, and no longer
|
||||
has static methods.
|
||||
The following methods have been moved to this new class and renamed as non-static:
|
||||
* `using_temp_db` -> `isUsed()`
|
||||
* `kill_temp_db` -> `kill()`
|
||||
* `empty_temp_db` _> `clearAllData()`
|
||||
* `create_temp_db` -> `build()`
|
||||
* `delete_all_temp_dbs` -> `deleteAll()`
|
||||
* `resetDBSchema` -> `resetSchema()`
|
||||
|
||||
The below methods have been added or had their functionality updated to `DBDate`, `DBTime` and `DBDatetime`
|
||||
* `getTimestamp()` added to get the respective date / time as unix timestamp (seconds since 1970-01-01)
|
||||
|
@ -163,15 +163,17 @@ class HTTP
|
||||
*
|
||||
* @param string $varname
|
||||
* @param string $varvalue
|
||||
* @param string $currentURL Relative or absolute URL.
|
||||
* @param string|null $currentURL Relative or absolute URL, or HTTPRequest to get url from
|
||||
* @param string $separator Separator for http_build_query().
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function setGetVar($varname, $varvalue, $currentURL = null, $separator = '&')
|
||||
{
|
||||
$request = Controller::curr()->getRequest();
|
||||
$uri = $currentURL ?: $request->getURL();
|
||||
if (!isset($currentURL)) {
|
||||
$request = Controller::curr()->getRequest();
|
||||
$currentURL = $request->getURL(true);
|
||||
}
|
||||
$uri = $currentURL;
|
||||
|
||||
$isRelative = false;
|
||||
// We need absolute URLs for parse_url()
|
||||
|
@ -65,7 +65,7 @@ class HTTPRequestBuilder
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function extractRequestHeaders(array $server)
|
||||
public static function extractRequestHeaders(array $server)
|
||||
{
|
||||
$headers = array();
|
||||
foreach ($server as $key => $value) {
|
||||
|
@ -582,7 +582,7 @@ class Convert
|
||||
*/
|
||||
public static function bytes2memstring($bytes, $decimal = 0)
|
||||
{
|
||||
$scales = ['b','k','m','g'];
|
||||
$scales = ['B','K','M','G'];
|
||||
// Get scale
|
||||
$scale = (int)floor(log($bytes, 1024));
|
||||
if (!isset($scales[$scale])) {
|
||||
|
@ -67,7 +67,7 @@ class Environment
|
||||
// Check hard maximums
|
||||
$max = static::getMemoryLimitMax();
|
||||
if ($max > 0 && ($memoryLimit < 0 || $memoryLimit > $max)) {
|
||||
return false;
|
||||
$memoryLimit = $max;
|
||||
}
|
||||
|
||||
// Increase the memory limit if it's too low
|
||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\Core;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
|
||||
/**
|
||||
* Invokes the HTTP application within an ErrorControlChain
|
||||
@ -118,6 +119,8 @@ class HTTPApplication implements Application
|
||||
$this->getKernel()->boot($flush);
|
||||
return call_user_func($callback, $request);
|
||||
});
|
||||
} catch (HTTPResponse_Exception $ex) {
|
||||
return $ex->getResponse();
|
||||
} finally {
|
||||
$this->getKernel()->shutdown();
|
||||
}
|
||||
|
@ -13,20 +13,16 @@ use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\Email\Email;
|
||||
use SilverStripe\Control\Email\Mailer;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\Session;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\HTTPApplication;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Injector\InjectorLoader;
|
||||
use SilverStripe\Core\Manifest\ClassLoader;
|
||||
use SilverStripe\Dev\TestKernel;
|
||||
use SilverStripe\Dev\State\SapphireTestState;
|
||||
use SilverStripe\Dev\State\TestState;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\ORM\DataExtension;
|
||||
use SilverStripe\ORM\Connect\TempDatabase;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
@ -45,6 +41,9 @@ if (!class_exists(PHPUnit_Framework_TestCase::class)) {
|
||||
* Test case class for the Sapphire framework.
|
||||
* Sapphire unit testing is based on PHPUnit, but provides a number of hooks into our data model that make it easier
|
||||
* to work with.
|
||||
*
|
||||
* This class should not be used anywhere outside of unit tests, as phpunit may not be installed
|
||||
* in production sites.
|
||||
*/
|
||||
class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
@ -67,6 +66,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
* @var Boolean If set to TRUE, this will force a test database to be generated
|
||||
* in {@link setUp()}. Note that this flag is overruled by the presence of a
|
||||
* {@link $fixture_file}, which always forces a database build.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $usesDatabase = null;
|
||||
|
||||
@ -92,6 +93,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
* the values are an array of illegal extensions on that class.
|
||||
*
|
||||
* Set a class to `*` to remove all extensions (unadvised)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $illegal_extensions = [];
|
||||
|
||||
@ -106,6 +109,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
* <code>
|
||||
* array("MyTreeDataObject" => array("Versioned", "Hierarchy"))
|
||||
* </code>
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $required_extensions = [];
|
||||
|
||||
@ -113,6 +118,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
* 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.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $extra_dataobjects = [];
|
||||
|
||||
@ -139,6 +146,13 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
protected static $state = null;
|
||||
|
||||
/**
|
||||
* Temp database helper
|
||||
*
|
||||
* @var TempDatabase
|
||||
*/
|
||||
protected static $tempDB = null;
|
||||
|
||||
/**
|
||||
* Gets illegal extensions for this class
|
||||
*
|
||||
@ -229,13 +243,13 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
// Set up fixture
|
||||
if ($fixtureFiles || $this->usesDatabase) {
|
||||
if (!self::using_temp_db()) {
|
||||
self::create_temp_db();
|
||||
if (!static::$tempDB->isUsed()) {
|
||||
static::$tempDB->build();
|
||||
}
|
||||
|
||||
DataObject::singleton()->flushCache();
|
||||
|
||||
self::empty_temp_db();
|
||||
static::$tempDB->clearAllData();
|
||||
|
||||
foreach ($this->requireDefaultRecordsFrom as $className) {
|
||||
$instance = singleton($className);
|
||||
@ -292,10 +306,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
// Build DB if we have objects
|
||||
if (static::getExtraDataObjects()) {
|
||||
DataObject::reset();
|
||||
if (!self::using_temp_db()) {
|
||||
self::create_temp_db();
|
||||
}
|
||||
static::resetDBSchema(true);
|
||||
static::resetDBSchema(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -915,159 +926,26 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
// Register state
|
||||
static::$state = SapphireTestState::singleton();
|
||||
// Register temp DB holder
|
||||
static::$tempDB = TempDatabase::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we are currently using a temporary database
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function using_temp_db()
|
||||
{
|
||||
$dbConn = DB::get_conn();
|
||||
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_';
|
||||
return 1 === preg_match(sprintf('/^%stmpdb_[0-9]+_[0-9]+$/i', preg_quote($prefix, '/')), $dbConn->getSelectedDatabase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy all temp databases
|
||||
*/
|
||||
public static function kill_temp_db()
|
||||
{
|
||||
// Delete our temporary database
|
||||
if (self::using_temp_db()) {
|
||||
$dbConn = DB::get_conn();
|
||||
$dbName = $dbConn->getSelectedDatabase();
|
||||
if ($dbName && DB::get_conn()->databaseExists($dbName)) {
|
||||
// Some DataExtensions keep a static cache of information that needs to
|
||||
// be reset whenever the database is killed
|
||||
foreach (ClassInfo::subclassesFor(DataExtension::class) as $class) {
|
||||
$toCall = array($class, 'on_db_reset');
|
||||
if (is_callable($toCall)) {
|
||||
call_user_func($toCall);
|
||||
}
|
||||
}
|
||||
|
||||
// echo "Deleted temp database " . $dbConn->currentDatabase() . "\n";
|
||||
$dbConn->dropSelectedDatabase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all content from the temporary database.
|
||||
*/
|
||||
public static function empty_temp_db()
|
||||
{
|
||||
if (self::using_temp_db()) {
|
||||
DB::get_conn()->clearAllData();
|
||||
|
||||
// Some DataExtensions keep a static cache of information that needs to
|
||||
// be reset whenever the database is cleaned out
|
||||
$classes = array_merge(ClassInfo::subclassesFor(DataExtension::class), ClassInfo::subclassesFor(DataObject::class));
|
||||
foreach ($classes as $class) {
|
||||
$toCall = array($class, 'on_db_reset');
|
||||
if (is_callable($toCall)) {
|
||||
call_user_func($toCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create temp DB without creating extra objects
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function create_temp_db()
|
||||
{
|
||||
// Disable PHPUnit error handling
|
||||
$oldErrorHandler = set_error_handler(null);
|
||||
|
||||
// Create a temporary database, and force the connection to use UTC for time
|
||||
global $databaseConfig;
|
||||
$databaseConfig['timezone'] = '+0:00';
|
||||
DB::connect($databaseConfig);
|
||||
$dbConn = DB::get_conn();
|
||||
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_';
|
||||
do {
|
||||
$dbname = strtolower(sprintf('%stmpdb_%s_%s', $prefix, time(), rand(1000000, 9999999)));
|
||||
} while ($dbConn->databaseExists($dbname));
|
||||
|
||||
$dbConn->selectDatabase($dbname, true);
|
||||
|
||||
static::resetDBSchema();
|
||||
|
||||
// Reinstate PHPUnit error handling
|
||||
set_error_handler($oldErrorHandler);
|
||||
|
||||
// Ensure test db is killed on exit
|
||||
register_shutdown_function(function () {
|
||||
static::kill_temp_db();
|
||||
});
|
||||
|
||||
return $dbname;
|
||||
}
|
||||
|
||||
public static function delete_all_temp_dbs()
|
||||
{
|
||||
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_';
|
||||
foreach (DB::get_schema()->databaseList() as $dbName) {
|
||||
if (1 === preg_match(sprintf('/^%stmpdb_[0-9]+_[0-9]+$/i', preg_quote($prefix, '/')), $dbName)) {
|
||||
DB::get_schema()->dropDatabase($dbName);
|
||||
if (Director::is_cli()) {
|
||||
echo "Dropped database \"$dbName\"" . PHP_EOL;
|
||||
} else {
|
||||
echo "<li>Dropped database \"$dbName\"</li>" . PHP_EOL;
|
||||
}
|
||||
flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the testing database's schema.
|
||||
* Reset the testing database's schema, but only if it is active
|
||||
* @param bool $includeExtraDataObjects If true, the extraDataObjects tables will also be included
|
||||
* @param bool $forceCreate Force DB to be created if it doesn't exist
|
||||
*/
|
||||
public static function resetDBSchema($includeExtraDataObjects = false)
|
||||
public static function resetDBSchema($includeExtraDataObjects = false, $forceCreate = false)
|
||||
{
|
||||
if (self::using_temp_db()) {
|
||||
DataObject::reset();
|
||||
|
||||
// clear singletons, they're caching old extension info which is used in DatabaseAdmin->doBuild()
|
||||
Injector::inst()->unregisterObjects(DataObject::class);
|
||||
|
||||
$dataClasses = ClassInfo::subclassesFor(DataObject::class);
|
||||
array_shift($dataClasses);
|
||||
|
||||
DB::quiet();
|
||||
$schema = DB::get_schema();
|
||||
$extraDataObjects = $includeExtraDataObjects ? static::getExtraDataObjects() : null;
|
||||
$schema->schemaUpdate(function () use ($dataClasses, $extraDataObjects) {
|
||||
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 ($extraDataObjects) {
|
||||
foreach ($extraDataObjects as $dataClass) {
|
||||
$SNG = singleton($dataClass);
|
||||
if (singleton($dataClass) instanceof DataObject) {
|
||||
$SNG->requireTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ClassInfo::reset_db_cache();
|
||||
DataObject::singleton()->flushCache();
|
||||
// Check if DB is active before reset
|
||||
if (!static::$tempDB->isUsed()) {
|
||||
if (!$forceCreate) {
|
||||
return;
|
||||
}
|
||||
static::$tempDB->build();
|
||||
}
|
||||
$extraDataObjects = $includeExtraDataObjects ? static::getExtraDataObjects() : [];
|
||||
static::$tempDB->resetDBSchema((array)$extraDataObjects);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1163,25 +1041,16 @@ class SapphireTest extends PHPUnit_Framework_TestCase
|
||||
protected function useTestTheme($themeBaseDir, $theme, $callback)
|
||||
{
|
||||
Config::nest();
|
||||
|
||||
if (strpos($themeBaseDir, BASE_PATH) === 0) {
|
||||
$themeBaseDir = substr($themeBaseDir, strlen(BASE_PATH));
|
||||
}
|
||||
SSViewer::config()->update('theme_enabled', true);
|
||||
SSViewer::set_themes([$themeBaseDir.'/themes/'.$theme, '$default']);
|
||||
|
||||
$e = null;
|
||||
|
||||
try {
|
||||
$callback();
|
||||
} catch (Exception $e) {
|
||||
/* NOP for now, just save $e */
|
||||
}
|
||||
|
||||
Config::unnest();
|
||||
|
||||
if ($e) {
|
||||
throw $e;
|
||||
} finally {
|
||||
Config::unnest();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,10 +96,7 @@ class ExtensionTestState implements TestState
|
||||
// reset the schema (if there were extra objects) then force a reset
|
||||
if ($isAltered && empty($class::getExtraDataObjects())) {
|
||||
DataObject::reset();
|
||||
if (!SapphireTest::using_temp_db()) {
|
||||
SapphireTest::create_temp_db();
|
||||
}
|
||||
$class::resetDBSchema(true);
|
||||
$class::resetDBSchema(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
namespace SilverStripe\Dev\Tasks;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Dev\BuildTask;
|
||||
use SilverStripe\ORM\Connect\TempDatabase;
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Security\Security;
|
||||
|
||||
@ -31,6 +31,7 @@ class CleanupTestDatabasesTask extends BuildTask
|
||||
die;
|
||||
}
|
||||
|
||||
SapphireTest::delete_all_temp_dbs();
|
||||
// Delete all temp DBs
|
||||
TempDatabase::create()->deleteAll();
|
||||
}
|
||||
}
|
||||
|
220
src/ORM/Connect/TempDatabase.php
Normal file
220
src/ORM/Connect/TempDatabase.php
Normal file
@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\ORM\Connect;
|
||||
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataExtension;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
|
||||
class TempDatabase
|
||||
{
|
||||
use Injectable;
|
||||
|
||||
/**
|
||||
* Connection name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = null;
|
||||
|
||||
/**
|
||||
* Create a new temp database
|
||||
*
|
||||
* @param string $name DB Connection name to use
|
||||
*/
|
||||
public function __construct($name = 'default')
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given name matches the temp_db pattern
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDBTemp($name)
|
||||
{
|
||||
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_';
|
||||
$result = preg_match(
|
||||
sprintf('/^%stmpdb_[0-9]+_[0-9]+$/i', preg_quote($prefix, '/')),
|
||||
$name
|
||||
);
|
||||
return $result === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Database
|
||||
*/
|
||||
protected function getConn()
|
||||
{
|
||||
return DB::get_conn($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we are currently using a temporary database
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isUsed()
|
||||
{
|
||||
$selected = $this->getConn()->getSelectedDatabase();
|
||||
return $this->isDBTemp($selected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the current temp database
|
||||
*/
|
||||
public function kill()
|
||||
{
|
||||
// Delete our temporary database
|
||||
if (!$this->isUsed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the database actually exists
|
||||
$dbConn = $this->getConn();
|
||||
$dbName = $dbConn->getSelectedDatabase();
|
||||
if (!$dbConn->databaseExists($dbName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Some DataExtensions keep a static cache of information that needs to
|
||||
// be reset whenever the database is killed
|
||||
foreach (ClassInfo::subclassesFor(DataExtension::class) as $class) {
|
||||
$toCall = array($class, 'on_db_reset');
|
||||
if (is_callable($toCall)) {
|
||||
call_user_func($toCall);
|
||||
}
|
||||
}
|
||||
|
||||
// echo "Deleted temp database " . $dbConn->currentDatabase() . "\n";
|
||||
$dbConn->dropSelectedDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all content from the temporary database.
|
||||
*/
|
||||
public function clearAllData()
|
||||
{
|
||||
if (!$this->isUsed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->getConn()->clearAllData();
|
||||
|
||||
// Some DataExtensions keep a static cache of information that needs to
|
||||
// be reset whenever the database is cleaned out
|
||||
$classes = array_merge(
|
||||
ClassInfo::subclassesFor(DataExtension::class),
|
||||
ClassInfo::subclassesFor(DataObject::class)
|
||||
);
|
||||
foreach ($classes as $class) {
|
||||
$toCall = array($class, 'on_db_reset');
|
||||
if (is_callable($toCall)) {
|
||||
call_user_func($toCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create temp DB without creating extra objects
|
||||
*
|
||||
* @return string DB name
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
// Disable PHPUnit error handling
|
||||
$oldErrorHandler = set_error_handler(null);
|
||||
|
||||
// Create a temporary database, and force the connection to use UTC for time
|
||||
$dbConn = $this->getConn();
|
||||
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_';
|
||||
do {
|
||||
$dbname = strtolower(sprintf('%stmpdb_%s_%s', $prefix, time(), rand(1000000, 9999999)));
|
||||
} while ($dbConn->databaseExists($dbname));
|
||||
|
||||
$dbConn->selectDatabase($dbname, true);
|
||||
|
||||
$this->resetDBSchema();
|
||||
|
||||
// Reinstate PHPUnit error handling
|
||||
set_error_handler($oldErrorHandler);
|
||||
|
||||
// Ensure test db is killed on exit
|
||||
register_shutdown_function(function () {
|
||||
$this->kill();
|
||||
});
|
||||
|
||||
return $dbname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all temp DBs on this connection
|
||||
*
|
||||
* Note: This will output results to stdout unless suppressOutput
|
||||
* is set on the current db schema
|
||||
*/
|
||||
public function deleteAll()
|
||||
{
|
||||
$schema = $this->getConn()->getSchemaManager();
|
||||
foreach ($schema->databaseList() as $dbName) {
|
||||
if ($this->isDBTemp($dbName)) {
|
||||
$schema->dropDatabase($dbName);
|
||||
$schema->alterationMessage("Dropped database \"$dbName\"", 'deleted');
|
||||
flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the testing database's schema.
|
||||
*
|
||||
* @param array $extraDataObjects List of extra dataobjects to build
|
||||
*/
|
||||
public function resetDBSchema(array $extraDataObjects = [])
|
||||
{
|
||||
if (!$this->isUsed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataObject::reset();
|
||||
|
||||
// clear singletons, they're caching old extension info which is used in DatabaseAdmin->doBuild()
|
||||
Injector::inst()->unregisterObjects(DataObject::class);
|
||||
|
||||
$dataClasses = ClassInfo::subclassesFor(DataObject::class);
|
||||
array_shift($dataClasses);
|
||||
|
||||
$schema = $this->getConn()->getSchemaManager();
|
||||
$schema->quiet();
|
||||
$schema->schemaUpdate(function () use ($dataClasses, $extraDataObjects) {
|
||||
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 ($extraDataObjects) {
|
||||
foreach ($extraDataObjects as $dataClass) {
|
||||
$SNG = singleton($dataClass);
|
||||
if (singleton($dataClass) instanceof DataObject) {
|
||||
$SNG->requireTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ClassInfo::reset_db_cache();
|
||||
DataObject::singleton()->flushCache();
|
||||
}
|
||||
}
|
@ -2,17 +2,16 @@
|
||||
|
||||
namespace SilverStripe\ORM;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Environment;
|
||||
use SilverStripe\Core\Manifest\ClassLoader;
|
||||
use SilverStripe\Dev\DevelopmentAdmin;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
/**
|
||||
* DatabaseAdmin class
|
||||
|
@ -391,7 +391,11 @@ class Security extends Controller implements TemplateGlobalProvider
|
||||
}
|
||||
|
||||
static::singleton()->setLoginMessage($message, ValidationResult::TYPE_WARNING);
|
||||
$loginResponse = static::singleton()->login($controller ? $controller->getRequest() : $controller);
|
||||
$request = new HTTPRequest('GET', '/');
|
||||
if ($controller) {
|
||||
$request->setSession($controller->getRequest()->getSession());
|
||||
}
|
||||
$loginResponse = static::singleton()->login($request);
|
||||
if ($loginResponse instanceof HTTPResponse) {
|
||||
return $loginResponse;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\Control\Tests;
|
||||
use SilverStripe\Control\Cookie_Backend;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPRequestBuilder;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Control\RequestProcessor;
|
||||
@ -523,7 +524,7 @@ class DirectorTest extends SapphireTest
|
||||
'Content-Length' => '10'
|
||||
);
|
||||
|
||||
$this->assertEquals($headers, HTTPRequest::extractRequestHeaders($request));
|
||||
$this->assertEquals($headers, HTTPRequestBuilder::extractRequestHeaders($request));
|
||||
}
|
||||
|
||||
public function testUnmatchedRequestReturns404()
|
||||
|
@ -2,7 +2,10 @@
|
||||
|
||||
namespace SilverStripe\Control\Tests;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTP;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Kernel;
|
||||
@ -129,14 +132,20 @@ class HTTPTest extends FunctionalTest
|
||||
{
|
||||
// Hackery to work around volatile URL formats in test invocation,
|
||||
// and the inability of Director::absoluteBaseURL() to produce consistent URLs.
|
||||
$origURI = $_SERVER['REQUEST_URI'];
|
||||
$_SERVER['REQUEST_URI'] = 'relative/url/';
|
||||
Director::mockRequest(function (HTTPRequest $request) {
|
||||
$controller = new Controller();
|
||||
$controller->setRequest($request);
|
||||
$controller->pushCurrent();
|
||||
try {
|
||||
$this->assertContains(
|
||||
'relative/url/?foo=bar',
|
||||
'relative/url?foo=bar',
|
||||
HTTP::setGetVar('foo', 'bar'),
|
||||
'Omitting a URL falls back to current URL'
|
||||
);
|
||||
$_SERVER['REQUEST_URI'] = $origURI;
|
||||
} finally {
|
||||
$controller->popCurrent();
|
||||
}
|
||||
}, 'relative/url/');
|
||||
|
||||
$this->assertEquals(
|
||||
'relative/url?foo=bar',
|
||||
|
@ -43,6 +43,7 @@ class MemoryLimitTest extends SapphireTest
|
||||
public function testIncreaseMemoryLimitTo()
|
||||
{
|
||||
ini_set('memory_limit', '64M');
|
||||
Environment::setMemoryLimitMax('256M');
|
||||
|
||||
// It can go up
|
||||
Environment::increaseMemoryLimitTo('128M');
|
||||
@ -54,22 +55,20 @@ class MemoryLimitTest extends SapphireTest
|
||||
|
||||
// Test the different kinds of syntaxes
|
||||
Environment::increaseMemoryLimitTo(1024*1024*200);
|
||||
$this->assertEquals(1024*1024*200, ini_get('memory_limit'));
|
||||
$this->assertEquals('200M', ini_get('memory_limit'));
|
||||
|
||||
Environment::increaseMemoryLimitTo('409600K');
|
||||
$this->assertEquals('409600K', ini_get('memory_limit'));
|
||||
Environment::increaseMemoryLimitTo('109600K');
|
||||
$this->assertEquals('200M', ini_get('memory_limit'));
|
||||
|
||||
// Attempting to increase past max size only sets to max
|
||||
Environment::increaseMemoryLimitTo('1G');
|
||||
$this->assertEquals('256M', ini_get('memory_limit'));
|
||||
|
||||
// If memory limit was left at 409600K, that means that the current testbox doesn't have
|
||||
// 1G of memory available. That's okay; let's not report a failure for that.
|
||||
if (ini_get('memory_limit') != '409600K') {
|
||||
$this->assertEquals('1G', ini_get('memory_limit'));
|
||||
// No argument means unlimited (but only if originally allowed)
|
||||
if (is_numeric($this->origMemLimitMax) && $this->origMemLimitMax < 0) {
|
||||
Environment::increaseMemoryLimitTo();
|
||||
$this->assertEquals(-1, ini_get('memory_limit'));
|
||||
}
|
||||
|
||||
// No argument means unlimited
|
||||
Environment::increaseMemoryLimitTo();
|
||||
$this->assertEquals(-1, ini_get('memory_limit'));
|
||||
}
|
||||
|
||||
public function testIncreaseTimeLimitTo()
|
||||
|
@ -21,10 +21,10 @@ class SecurityDefaultAdminTest extends SapphireTest
|
||||
|
||||
// TODO Workaround to force database clearing with no fixture present,
|
||||
// and avoid sideeffects from other tests
|
||||
if (!self::using_temp_db()) {
|
||||
self::create_temp_db();
|
||||
if (!static::$tempDB->isUsed()) {
|
||||
static::$tempDB->build();
|
||||
}
|
||||
self::empty_temp_db();
|
||||
static::$tempDB->clearAllData();
|
||||
|
||||
if (DefaultAdminService::hasDefaultAdmin()) {
|
||||
$this->defaultUsername = DefaultAdminService::getDefaultAdminUsername();
|
||||
|
Loading…
Reference in New Issue
Block a user