From ffbede55f2dd8f50add84f666de6001b6f7e34b9 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 4 Aug 2017 16:52:17 -0400 Subject: [PATCH] Attempt to get the session tests passing in PHP7.2 In PHP7.2 ini_set() cannot modify session configuration once headers have been 'sent'. In the CLI SAPI, headers are 'sent' as soon as STDOUT gets written to. By running most of the session tests in separate processes we can get around most of the limitations. But I had to change a few of the methods to supress errors in every other test. --- src/Network/Session.php | 8 +-- src/Network/Session/DatabaseSession.php | 15 ++++++ .../Network/Session/DatabaseSessionTest.php | 2 +- tests/TestCase/Network/SessionTest.php | 49 ++++++------------- tests/bootstrap.php | 1 + 5 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/Network/Session.php b/src/Network/Session.php index c02e0512da8..b4e672f37b1 100644 --- a/src/Network/Session.php +++ b/src/Network/Session.php @@ -108,7 +108,9 @@ public static function create($sessionConfig = []) $sessionConfig['ini']['session.name'] = $sessionConfig['cookie']; } - if (!empty($sessionConfig['handler'])) { + // In PHP7.1.0+ session.save_handler can't be set to user by the user. + // https://github.com/php/php-src/blob/master/ext/session/session.c#L559 + if (!empty($sessionConfig['handler']) && version_compare(PHP_VERSION, '7.1.0', '<=')) { $sessionConfig['ini']['session.save_handler'] = 'user'; } @@ -283,7 +285,7 @@ public function engine($class = null, array $options = []) */ public function options(array $options) { - if (session_status() === \PHP_SESSION_ACTIVE) { + if (session_status() === \PHP_SESSION_ACTIVE || headers_sent()) { return; } @@ -453,7 +455,7 @@ public function write($name, $value = null) */ public function id($id = null) { - if ($id !== null) { + if ($id !== null && !headers_sent()) { session_id($id); } diff --git a/src/Network/Session/DatabaseSession.php b/src/Network/Session/DatabaseSession.php index f7ca34acc41..b9f3f3dfd40 100644 --- a/src/Network/Session/DatabaseSession.php +++ b/src/Network/Session/DatabaseSession.php @@ -62,6 +62,21 @@ public function __construct(array $config = []) $this->_timeout = ini_get('session.gc_maxlifetime'); } + /** + * Set the timeout value for sessions. + * + * Primarily used in testing. + * + * @param int $timeout The timeout duration. + * @return $this + */ + public function setTimeout($timeout) + { + $this->_timeout = $timeout; + + return $this; + } + /** * Method called on open of a database session. * diff --git a/tests/TestCase/Network/Session/DatabaseSessionTest.php b/tests/TestCase/Network/Session/DatabaseSessionTest.php index 9bd8bf36880..b65c289182e 100644 --- a/tests/TestCase/Network/Session/DatabaseSessionTest.php +++ b/tests/TestCase/Network/Session/DatabaseSessionTest.php @@ -153,8 +153,8 @@ public function testGc() { TableRegistry::clear(); - ini_set('session.gc_maxlifetime', '0'); $storage = new DatabaseSession(); + $storage->setTimeout(0); $storage->write('foo', 'Some value'); sleep(1); diff --git a/tests/TestCase/Network/SessionTest.php b/tests/TestCase/Network/SessionTest.php index 954b5ad2bb7..5b3c600ff27 100644 --- a/tests/TestCase/Network/SessionTest.php +++ b/tests/TestCase/Network/SessionTest.php @@ -77,39 +77,6 @@ class SessionTest extends TestCase */ public $fixtures = ['core.cake_sessions', 'core.sessions']; - /** - * setup before class. - * - * @return void - */ - public static function setupBeforeClass() - { - // Make sure garbage collector will be called - static::$_gcDivisor = ini_get('session.gc_divisor'); - ini_set('session.gc_divisor', '1'); - } - - /** - * teardown after class - * - * @return void - */ - public static function teardownAfterClass() - { - // Revert to the default setting - ini_set('session.gc_divisor', static::$_gcDivisor); - } - - /** - * setUp method - * - * @return void - */ - public function setUp() - { - parent::setUp(); - } - /** * tearDown method * @@ -124,6 +91,7 @@ public function tearDown() /** * test setting ini properties with Session configuration. * + * @runInSeparateProcess * @return void */ public function testSessionConfigIniSetting() @@ -149,6 +117,7 @@ public function testSessionConfigIniSetting() /** * test session cookie path setting * + * @runInSeparateProcess * @return void */ public function testCookiePath() @@ -298,15 +267,16 @@ public function testConsume() /** * testId method * + * @runInSeparateProcess * @return void */ public function testId() { $session = new Session(); + $session->start(); $result = $session->id(); - $expected = session_id(); $this->assertNotEmpty($result); - $this->assertSame($expected, $result); + $this->assertSame(session_id(), $result); $session->id('MySessionId'); $this->assertSame('MySessionId', $session->id()); @@ -489,6 +459,7 @@ public function testReadingSavedEmpty() /** * test using a handler from app/Model/Datasource/Session. * + * @runInSeparateProcess * @return void */ public function testUsingAppLibsHandler() @@ -512,6 +483,7 @@ public function testUsingAppLibsHandler() /** * test using a handler from a plugin. * + * @runInSeparateProcess * @return void */ public function testUsingPluginHandler() @@ -534,6 +506,7 @@ public function testUsingPluginHandler() /** * Tests that it is possible to pass an already made instance as the session engine * + * @runInSeparateProcess * @return void */ public function testEngineWithPreMadeInstance() @@ -564,6 +537,7 @@ public function testBadEngine() /** * Test that cookieTimeout matches timeout when unspecified. * + * @runInSeparateProcess * @return void */ public function testCookieTimeoutFallback() @@ -581,6 +555,7 @@ public function testCookieTimeoutFallback() /** * Tests that the cookie name can be changed with configuration * + * @runInSeparateProcess * @return void */ public function testSessionName() @@ -591,6 +566,8 @@ public function testSessionName() /** * Test that a call of check() starts the session when cookies are disabled in php.ini + * + * @runInSeparateProcess */ public function testCheckStartsSessionWithCookiesDisabled() { @@ -631,6 +608,8 @@ public function testCheckStartsSessionWithCookie() /** * Test that a call of check() starts the session when the session ID is passed via URL and session.use_trans_sid is enabled + * + * @runInSeparateProcess */ public function testCheckStartsSessionWithSIDinURL() { diff --git a/tests/bootstrap.php b/tests/bootstrap.php index bd9d6a0d8f6..e09114846d4 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -131,6 +131,7 @@ MutableDate::setTestNow(MutableDate::now()); ini_set('intl.default_locale', 'en_US'); +ini_set('session.gc_divisor', '1'); if (class_exists('PHPUnit_Runner_Version')) { class_alias('PHPUnit_Framework_TestResult', 'PHPUnit\Framework\TestResult');