From a2d7675e57a1fe00bf1fc38783c89a756c8d283e Mon Sep 17 00:00:00 2001
From: Ingo Schommer
Enter a fixture file name to start a new test session. Don't forget to visit dev/testsession/end when -you're done!
-Fixture file (leave blank to start with default set-up):
- - - -HTML; - } else { - $fixtureFile = $_GET['fixture']; - - if($fixtureFile) { - // Validate fixture file - $realFile = realpath(BASE_PATH.'/'.$fixtureFile); - $baseDir = realpath(Director::baseFolder()); - if(!$realFile || !file_exists($realFile)) { - return "Fixture file doesn't exist
"; - } else if(substr($realFile,0,strlen($baseDir)) != $baseDir) { - return "Fixture file must be inside $baseDir
"; - } else if(substr($realFile,-4) != '.yml') { - return "Fixture file must be a .yml file
"; - } else if(!preg_match('/^([^\/.][^\/]+)\/tests\//', $fixtureFile)) { - return "Fixture file must be inside the tests subfolder of one of your modules.
"; - } - } - - $dbname = SapphireTest::create_temp_db(); - + // Database + if(!$request->getVar('database')) { + // Create a new one with a randomized name + $dbname = SapphireTest::create_temp_db(); DB::set_alternative_database_name($dbname); - - // Fixture - if($fixtureFile) { - $fixture = Injector::inst()->create('YamlFixture', $fixtureFile); - $fixture->saveIntoDatabase(); - - // If no fixture, then use defaults - } else { - $dataClasses = ClassInfo::subclassesFor('DataObject'); - array_shift($dataClasses); - foreach($dataClasses as $dataClass) singleton($dataClass)->requireDefaultRecords(); - } - - return "Started testing session with fixture '$fixtureFile'. - Time to start testing; where would you like to start?
- "; } + + $this->setState($request->getVars()); + + return $this->renderWith('TestSession_start'); } - /** - * Set an alternative database name in the current browser session as a cookie. - * Useful for functional testing libraries like behat to create a "clean slate". - * Does not actually create the database, that's usually handled - * by {@link SapphireTest::create_temp_db()}. - * - * The database names are limited to a specific naming convention as a security measure: - * The "ss_tmpdb" prefix and a random sequence of seven digits. - * This avoids the user gaining access to other production databases - * available on the same connection. - * - * See {@link start()} for a different approach which actually creates - * the DB and loads a fixture file instead. - * - * Requires PHP's mycrypt extension in order to set the database name - * as an encrypted cookie. - */ - public function setdb() { - if(!isset($_GET['database'])) { - return $this->httpError(400, "dev/testsession/setdb must be used with a 'database' parameter"); - } - - $name = $_GET['database']; - $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_'; - $pattern = strtolower(sprintf('#^%stmpdb\d{7}#', $prefix)); - if($name && !preg_match($pattern, $name)) { - return $this->httpError(400, "Invalid database name format"); + public function set($request) { + if(!SapphireTest::using_temp_db()) { + throw new LogicException( + "This command can only be used with a temporary database. " + . "Perhaps you should use dev/testsession/start first?" + ); } - DB::set_alternative_database_name($name); + $this->setState($request->getVars()); - if($name) { - return "Set database session to '$name'.
"; - } else { - return "Unset database session.
"; + return $this->renderWith('TestSession_inprogress'); + } + + public function clear($request) { + if(!SapphireTest::using_temp_db()) { + throw new LogicException( + "This command can only be used with a temporary database. " + . "Perhaps you should use dev/testsession/start first?" + ); } - + + SapphireTest::empty_temp_db(); + + return "Cleared database and test state"; } - public function emptydb() { - if(SapphireTest::using_temp_db()) { - SapphireTest::empty_temp_db(); - - if(isset($_GET['fixture']) && ($fixtureFile = $_GET['fixture'])) { - $fixture = Injector::inst()->create('YamlFixture', $fixtureFile); - $fixture->saveIntoDatabase(); - return "Re-test the test database with fixture '$fixtureFile'. Time to start testing; where would" - . " you like to start?
"; - - } else { - return "Re-test the test database. Time to start testing; where would you like to start?
"; - } - - } else { - return "dev/testsession/emptydb can only be used with a temporary database. Perhaps you should use" - . " dev/testsession/start first?
"; - } - } - public function end() { + if(!SapphireTest::using_temp_db()) { + throw new LogicException( + "This command can only be used with a temporary database. " + . "Perhaps you should use dev/testsession/start first?" + ); + } + SapphireTest::kill_temp_db(); DB::set_alternative_database_name(null); Session::clear('testsession'); - return "Test session ended.
- "; + return $this->renderWith('TestSession_end'); + } + + protected function loadFixtureIntoDb($fixtureFile) { + $realFile = realpath(BASE_PATH.'/'.$fixtureFile); + $baseDir = realpath(Director::baseFolder()); + if(!$realFile || !file_exists($realFile)) { + throw new LogicException("Fixture file doesn't exist"); + } else if(substr($realFile,0,strlen($baseDir)) != $baseDir) { + throw new LogicException("Fixture file must be inside $baseDir"); + } else if(substr($realFile,-4) != '.yml') { + throw new LogicException("Fixture file must be a .yml file"); + } else if(!preg_match('/^([^\/.][^\/]+)\/tests\//', $fixtureFile)) { + throw new LogicException("Fixture file must be inside the tests subfolder of one of your modules."); + } + + $fixture = Injector::inst()->create('YamlFixture', $fixtureFile); + $fixture->saveIntoDatabase(); + + Session::add_to_array('testsession.fixtures', $fixtureFile); + + return $fixture; + } + + /** + * @return boolean + */ + public function isTesting() { + return SapphireTest::using_temp_db(); + } + + public function setState($data) { + // Database + $dbname = (isset($data['database'])) ? $data['database'] : null; + if($dbname) { + // Set existing one, assumes it already has been created + $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_'; + $pattern = strtolower(sprintf('#^%stmpdb\d{7}#', $prefix)); + if(!preg_match($pattern, $dbname)) { + throw new InvalidArgumentException("Invalid database name format"); + } + DB::set_alternative_database_name($dbname); + } + + // Fixtures + $fixtureFile = (isset($data['fixture'])) ? $data['fixture'] : null; + if($fixtureFile) { + $this->loadFixtureIntoDb($fixtureFile); + } else { + // If no fixture, then use defaults + $dataClasses = ClassInfo::subclassesFor('DataObject'); + array_shift($dataClasses); + foreach($dataClasses as $dataClass) singleton($dataClass)->requireDefaultRecords(); + } + } + + /** + * @return ArrayList + */ + public function getState() { + $state = array(); + if($dbname = DB::get_alternative_database_name()) { + $state[] = new ArrayData(array( + 'Name' => 'Database', + 'Value' => $dbname, + )); + } + if($fixtures = Session::get('testsession.fixtures')) { + $state[] = new ArrayData(array( + 'Name' => 'Fixture', + 'Value' => implode(',', array_unique($fixtures)), + )); + } + + return new ArrayList($state); } } \ No newline at end of file diff --git a/templates/Includes/TestSession_State.ss b/templates/Includes/TestSession_State.ss new file mode 100644 index 0000000..169959d --- /dev/null +++ b/templates/Includes/TestSession_State.ss @@ -0,0 +1,10 @@ +<% if State %> ++ Current testing state +
Test session ended.
++ You're in the middle of a test session. + Click here to end it. +
+<% include TestSession_State %> \ No newline at end of file diff --git a/templates/TestSession_start.ss b/templates/TestSession_start.ss new file mode 100644 index 0000000..f7ffdf2 --- /dev/null +++ b/templates/TestSession_start.ss @@ -0,0 +1,34 @@ ++ Started testing session. + <% if Fixture %>Loaded fixture "$Fixture" into database.<% end_if %> + Time to start testing; where would you like to start? +
+