From db290a1cf98e48f28d7c4f666ed48bfdd892f3e7 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 19 Dec 2012 14:20:06 +0100 Subject: [PATCH] Initial commit Mostly migrated from 3.0 core, with some documentation adjustments. Removed the unused dev/tests/sessionloadyaml command. --- README.md | 44 +++++++++ _config.php | 16 +++ _config/routes.yml | 6 ++ code/TestSessionController.php | 174 +++++++++++++++++++++++++++++++++ composer.json | 20 ++++ 5 files changed, 260 insertions(+) create mode 100644 README.md create mode 100644 _config.php create mode 100644 _config/routes.yml create mode 100644 code/TestSessionController.php create mode 100644 composer.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..b62a58d --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# Browser Test Session Module + +## Overview + +This module starts a testing session in a browser, +in order to test a SilverStripe application in a clean state. +Usually the session is started on a fresh database with only default records loaded. +Further data can be loaded from YAML fixtures. + +The module also serves as an initializer for the +[SilverStripe Behat Extension](https://github.com/silverstripe-labs/silverstripe-behat-extension/). +It is required for Behat because the Behat CLI test runner needs to persist +test configuration just for the tested browser connection, +available on arbitary URL endpoints. For example, +we're setting up a test mailer which writes every email +into a temporary database table for inspection by the CLI-based process. + +## Setup + +In order to execute the commands, the environment must be in "dev mode", +or you must be logged-in with administrative permissions. + +Since the database name is stored as an encrypted cookie, +you need to create a secure token for the encryption first: + + sake dev/generatesecuretoken + +The resulting configuration code needs to be placed in `mysite/_config.php`. + +## Usage + + * `dev/testsession/start`: A test database will be constructed, and your + browser session will be amended to use this database. + * `dev/testsession/start?fixture=`: Same as above, but also loads a YAML fixture + in the format generally accepted by `SapphireTest` (see [fixture format docs](http://doc.silverstripe.org/framework/en/topics/testing/fixtures)). The path should be relative to the webroot. + * `dev/testsession/end`: Removes the test state, and resets to the original database + * `dev/testsession/setdb?database=`: Set an alternative database name in the current + browser session as a cookie. Does not actually create the database, + that's usually handley by `SapphireTest::create_temp_db()`. + * `dev/testsession/emptydb`: Empties the test state. + +Note: 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. diff --git a/_config.php b/_config.php new file mode 100644 index 0000000..d07c59a --- /dev/null +++ b/_config.php @@ -0,0 +1,16 @@ +mailer = new SilverStripe\BehatExtension\Utility\TestMailer(); + Email::set_mailer($this->mailer); + Email::send_all_emails_to(null); + + // Set mock date and time + $mockDate = Session::get('behat.mockDate'); + if($mockDate) { + SS_Datetime::set_mock_now($mockDate); + } +} \ No newline at end of file diff --git a/_config/routes.yml b/_config/routes.yml new file mode 100644 index 0000000..829ca9d --- /dev/null +++ b/_config/routes.yml @@ -0,0 +1,6 @@ +--- +Name: testsessionroutes +--- +Director: + rules: + 'dev/testsession': 'TestSessionController' \ No newline at end of file diff --git a/code/TestSessionController.php b/code/TestSessionController.php new file mode 100644 index 0000000..83d02d0 --- /dev/null +++ b/code/TestSessionController.php @@ -0,0 +1,174 @@ +You're in the middle of a test session;" + . " click here to end it.

"; + + } else if(!isset($_GET['fixture'])) { + $me = Director::baseURL() . "dev/testsession/start"; + return << +

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(); + + 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?

+ "; + } + + } else { + return "

startession can only be used on dev and test sites

"; + } + } + + /** + * 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(Director::isLive()) { + return $this->httpError(403, "dev/testsession/setdb can only be used on dev and test sites"); + } + 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"); + } + + DB::set_alternative_database_name($name); + + if($name) { + return "

Set database session to '$name'.

"; + } else { + return "

Unset database session.

"; + } + + } + + 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() { + SapphireTest::kill_temp_db(); + DB::set_alternative_database_name(null); + + return "

Test session ended.

+ "; + } + +} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..18b41b1 --- /dev/null +++ b/composer.json @@ -0,0 +1,20 @@ +{ + "name": "silverstripe/testsession", + "type": "silverstripe-module", + "description": "Support module for browser-based test sessions, e.g. for Behat behaviour testing", + "homepage": "http://silverstripe.org", + "license": "BSD-3-Clause", + "keywords": ["silverstripe", "testing"], + "authors": [ + { + "name": "SilverStripe", + "homepage": "http://silverstripe.com" + } + ], + "require": { + "php": ">=5.3.2", + "composer/installers": "*", + "silverstripe/framework": "3.0.*", + "silverstripe/behat-extension": "*" + } +} \ No newline at end of file