‪TYPO3CMS  9.5
RedisSessionBackendTest.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
22 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
23 
29 class ‪RedisSessionBackendTest extends FunctionalTestCase
30 {
34  protected ‪$subject;
35 
39  protected ‪$redis;
40 
44  protected ‪$testSessionRecord = [
45  // RedisSessionBackend::hash('randomSessionId') with encryption key 12345
46  'ses_id' => '21c0e911565a67315cdc384889c470fd291feafbfa62e31ecf7409430640bc7a',
47  'ses_userid' => 1,
48  // serialize(['foo' => 'bar', 'boo' => 'far'])
49  'ses_data' => 'a:2:{s:3:"foo";s:3:"bar";s:3:"boo";s:3:"far";}',
50  ];
51 
55  protected function ‪setUp()
56  {
57  parent::setUp();
58  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = '12345';
59 
60  if (!getenv('typo3TestingRedisHost')) {
61  $this->markTestSkipped('environment variable "typo3TestingRedisHost" must be set to run this test');
62  }
63  // Note we assume that if that typo3TestingRedisHost env is set, we can use that for testing,
64  // there is no test to see if the daemon is actually up and running. Tests will fail if env
65  // is set but daemon is down.
66 
67  // We know this env is set, otherwise setUp() would skip the tests
68  $redisHost = getenv('typo3TestingRedisHost');
69  // If typo3TestingRedisPort env is set, use it, otherwise fall back to standard port
70  $env = getenv('typo3TestingRedisPort');
71  $redisPort = is_string($env) ? (int)$env : 6379;
72 
73  $this->redis = new \Redis();
74  $this->redis->connect($redisHost, $redisPort);
75  $this->redis->select(0);
76  // Clear db to ensure no sessions exist currently
77  $this->redis->flushDB();
78 
79  $this->subject = new ‪RedisSessionBackend();
80  $this->subject->initialize(
81  'default',
82  [
83  'database' => 0,
84  'port' => $redisPort,
85  'hostname' => $redisHost
86  ]
87  );
88  }
89 
93  public function ‪cannotUpdateNonExistingRecord()
94  {
95  $this->expectException(SessionNotUpdatedException::class);
96  $this->expectExceptionCode(1484389971);
97  $this->subject->update('iSoNotExist', []);
98  }
99 
103  public function ‪canValidateSessionBackend()
104  {
105  $this->subject->validateConfiguration();
106  }
107 
112  public function ‪sessionDataIsStoredProperly()
113  {
114  $record = $this->subject->set('randomSessionId', $this->testSessionRecord);
115 
116  $expected = array_merge($this->testSessionRecord, ['ses_tstamp' => ‪$GLOBALS['EXEC_TIME']]);
117 
118  $this->assertEquals($record, $expected);
119  $this->assertArraySubset($expected, $this->subject->get('randomSessionId'));
120  }
121 
126  {
127  $record = $this->subject->set('randomSessionId', array_merge($this->testSessionRecord, ['ses_anonymous' => 1]));
128 
129  $expected = array_merge($this->testSessionRecord, ['ses_anonymous' => 1, 'ses_tstamp' => ‪$GLOBALS['EXEC_TIME']]);
130 
131  $this->assertEquals($record, $expected);
132  $this->assertArraySubset($expected, $this->subject->get('randomSessionId'));
133  }
134 
140  {
141  $this->expectException(SessionNotFoundException::class);
142  $this->expectExceptionCode(1481885583);
143  $this->subject->get('IDoNotExist');
144  }
145 
150  public function ‪mergeSessionDataWithNewData()
151  {
152  $this->subject->set('randomSessionId', $this->testSessionRecord);
153 
154  $updateData = [
155  'ses_data' => serialize(['foo' => 'baz', 'idontwantto' => 'set the world on fire']),
156  'ses_tstamp' => ‪$GLOBALS['EXEC_TIME']
157  ];
158  $expectedMergedData = array_merge($this->testSessionRecord, $updateData);
159  $this->subject->update('randomSessionId', $updateData);
160  $fetchedRecord = $this->subject->get('randomSessionId');
161  $this->assertArraySubset($expectedMergedData, $fetchedRecord);
162  }
163 
168  public function ‪nonHashedSessionIdsAreUpdated()
169  {
171  ‪$testSessionRecord['ses_tstamp'] = 1;
172  // simulate old session record by directly inserting it into redis
173  $this->redis->set(
174  'typo3_ses_default_' . sha1(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']) . '_randomSessionId',
175  json_encode(‪$testSessionRecord),
176  ['nx']
177  );
178 
179  $updateData = [
180  'ses_data' => serialize(['foo' => 'baz', 'idontwantto' => 'set the world on fire']),
181  'ses_tstamp' => ‪$GLOBALS['EXEC_TIME']
182  ];
183  $expectedMergedData = array_merge(‪$testSessionRecord, $updateData);
184  $this->subject->update('randomSessionId', $updateData);
185  $fetchedRecord = $this->subject->get('randomSessionId');
186  self::assertSame($expectedMergedData, $fetchedRecord);
187  }
188 
193  public function ‪existingSessionMustNotBeOverridden()
194  {
195  $this->expectException(SessionNotCreatedException::class);
196  $this->expectExceptionCode(1481895647);
197 
198  $this->subject->set('randomSessionId', $this->testSessionRecord);
199 
200  $newData = array_merge($this->testSessionRecord, ['ses_data' => serialize(['foo' => 'baz', 'idontwantto' => 'set the world on fire'])]);
201  $this->subject->set('randomSessionId', $newData);
202  }
203 
208  public function ‪cannotChangeSessionId()
209  {
210  $this->subject->set('randomSessionId', $this->testSessionRecord);
211 
212  $newSessionId = 'newRandomSessionId';
213  $newData = array_merge($this->testSessionRecord, ['ses_id' => $newSessionId]);
214 
215  // old session id has to exist, no exception must be thrown at this point
216  $this->subject->get('randomSessionId');
217 
218  // Change session id
219  $this->subject->update('randomSessionId', $newData);
220 
221  // no session with key newRandomSessionId should exist
222  $this->expectException(SessionNotFoundException::class);
223  $this->expectExceptionCode(1481885583);
224  $this->subject->get('newRandomSessionId');
225  }
226 
231  public function ‪sessionGetsDestroyed()
232  {
233  $this->subject->set('randomSessionId', $this->testSessionRecord);
234 
235  // Remove session
236  $this->assertTrue($this->subject->remove('randomSessionId'));
237 
238  // Check if session was really removed
239  $this->expectException(SessionNotFoundException::class);
240  $this->expectExceptionCode(1481885583);
241  $this->subject->get('randomSessionId');
242  }
243 
248  public function ‪canLoadAllSessions()
249  {
250  $this->subject->set('randomSessionId', $this->testSessionRecord);
251  $this->subject->set('randomSessionId2', $this->testSessionRecord);
252 
253  // Check if session was really removed
254  $this->assertEquals(2, count($this->subject->getAll()));
255  }
256 
260  public function ‪canCollectGarbage()
261  {
262  ‪$GLOBALS['EXEC_TIME'] = 150;
263  $authenticatedSession = array_merge($this->testSessionRecord, ['ses_id' => 'authenticatedSession']);
264  $anonymousSession = array_merge($this->testSessionRecord, ['ses_id' => 'anonymousSession', 'ses_anonymous' => 1]);
265 
266  $this->subject->set('authenticatedSession', $authenticatedSession);
267  $this->subject->set('anonymousSession', $anonymousSession);
268 
269  // Assert that we set authenticated session correctly
270  self::assertSame(
271  $authenticatedSession['ses_data'],
272  $this->subject->get('authenticatedSession')['ses_data']
273  );
274 
275  // assert that we set anonymous session correctly
276  self::assertSame(
277  $anonymousSession['ses_data'],
278  $this->subject->get('anonymousSession')['ses_data']
279  );
280 
281  // Run the garbage collection
282  ‪$GLOBALS['EXEC_TIME'] = 200;
283  // 150 + 10 < 200 but 150 + 60 >= 200
284  $this->subject->collectGarbage(60, 10);
285 
286  // Authenticated session should still be there
287  self::assertSame(
288  $authenticatedSession['ses_data'],
289  $this->subject->get('authenticatedSession')['ses_data']
290  );
291 
292  // Non-authenticated session should be removed
293  $this->expectException(SessionNotFoundException::class);
294  $this->expectExceptionCode(1481885583);
295  $this->subject->get('anonymousSession');
296  }
297 
301  public function ‪canPartiallyUpdateAfterGet()
302  {
303  $updatedRecord = array_merge(
304  $this->testSessionRecord,
305  ['ses_tstamp' => ‪$GLOBALS['EXEC_TIME']]
306  );
307  $sessionId = 'randomSessionId';
308  $this->subject->set($sessionId, $this->testSessionRecord);
309  $this->subject->update($sessionId, []);
310  $this->assertArraySubset($updatedRecord, $this->subject->get($sessionId));
311  }
312 }
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\setUp
‪setUp()
Definition: RedisSessionBackendTest.php:52
‪TYPO3\CMS\Core\Session\Backend\Exception\SessionNotCreatedException
Definition: SessionNotCreatedException.php:22
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\mergeSessionDataWithNewData
‪mergeSessionDataWithNewData()
Definition: RedisSessionBackendTest.php:147
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\canPartiallyUpdateAfterGet
‪canPartiallyUpdateAfterGet()
Definition: RedisSessionBackendTest.php:298
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\anonymousSessionDataIsStoredProperly
‪anonymousSessionDataIsStoredProperly()
Definition: RedisSessionBackendTest.php:122
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\existingSessionMustNotBeOverridden
‪existingSessionMustNotBeOverridden()
Definition: RedisSessionBackendTest.php:190
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\$testSessionRecord
‪array $testSessionRecord
Definition: RedisSessionBackendTest.php:41
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\$subject
‪RedisSessionBackend $subject
Definition: RedisSessionBackendTest.php:33
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\canValidateSessionBackend
‪canValidateSessionBackend()
Definition: RedisSessionBackendTest.php:100
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\sessionDataIsStoredProperly
‪sessionDataIsStoredProperly()
Definition: RedisSessionBackendTest.php:109
‪TYPO3\CMS\Core\Session\Backend\RedisSessionBackend
Definition: RedisSessionBackend.php:31
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\canCollectGarbage
‪canCollectGarbage()
Definition: RedisSessionBackendTest.php:257
‪TYPO3\CMS\Core\Session\Backend\Exception\SessionNotUpdatedException
Definition: SessionNotUpdatedException.php:22
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\nonHashedSessionIdsAreUpdated
‪nonHashedSessionIdsAreUpdated()
Definition: RedisSessionBackendTest.php:165
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\canLoadAllSessions
‪canLoadAllSessions()
Definition: RedisSessionBackendTest.php:245
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\cannotChangeSessionId
‪cannotChangeSessionId()
Definition: RedisSessionBackendTest.php:205
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend
Definition: DatabaseSessionBackendTest.php:3
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\$redis
‪Redis $redis
Definition: RedisSessionBackendTest.php:37
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\sessionGetsDestroyed
‪sessionGetsDestroyed()
Definition: RedisSessionBackendTest.php:228
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\cannotUpdateNonExistingRecord
‪cannotUpdateNonExistingRecord()
Definition: RedisSessionBackendTest.php:90
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\throwExceptionOnNonExistingSessionId
‪throwExceptionOnNonExistingSessionId()
Definition: RedisSessionBackendTest.php:136
‪TYPO3\CMS\Core\Session\Backend\Exception\SessionNotFoundException
Definition: SessionNotFoundException.php:22
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest
Definition: RedisSessionBackendTest.php:30