Open Journal Systems  3.3.0
PdoSessionHandlerTest.php
1 <?php
2 
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
13 
14 use PHPUnit\Framework\TestCase;
16 
21 class PdoSessionHandlerTest extends TestCase
22 {
23  private $dbFile;
24 
25  protected function tearDown()
26  {
27  // make sure the temporary database file is deleted when it has been created (even when a test fails)
28  if ($this->dbFile) {
29  @unlink($this->dbFile);
30  }
31  parent::tearDown();
32  }
33 
34  protected function getPersistentSqliteDsn()
35  {
36  $this->dbFile = tempnam(sys_get_temp_dir(), 'sf2_sqlite_sessions');
37 
38  return 'sqlite:'.$this->dbFile;
39  }
40 
41  protected function getMemorySqlitePdo()
42  {
43  $pdo = new \PDO('sqlite::memory:');
44  $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
45  $storage = new PdoSessionHandler($pdo);
46  $storage->createTable();
47 
48  return $pdo;
49  }
50 
54  public function testWrongPdoErrMode()
55  {
56  $pdo = $this->getMemorySqlitePdo();
57  $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);
58 
59  $storage = new PdoSessionHandler($pdo);
60  }
61 
65  public function testInexistentTable()
66  {
67  $storage = new PdoSessionHandler($this->getMemorySqlitePdo(), array('db_table' => 'inexistent_table'));
68  $storage->open('', 'sid');
69  $storage->read('id');
70  $storage->write('id', 'data');
71  $storage->close();
72  }
73 
77  public function testCreateTableTwice()
78  {
80  $storage->createTable();
81  }
82 
83  public function testWithLazyDsnConnection()
84  {
85  $dsn = $this->getPersistentSqliteDsn();
86 
87  $storage = new PdoSessionHandler($dsn);
88  $storage->createTable();
89  $storage->open('', 'sid');
90  $data = $storage->read('id');
91  $storage->write('id', 'data');
92  $storage->close();
93  $this->assertSame('', $data, 'New session returns empty string data');
94 
95  $storage->open('', 'sid');
96  $data = $storage->read('id');
97  $storage->close();
98  $this->assertSame('data', $data, 'Written value can be read back correctly');
99  }
100 
102  {
103  $dsn = $this->getPersistentSqliteDsn();
104 
105  // Open is called with what ini_set('session.save_path', $dsn) would mean
106  $storage = new PdoSessionHandler(null);
107  $storage->open($dsn, 'sid');
108  $storage->createTable();
109  $data = $storage->read('id');
110  $storage->write('id', 'data');
111  $storage->close();
112  $this->assertSame('', $data, 'New session returns empty string data');
113 
114  $storage->open($dsn, 'sid');
115  $data = $storage->read('id');
116  $storage->close();
117  $this->assertSame('data', $data, 'Written value can be read back correctly');
118  }
119 
121  {
122  $sessionData = 'da'."\0".'ta';
123 
125  $storage->open('', 'sid');
126  $readData = $storage->read('id');
127  $storage->write('id', $sessionData);
128  $storage->close();
129  $this->assertSame('', $readData, 'New session returns empty string data');
130 
131  $storage->open('', 'sid');
132  $readData = $storage->read('id');
133  $storage->close();
134  $this->assertSame($sessionData, $readData, 'Written value can be read back correctly');
135  }
136 
138  {
139  if (defined('HHVM_VERSION')) {
140  $this->markTestSkipped('PHPUnit_MockObject cannot mock the PDOStatement class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289');
141  }
142 
143  $pdo = new MockPdo('pgsql');
144  $pdo->prepareResult = $this->getMockBuilder('PDOStatement')->getMock();
145 
146  $content = 'foobar';
147  $stream = $this->createStream($content);
148 
149  $pdo->prepareResult->expects($this->once())->method('fetchAll')
150  ->will($this->returnValue(array(array($stream, 42, time()))));
151 
152  $storage = new PdoSessionHandler($pdo);
153  $result = $storage->read('foo');
154 
155  $this->assertSame($content, $result);
156  }
157 
159  {
160  if (defined('HHVM_VERSION')) {
161  $this->markTestSkipped('PHPUnit_MockObject cannot mock the PDOStatement class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289');
162  }
163 
164  $pdo = new MockPdo('pgsql');
165  $selectStmt = $this->getMockBuilder('PDOStatement')->getMock();
166  $insertStmt = $this->getMockBuilder('PDOStatement')->getMock();
167 
168  $pdo->prepareResult = function ($statement) use ($selectStmt, $insertStmt) {
169  return 0 === strpos($statement, 'INSERT') ? $insertStmt : $selectStmt;
170  };
171 
172  $content = 'foobar';
173  $stream = $this->createStream($content);
174  $exception = null;
175 
176  $selectStmt->expects($this->atLeast(2))->method('fetchAll')
177  ->will($this->returnCallback(function () use (&$exception, $stream) {
178  return $exception ? array(array($stream, 42, time())) : array();
179  }));
180 
181  $insertStmt->expects($this->once())->method('execute')
182  ->will($this->returnCallback(function () use (&$exception) {
183  throw $exception = new \PDOException('', '23');
184  }));
185 
186  $storage = new PdoSessionHandler($pdo);
187  $result = $storage->read('foo');
188 
189  $this->assertSame($content, $result);
190  }
191 
193  {
195  $storage->open('', 'sid');
196  $storage->write('id', 'data');
197  $storage->write('test', 'data');
198  $storage->write('space ', 'data');
199  $storage->close();
200 
201  $storage->open('', 'sid');
202  $readDataCaseSensitive = $storage->read('ID');
203  $readDataNoCharFolding = $storage->read('tést');
204  $readDataKeepSpace = $storage->read('space ');
205  $readDataExtraSpace = $storage->read('space ');
206  $storage->close();
207 
208  $this->assertSame('', $readDataCaseSensitive, 'Retrieval by ID should be case-sensitive (collation setting)');
209  $this->assertSame('', $readDataNoCharFolding, 'Retrieval by ID should not do character folding (collation setting)');
210  $this->assertSame('data', $readDataKeepSpace, 'Retrieval by ID requires spaces as-is');
211  $this->assertSame('', $readDataExtraSpace, 'Retrieval by ID requires spaces as-is');
212  }
213 
218  {
220  $storage->open('', 'sid');
221  $storage->read('id');
222  $storage->destroy('id');
223  $storage->write('new_id', 'data_of_new_session_id');
224  $storage->close();
225 
226  $storage->open('', 'sid');
227  $data = $storage->read('new_id');
228  $storage->close();
229 
230  $this->assertSame('data_of_new_session_id', $data, 'Data of regenerated session id is available');
231  }
232 
233  public function testWrongUsageStillWorks()
234  {
235  // wrong method sequence that should no happen, but still works
237  $storage->write('id', 'data');
238  $storage->write('other_id', 'other_data');
239  $storage->destroy('inexistent');
240  $storage->open('', 'sid');
241  $data = $storage->read('id');
242  $otherData = $storage->read('other_id');
243  $storage->close();
244 
245  $this->assertSame('data', $data);
246  $this->assertSame('other_data', $otherData);
247  }
248 
249  public function testSessionDestroy()
250  {
251  $pdo = $this->getMemorySqlitePdo();
252  $storage = new PdoSessionHandler($pdo);
253 
254  $storage->open('', 'sid');
255  $storage->read('id');
256  $storage->write('id', 'data');
257  $storage->close();
258  $this->assertEquals(1, $pdo->query('SELECT COUNT(*) FROM sessions')->fetchColumn());
259 
260  $storage->open('', 'sid');
261  $storage->read('id');
262  $storage->destroy('id');
263  $storage->close();
264  $this->assertEquals(0, $pdo->query('SELECT COUNT(*) FROM sessions')->fetchColumn());
265 
266  $storage->open('', 'sid');
267  $data = $storage->read('id');
268  $storage->close();
269  $this->assertSame('', $data, 'Destroyed session returns empty string');
270  }
271 
272  public function testSessionGC()
273  {
274  $previousLifeTime = ini_set('session.gc_maxlifetime', 1000);
275  $pdo = $this->getMemorySqlitePdo();
276  $storage = new PdoSessionHandler($pdo);
277 
278  $storage->open('', 'sid');
279  $storage->read('id');
280  $storage->write('id', 'data');
281  $storage->close();
282 
283  $storage->open('', 'sid');
284  $storage->read('gc_id');
285  ini_set('session.gc_maxlifetime', -1); // test that you can set lifetime of a session after it has been read
286  $storage->write('gc_id', 'data');
287  $storage->close();
288  $this->assertEquals(2, $pdo->query('SELECT COUNT(*) FROM sessions')->fetchColumn(), 'No session pruned because gc not called');
289 
290  $storage->open('', 'sid');
291  $data = $storage->read('gc_id');
292  $storage->gc(-1);
293  $storage->close();
294 
295  ini_set('session.gc_maxlifetime', $previousLifeTime);
296 
297  $this->assertSame('', $data, 'Session already considered garbage, so not returning data even if it is not pruned yet');
298  $this->assertEquals(1, $pdo->query('SELECT COUNT(*) FROM sessions')->fetchColumn(), 'Expired session is pruned');
299  }
300 
301  public function testGetConnection()
302  {
304 
305  $method = new \ReflectionMethod($storage, 'getConnection');
306  $method->setAccessible(true);
307 
308  $this->assertInstanceOf('\PDO', $method->invoke($storage));
309  }
310 
312  {
313  $storage = new PdoSessionHandler('sqlite::memory:');
314 
315  $method = new \ReflectionMethod($storage, 'getConnection');
316  $method->setAccessible(true);
317 
318  $this->assertInstanceOf('\PDO', $method->invoke($storage));
319  }
320 
321  private function createStream($content)
322  {
323  $stream = tmpfile();
324  fwrite($stream, $content);
325  fseek($stream, 0);
326 
327  return $stream;
328  }
329 }
330 
331 class MockPdo extends \PDO
332 {
334  private $driverName;
335  private $errorMode;
336 
337  public function __construct($driverName = null, $errorMode = null)
338  {
339  $this->driverName = $driverName;
340  $this->errorMode = null !== $errorMode ?: \PDO::ERRMODE_EXCEPTION;
341  }
342 
343  public function getAttribute($attribute)
344  {
345  if (\PDO::ATTR_ERRMODE === $attribute) {
346  return $this->errorMode;
347  }
348 
349  if (\PDO::ATTR_DRIVER_NAME === $attribute) {
350  return $this->driverName;
351  }
352 
353  return parent::getAttribute($attribute);
354  }
355 
356  public function prepare($statement, $driverOptions = array())
357  {
358  return is_callable($this->prepareResult)
359  ? call_user_func($this->prepareResult, $statement, $driverOptions)
361  }
362 
363  public function beginTransaction()
364  {
365  }
366 
367  public function rollBack()
368  {
369  }
370 }
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testSessionGC
testSessionGC()
Definition: PdoSessionHandlerTest.php:272
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testInexistentTable
testInexistentTable()
Definition: PdoSessionHandlerTest.php:65
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testWriteDifferentSessionIdThanRead
testWriteDifferentSessionIdThanRead()
Definition: PdoSessionHandlerTest.php:217
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testWrongUsageStillWorks
testWrongUsageStillWorks()
Definition: PdoSessionHandlerTest.php:233
Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
Definition: lib/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php:41
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testReadingRequiresExactlySameId
testReadingRequiresExactlySameId()
Definition: PdoSessionHandlerTest.php:192
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testGetConnectionConnectsIfNeeded
testGetConnectionConnectsIfNeeded()
Definition: PdoSessionHandlerTest.php:311
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testWithLazyDsnConnection
testWithLazyDsnConnection()
Definition: PdoSessionHandlerTest.php:83
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\MockPdo\beginTransaction
beginTransaction()
Definition: PdoSessionHandlerTest.php:363
Symfony\Component\HttpFoundation\Session\Session\$storage
$storage
Definition: lib/vendor/symfony/http-foundation/Session/Session.php:37
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\MockPdo\__construct
__construct($driverName=null, $errorMode=null)
Definition: PdoSessionHandlerTest.php:337
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testReadConvertsStreamToString
testReadConvertsStreamToString()
Definition: PdoSessionHandlerTest.php:137
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest
Definition: PdoSessionHandlerTest.php:21
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\getMemorySqlitePdo
getMemorySqlitePdo()
Definition: PdoSessionHandlerTest.php:41
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testReadWriteReadWithNullByte
testReadWriteReadWithNullByte()
Definition: PdoSessionHandlerTest.php:120
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\MockPdo
Definition: PdoSessionHandlerTest.php:331
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\getPersistentSqliteDsn
getPersistentSqliteDsn()
Definition: PdoSessionHandlerTest.php:34
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testWithLazySavePathConnection
testWithLazySavePathConnection()
Definition: PdoSessionHandlerTest.php:101
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\MockPdo\getAttribute
getAttribute($attribute)
Definition: PdoSessionHandlerTest.php:343
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testReadLockedConvertsStreamToString
testReadLockedConvertsStreamToString()
Definition: PdoSessionHandlerTest.php:158
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testGetConnection
testGetConnection()
Definition: PdoSessionHandlerTest.php:301
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\MockPdo\rollBack
rollBack()
Definition: PdoSessionHandlerTest.php:367
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\tearDown
tearDown()
Definition: PdoSessionHandlerTest.php:25
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testSessionDestroy
testSessionDestroy()
Definition: PdoSessionHandlerTest.php:249
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler
Definition: MemcachedSessionHandlerTest.php:12
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testWrongPdoErrMode
testWrongPdoErrMode()
Definition: PdoSessionHandlerTest.php:54
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\MockPdo\prepare
prepare($statement, $driverOptions=array())
Definition: PdoSessionHandlerTest.php:356
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\MockPdo\$prepareResult
$prepareResult
Definition: PdoSessionHandlerTest.php:333
Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\PdoSessionHandlerTest\testCreateTableTwice
testCreateTableTwice()
Definition: PdoSessionHandlerTest.php:77