Browse Source

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.
Mark Story 8 years ago
parent
commit
ffbede55f2

+ 5 - 3
src/Network/Session.php

@@ -108,7 +108,9 @@ class Session
             $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 @@ class Session
      */
     public function options(array $options)
     {
-        if (session_status() === \PHP_SESSION_ACTIVE) {
+        if (session_status() === \PHP_SESSION_ACTIVE || headers_sent()) {
             return;
         }
 
@@ -453,7 +455,7 @@ class Session
      */
     public function id($id = null)
     {
-        if ($id !== null) {
+        if ($id !== null && !headers_sent()) {
             session_id($id);
         }
 

+ 15 - 0
src/Network/Session/DatabaseSession.php

@@ -63,6 +63,21 @@ class DatabaseSession implements SessionHandlerInterface
     }
 
     /**
+     * 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.
      *
      * @param string $savePath The path where to store/retrieve the session.

+ 1 - 1
tests/TestCase/Network/Session/DatabaseSessionTest.php

@@ -153,8 +153,8 @@ class DatabaseSessionTest extends TestCase
     {
         TableRegistry::clear();
 
-        ini_set('session.gc_maxlifetime', '0');
         $storage = new DatabaseSession();
+        $storage->setTimeout(0);
         $storage->write('foo', 'Some value');
 
         sleep(1);

+ 14 - 35
tests/TestCase/Network/SessionTest.php

@@ -78,39 +78,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
      *
      * @return void
@@ -124,6 +91,7 @@ class SessionTest extends TestCase
     /**
      * test setting ini properties with Session configuration.
      *
+     * @runInSeparateProcess
      * @return void
      */
     public function testSessionConfigIniSetting()
@@ -149,6 +117,7 @@ class SessionTest extends TestCase
     /**
      * test session cookie path setting
      *
+     * @runInSeparateProcess
      * @return void
      */
     public function testCookiePath()
@@ -298,15 +267,16 @@ class SessionTest extends TestCase
     /**
      * 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 @@ class SessionTest extends TestCase
     /**
      * test using a handler from app/Model/Datasource/Session.
      *
+     * @runInSeparateProcess
      * @return void
      */
     public function testUsingAppLibsHandler()
@@ -512,6 +483,7 @@ class SessionTest extends TestCase
     /**
      * test using a handler from a plugin.
      *
+     * @runInSeparateProcess
      * @return void
      */
     public function testUsingPluginHandler()
@@ -534,6 +506,7 @@ class SessionTest extends TestCase
     /**
      * 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 @@ class SessionTest extends TestCase
     /**
      * Test that cookieTimeout matches timeout when unspecified.
      *
+     * @runInSeparateProcess
      * @return void
      */
     public function testCookieTimeoutFallback()
@@ -581,6 +555,7 @@ class SessionTest extends TestCase
     /**
      * Tests that the cookie name can be changed with configuration
      *
+     * @runInSeparateProcess
      * @return void
      */
     public function testSessionName()
@@ -591,6 +566,8 @@ class SessionTest extends TestCase
 
     /**
      * Test that a call of check() starts the session when cookies are disabled in php.ini
+     *
+     * @runInSeparateProcess
      */
     public function testCheckStartsSessionWithCookiesDisabled()
     {
@@ -631,6 +608,8 @@ class SessionTest extends TestCase
 
     /**
      * 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()
     {

+ 1 - 0
tests/bootstrap.php

@@ -131,6 +131,7 @@ Date::setTestNow(Date::now());
 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');