diff --git a/lib/SimpleSAML/Configuration.php b/lib/SimpleSAML/Configuration.php index 28737c58e35e49feec943e59bc7c5ee964fe4090..e2a9fdbc1cf29657dba19a436c2a26c361d543f4 100644 --- a/lib/SimpleSAML/Configuration.php +++ b/lib/SimpleSAML/Configuration.php @@ -198,7 +198,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState /** - * Load a configuration file from a configuration set.XM + * Load a configuration file from a configuration set. * * @param string $filename The name of the configuration file. * @param string $configSet The configuration set. Optional, defaults to 'simplesaml'. diff --git a/tests/Utils/ClearStateTestCase.php b/tests/Utils/ClearStateTestCase.php new file mode 100644 index 0000000000000000000000000000000000000000..701dba29f95beb7b5e2d92063c8f071980ed313d --- /dev/null +++ b/tests/Utils/ClearStateTestCase.php @@ -0,0 +1,46 @@ +<?php + +namespace SimpleSAML\Test\Utils; + +include(dirname(__FILE__) . '/StateClearer.php'); + +/** + * A base SSP test case that takes care of removing global state prior to test runs + */ +class ClearStateTestCase extends \PHPUnit_Framework_TestCase +{ + /** + * Used for managing and clearing state + * @var StateClearer + */ + protected static $stateClearer; + + public static function setUpBeforeClass() + { + if (!self::$stateClearer) { + self::$stateClearer = new StateClearer(); + self::$stateClearer->backupGlobals(); + } + } + + + protected function setUp() + { + self::clearState(); + } + + public static function tearDownAfterClass() + { + self::clearState(); + } + + + /** + * Clear any SSP global state to reduce spill over between tests. + */ + public static function clearState() + { + self::$stateClearer->clearGlobals(); + self::$stateClearer->clearSSPState(); + } +} diff --git a/tests/Utils/ClearStateTestListener.php b/tests/Utils/ClearStateTestListener.php deleted file mode 100644 index 7a92fac854cac816e3fac5e70f9ce00ae2c0bc98..0000000000000000000000000000000000000000 --- a/tests/Utils/ClearStateTestListener.php +++ /dev/null @@ -1,78 +0,0 @@ -<?php -namespace SimpleSAML\Test\Utils; - -use PHPUnit_Framework_Test; -use PHPUnit_Framework_TestSuite; - -/** - * A PHPUnit test listener that attempts to clear global state and cached SSP configuration between test run - */ -class ClearStateTestListener extends \PHPUnit_Framework_BaseTestListener -{ - - /** - * Global state to restore between test runs - * @var array - */ - private static $backups = array(); - - /** - * Class that implement \SimpleSAML\Utils\ClearableState and should have clearInternalState called between tests - * @var array - */ - private static $clearableState = array('SimpleSAML_Configuration'); - - /** - * Variables - * @var array - */ - private static $vars_to_unset = array('SIMPLESAMLPHP_CONFIG_DIR'); - - public function __construct() - { - // Backup any state that is needed as part of processing, so we can restore it later. - // TODO: phpunit's backupGlobals = false, yet we are trying to do a similar thing here. Is that an issue? - if (!self::$backups) { - self::$backups['$_COOKIE'] = $_COOKIE; - self::$backups['$_ENV'] = $_ENV; - self::$backups['$_FILES'] = $_FILES; - self::$backups['$_GET'] = $_GET; - self::$backups['$_POST'] = $_POST; - self::$backups['$_SERVER'] = $_SERVER; - self::$backups['$_SESSION'] = isset($_SESSION) ? $_SESSION : array(); - self::$backups['$_REQUEST'] = $_REQUEST; - } - } - - /** - * Clear any state needed prior to a test file running - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - // TODO: decide how to handle tests that want to set suite level settings with setUpBeforeClass() - } - - /** - * Clear any state needed prior to a test case - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test) - { - $_COOKIE = self::$backups['$_COOKIE']; - $_ENV = self::$backups['$_ENV']; - $_FILES = self::$backups['$_FILES']; - $_GET = self::$backups['$_GET']; - $_POST = self::$backups['$_POST']; - $_SERVER = self::$backups['$_SERVER']; - $_SESSION = self::$backups['$_SESSION']; - $_REQUEST = self::$backups['$_REQUEST']; - - foreach (self::$clearableState as $var) { - $var::clearInternalState(); - } - - foreach (self::$vars_to_unset as $var) { - putenv($var); - } - } -} diff --git a/tests/Utils/ReduceSpillOverTest.php b/tests/Utils/ReduceSpillOverTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3c1022209bb38225ad37e6042e82001b2d274839 --- /dev/null +++ b/tests/Utils/ReduceSpillOverTest.php @@ -0,0 +1,38 @@ +<?php + +namespace SimpleSAML\Test\Utils; + +/** + * Test that ensures state doesn't spill over between tests + * @package SimpleSAML\Test\Utils + */ +class ReduceSpillOverTest extends ClearStateTestCase +{ + + /** + * Set some global state + */ + public function testSetState() + { + $_SERVER['QUERY_STRING'] = 'a=b'; + \SimpleSAML_Configuration::loadFromArray(array('a' => 'b'), '[ARRAY]', 'simplesaml'); + $this->assertEquals('b', \SimpleSAML_Configuration::getInstance()->getString('a')); + putenv('SIMPLESAMLPHP_CONFIG_DIR=' . __DIR__); + } + + /** + * Confirm global state removed prior to next test + */ + public function testStateRemoved() + { + + $this->assertArrayNotHasKey('QUERY_STRING', $_SERVER); + $this->assertFalse(getenv('SIMPLESAMLPHP_CONFIG_DIR')); + try { + \SimpleSAML_Configuration::getInstance(); + $this->fail('Expected config configured in other tests to no longer be valid'); + } catch (\SimpleSAML\Error\ConfigurationError $error) { + // Expected error + } + } +} diff --git a/tests/Utils/StateClearer.php b/tests/Utils/StateClearer.php new file mode 100644 index 0000000000000000000000000000000000000000..7d074d5b1a861a0b1e149a6fa1cf5ee94183352e --- /dev/null +++ b/tests/Utils/StateClearer.php @@ -0,0 +1,76 @@ +<?php +namespace SimpleSAML\Test\Utils; + +/** + * A helper class to aid in clearing global state that is set during SSP tests + */ +class StateClearer +{ + + /** + * Global state to restore between test runs + * @var array + */ + private $backups = array(); + + /** + * Class that implement \SimpleSAML\Utils\ClearableState and should have clearInternalState called between tests + * @var array + */ + private $clearableState = array('SimpleSAML_Configuration'); + + /** + * Environmental variables to unset + * @var array + */ + private $vars_to_unset = array('SIMPLESAMLPHP_CONFIG_DIR'); + + public function backupGlobals() + { + // Backup any state that is needed as part of processing, so we can restore it later. + // TODO: phpunit's backupGlobals = false, yet we are trying to do a similar thing here. Is that an issue? + $this->backups['$_COOKIE'] = $_COOKIE; + $this->backups['$_ENV'] = $_ENV; + $this->backups['$_FILES'] = $_FILES; + $this->backups['$_GET'] = $_GET; + $this->backups['$_POST'] = $_POST; + $this->backups['$_SERVER'] = $_SERVER; + $this->backups['$_SESSION'] = isset($_SESSION) ? $_SESSION : array(); + $this->backups['$_REQUEST'] = $_REQUEST; + } + + + /** + * Clear any global state. + */ + public function clearGlobals() + { + if (!empty($this->backups)) { + $_COOKIE = $this->backups['$_COOKIE']; + $_ENV = $this->backups['$_ENV']; + $_FILES = $this->backups['$_FILES']; + $_GET = $this->backups['$_GET']; + $_POST = $this->backups['$_POST']; + $_SERVER = $this->backups['$_SERVER']; + $_SESSION = $this->backups['$_SESSION']; + $_REQUEST = $this->backups['$_REQUEST']; + } else { + //TODO: what should this behavior be? + } + } + + /** + * Clear any SSP specific state, such as SSP enviormental variables or cached internals. + */ + public function clearSSPState() + { + + foreach ($this->clearableState as $var) { + $var::clearInternalState(); + } + + foreach ($this->vars_to_unset as $var) { + putenv($var); + } + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000000000000000000000000000000000000..4ec9274b9b08c126d52bc3286c5b9c877eed2a4e --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,7 @@ +<?php + +$projectRoot = dirname(__DIR__); +require_once($projectRoot . '/vendor/autoload.php'); + +// Current SSP autoloader can't resolve classes from the tests folder. +include($projectRoot . '/tests/Utils/ClearStateTestCase.php'); diff --git a/tools/phpunit/phpunit.xml b/tools/phpunit/phpunit.xml index 4d455eb109e4b9f0a281d085f3ef739fbb84c16b..b82bc2077bff517bf5f5c806da56498b6bf68133 100644 --- a/tools/phpunit/phpunit.xml +++ b/tools/phpunit/phpunit.xml @@ -8,7 +8,7 @@ processIsolation="false" stopOnFailure="false" syntaxCheck="false" - bootstrap="./../../vendor/autoload.php"> + bootstrap="./../../tests/bootstrap.php"> <testsuites> <testsuite name="Unit tests"> <directory>./../../tests/</directory> @@ -31,8 +31,4 @@ <log type="coverage-html" target="build/coverage" title="PHP Coveralls" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/> <log type="coverage-clover" target="build/logs/clover.xml"/> </logging> - <listeners> - <listener class="\SimpleSAML\Test\Utils\ClearStateTestListener" file="./tests/Utils/ClearStateTestListener.php"> - </listener> - </listeners> </phpunit>