‪TYPO3CMS  11.5
RedisSessionBackendTest.php
Go to the documentation of this file.
1 <?php
2 
3 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 
19 
24 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
25 
29 class ‪RedisSessionBackendTest extends FunctionalTestCase
30 {
34  protected ‪$initializeDatabase = false;
35 
39  protected ‪$subject;
40 
44  protected ‪$redis;
45 
49  protected ‪$testSessionRecord = [
50  // RedisSessionBackend::hash('randomSessionId') with encryption key 12345
51  'ses_id' => '21c0e911565a67315cdc384889c470fd291feafbfa62e31ecf7409430640bc7a',
52  'ses_userid' => 1,
53  // serialize(['foo' => 'bar', 'boo' => 'far'])
54  'ses_data' => 'a:2:{s:3:"foo";s:3:"bar";s:3:"boo";s:3:"far";}',
55  ];
56 
60  protected function ‪setUp(): void
61  {
62  parent::setUp();
63  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = '12345';
64 
65  if (!getenv('typo3TestingRedisHost')) {
66  self::markTestSkipped('environment variable "typo3TestingRedisHost" must be set to run this test');
67  }
68  // Note we assume that if that typo3TestingRedisHost env is set, we can use that for testing,
69  // there is no test to see if the daemon is actually up and running. Tests will fail if env
70  // is set but daemon is down.
71 
72  // We know this env is set, otherwise setUp() would skip the tests
73  $redisHost = getenv('typo3TestingRedisHost');
74  // If typo3TestingRedisPort env is set, use it, otherwise fall back to standard port
75  $env = getenv('typo3TestingRedisPort');
76  $redisPort = is_string($env) ? (int)$env : 6379;
77 
78  $this->redis = new \Redis();
79  $this->redis->connect($redisHost, $redisPort);
80  $this->redis->select(0);
81  // Clear db to ensure no sessions exist currently
82  $this->redis->flushDB();
83 
84  $this->subject = new ‪RedisSessionBackend();
85  $this->subject->initialize(
86  'default',
87  [
88  'database' => 0,
89  'port' => $redisPort,
90  'hostname' => $redisHost,
91  ]
92  );
93  }
94 
98  public function ‪cannotUpdateNonExistingRecord(): void
99  {
100  $this->expectException(SessionNotUpdatedException::class);
101  $this->expectExceptionCode(1484389971);
102  $this->subject->update('iSoNotExist', []);
103  }
104 
108  public function ‪canValidateSessionBackend(): void
109  {
110  $this->subject->validateConfiguration();
111  }
112 
117  public function ‪sessionDataIsStoredProperly(): void
118  {
119  $record = $this->subject->set('randomSessionId', $this->testSessionRecord);
120 
121  $expected = array_merge($this->testSessionRecord, ['ses_tstamp' => ‪$GLOBALS['EXEC_TIME']]);
122 
123  self::assertEquals($record, $expected);
124  $result = $this->subject->get('randomSessionId');
125  self::assertSame($expected, $result);
126  }
127 
131  public function ‪anonymousSessionDataIsStoredProperly(): void
132  {
133  $record = $this->subject->set('randomSessionId', array_merge($this->testSessionRecord, ['ses_userid' => 0]));
134 
135  $expected = array_merge($this->testSessionRecord, ['ses_userid' => 0, 'ses_tstamp' => ‪$GLOBALS['EXEC_TIME']]);
136 
137  self::assertEquals($record, $expected);
138  self::assertSame($expected, $this->subject->get('randomSessionId'));
139  }
140 
145  public function ‪throwExceptionOnNonExistingSessionId(): void
146  {
147  $this->expectException(SessionNotFoundException::class);
148  $this->expectExceptionCode(1481885583);
149  $this->subject->get('IDoNotExist');
150  }
151 
156  public function ‪mergeSessionDataWithNewData(): void
157  {
158  $this->subject->set('randomSessionId', $this->testSessionRecord);
159 
160  $updateData = [
161  'ses_data' => serialize(['foo' => 'baz', 'idontwantto' => 'set the world on fire']),
162  'ses_tstamp' => ‪$GLOBALS['EXEC_TIME'],
163  ];
164  $expectedMergedData = array_merge($this->testSessionRecord, $updateData);
165  $this->subject->update('randomSessionId', $updateData);
166  $fetchedRecord = $this->subject->get('randomSessionId');
167  self::assertSame($expectedMergedData, $fetchedRecord);
168  }
169 
174  public function ‪existingSessionMustNotBeOverridden(): void
175  {
176  $this->expectException(SessionNotCreatedException::class);
177  $this->expectExceptionCode(1481895647);
178 
179  $this->subject->set('randomSessionId', $this->testSessionRecord);
180 
181  $newData = array_merge($this->testSessionRecord, ['ses_data' => serialize(['foo' => 'baz', 'idontwantto' => 'set the world on fire'])]);
182  $this->subject->set('randomSessionId', $newData);
183  }
184 
189  public function ‪cannotChangeSessionId(): void
190  {
191  $this->subject->set('randomSessionId', $this->testSessionRecord);
192 
193  $newSessionId = 'newRandomSessionId';
194  $newData = array_merge($this->testSessionRecord, ['ses_id' => $newSessionId]);
195 
196  // old session id has to exist, no exception must be thrown at this point
197  $this->subject->get('randomSessionId');
198 
199  // Change session id
200  $this->subject->update('randomSessionId', $newData);
201 
202  // no session with key newRandomSessionId should exist
203  $this->expectException(SessionNotFoundException::class);
204  $this->expectExceptionCode(1481885583);
205  $this->subject->get('newRandomSessionId');
206  }
207 
212  public function ‪sessionGetsDestroyed(): void
213  {
214  $this->subject->set('randomSessionId', $this->testSessionRecord);
215 
216  // Remove session
217  self::assertTrue($this->subject->remove('randomSessionId'));
218 
219  // Check if session was really removed
220  $this->expectException(SessionNotFoundException::class);
221  $this->expectExceptionCode(1481885583);
222  $this->subject->get('randomSessionId');
223  }
224 
229  public function ‪canLoadAllSessions(): void
230  {
231  $this->subject->set('randomSessionId', $this->testSessionRecord);
232  $this->subject->set('randomSessionId2', $this->testSessionRecord);
233 
234  // Check if session was really removed
235  self::assertCount(2, $this->subject->getAll());
236  }
237 
241  public function ‪canCollectGarbage(): void
242  {
243  ‪$GLOBALS['EXEC_TIME'] = 150;
244  $authenticatedSession = array_merge($this->testSessionRecord, ['ses_id' => 'authenticatedSession']);
245  $anonymousSession = array_merge($this->testSessionRecord, ['ses_id' => 'anonymousSession', 'ses_userid' => 0]);
246 
247  $this->subject->set('authenticatedSession', $authenticatedSession);
248  $this->subject->set('anonymousSession', $anonymousSession);
249 
250  // Assert that we set authenticated session correctly
251  self::assertSame(
252  $authenticatedSession['ses_data'],
253  $this->subject->get('authenticatedSession')['ses_data']
254  );
255  self::assertSame(
256  $authenticatedSession['ses_userid'],
257  $this->subject->get('authenticatedSession')['ses_userid']
258  );
259 
260  // assert that we set anonymous session correctly
261  self::assertSame(
262  $anonymousSession['ses_data'],
263  $this->subject->get('anonymousSession')['ses_data']
264  );
265 
266  // Run the garbage collection
267  ‪$GLOBALS['EXEC_TIME'] = 200;
268  // 150 + 10 < 200 but 150 + 60 >= 200
269  $this->subject->collectGarbage(60, 10);
270 
271  // Authenticated session should still be there
272  self::assertSame(
273  $authenticatedSession['ses_data'],
274  $this->subject->get('authenticatedSession')['ses_data']
275  );
276  self::assertSame(
277  $authenticatedSession['ses_userid'],
278  $this->subject->get('authenticatedSession')['ses_userid']
279  );
280 
281  // Non-authenticated session should be removed
282  $this->expectException(SessionNotFoundException::class);
283  $this->expectExceptionCode(1481885583);
284  $this->subject->get('anonymousSession');
285  }
286 
290  public function ‪canPartiallyUpdateAfterGet(): void
291  {
292  $updatedRecord = array_merge(
293  $this->testSessionRecord,
294  ['ses_tstamp' => ‪$GLOBALS['EXEC_TIME']]
295  );
296  $sessionId = 'randomSessionId';
297  $this->subject->set($sessionId, $this->testSessionRecord);
298  $this->subject->update($sessionId, []);
299  self::assertSame($updatedRecord, $this->subject->get($sessionId));
300  }
301 }
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\$initializeDatabase
‪bool $initializeDatabase
Definition: RedisSessionBackendTest.php:33
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\setUp
‪setUp()
Definition: RedisSessionBackendTest.php:56
‪TYPO3\CMS\Core\Session\Backend\Exception\SessionNotCreatedException
Definition: SessionNotCreatedException.php:23
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\mergeSessionDataWithNewData
‪mergeSessionDataWithNewData()
Definition: RedisSessionBackendTest.php:152
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\canPartiallyUpdateAfterGet
‪canPartiallyUpdateAfterGet()
Definition: RedisSessionBackendTest.php:286
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\anonymousSessionDataIsStoredProperly
‪anonymousSessionDataIsStoredProperly()
Definition: RedisSessionBackendTest.php:127
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\existingSessionMustNotBeOverridden
‪existingSessionMustNotBeOverridden()
Definition: RedisSessionBackendTest.php:170
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\$testSessionRecord
‪array $testSessionRecord
Definition: RedisSessionBackendTest.php:45
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\$subject
‪RedisSessionBackend $subject
Definition: RedisSessionBackendTest.php:37
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\canValidateSessionBackend
‪canValidateSessionBackend()
Definition: RedisSessionBackendTest.php:104
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\sessionDataIsStoredProperly
‪sessionDataIsStoredProperly()
Definition: RedisSessionBackendTest.php:113
‪TYPO3\CMS\Core\Session\Backend\RedisSessionBackend
Definition: RedisSessionBackend.php:33
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\canCollectGarbage
‪canCollectGarbage()
Definition: RedisSessionBackendTest.php:237
‪TYPO3\CMS\Core\Session\Backend\Exception\SessionNotUpdatedException
Definition: SessionNotUpdatedException.php:23
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\canLoadAllSessions
‪canLoadAllSessions()
Definition: RedisSessionBackendTest.php:225
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\cannotChangeSessionId
‪cannotChangeSessionId()
Definition: RedisSessionBackendTest.php:185
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend
Definition: DatabaseSessionBackendTest.php:18
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\$redis
‪Redis $redis
Definition: RedisSessionBackendTest.php:41
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\sessionGetsDestroyed
‪sessionGetsDestroyed()
Definition: RedisSessionBackendTest.php:208
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\cannotUpdateNonExistingRecord
‪cannotUpdateNonExistingRecord()
Definition: RedisSessionBackendTest.php:94
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest\throwExceptionOnNonExistingSessionId
‪throwExceptionOnNonExistingSessionId()
Definition: RedisSessionBackendTest.php:141
‪TYPO3\CMS\Core\Session\Backend\Exception\SessionNotFoundException
Definition: SessionNotFoundException.php:23
‪TYPO3\CMS\Core\Tests\Functional\Session\Backend\RedisSessionBackendTest
Definition: RedisSessionBackendTest.php:30