Skip to content

Commit 13196f2

Browse files
committed
Merge remote-tracking branch 'origin/MC-28948' into 2.3.4-develop-pr87
2 parents 32d24c8 + 25868f6 commit 13196f2

File tree

3 files changed

+124
-104
lines changed

3 files changed

+124
-104
lines changed

dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandlerTest.php

Lines changed: 66 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@
99
use Magento\Framework\Exception\SessionException;
1010
use Magento\Framework\Phrase;
1111
use Magento\Framework\Session\Config\ConfigInterface;
12-
use Magento\Framework\App\ObjectManager;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
use Magento\TestFramework\ObjectManager;
1314

15+
/**
16+
* Tests \Magento\Framework\Session\SaveHandler functionality.
17+
*
18+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
19+
*/
1420
class SaveHandlerTest extends \PHPUnit\Framework\TestCase
1521
{
1622
/**
17-
* @var \Magento\TestFramework\ObjectManager
23+
* @var ObjectManager
1824
*/
1925
private $objectManager;
2026

@@ -28,115 +34,96 @@ class SaveHandlerTest extends \PHPUnit\Framework\TestCase
2834
*/
2935
private $saveHandlerFactoryMock;
3036

37+
/**
38+
* @inheritdoc
39+
*/
3140
protected function setUp()
3241
{
33-
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
42+
$this->objectManager = Bootstrap::getObjectManager();
3443
$this->deploymentConfigMock = $this->createMock(DeploymentConfig::class);
3544
$this->objectManager->addSharedInstance($this->deploymentConfigMock, DeploymentConfig::class);
3645
$this->saveHandlerFactoryMock = $this->createMock(SaveHandlerFactory::class);
3746
$this->objectManager->addSharedInstance($this->saveHandlerFactoryMock, SaveHandlerFactory::class);
3847
}
3948

49+
/**
50+
* @inheritdoc
51+
*/
4052
protected function tearDown()
4153
{
4254
$this->objectManager->removeSharedInstance(DeploymentConfig::class);
4355
$this->objectManager->removeSharedInstance(SaveHandlerFactory::class);
4456
}
4557

4658
/**
47-
* Tests that the session handler is correctly set when object is created.
48-
*
49-
* @dataProvider saveHandlerProvider
50-
* @param string $deploymentConfigHandler
59+
* @return void
5160
*/
52-
public function testConstructor($deploymentConfigHandler)
61+
public function testRedisSaveHandler(): void
5362
{
54-
$expected = $this->getExpectedSaveHandler($deploymentConfigHandler, ini_get('session.save_handler'));
55-
5663
$this->deploymentConfigMock->method('get')
57-
->willReturnCallback(function ($configPath) use ($deploymentConfigHandler) {
58-
switch ($configPath) {
59-
case Config::PARAM_SESSION_SAVE_METHOD:
60-
return $deploymentConfigHandler;
61-
case Config::PARAM_SESSION_CACHE_LIMITER:
62-
return 'private_no_expire';
63-
case Config::PARAM_SESSION_SAVE_PATH:
64-
return 'explicit_save_path';
65-
default:
66-
return null;
67-
}
68-
});
64+
->willReturnMap(
65+
[
66+
[Config::PARAM_SESSION_SAVE_METHOD, null, 'redis'],
67+
[Config::PARAM_SESSION_SAVE_PATH, null, 'explicit_save_path'],
68+
]
69+
);
6970

70-
$this->saveHandlerFactoryMock->expects($this->once())
71-
->method('create')
72-
->with($expected);
73-
$sessionConfig = $this->objectManager->create(ConfigInterface::class);
74-
$this->objectManager->create(SaveHandler::class, ['sessionConfig' => $sessionConfig]);
71+
$redisHandlerMock = $this->getMockBuilder(SaveHandler\Redis::class)
72+
->disableOriginalConstructor()
73+
->getMock();
74+
$redisHandlerMock->method('open')
75+
->with('explicit_save_path', 'test_session_id')
76+
->willReturn(true);
7577

76-
// Test expectation
77-
$this->assertEquals(
78-
$expected,
79-
$sessionConfig->getOption('session.save_handler')
80-
);
81-
}
78+
$this->saveHandlerFactoryMock->expects($this->exactly(1))
79+
->method('create')
80+
->with('redis')
81+
->willReturn($redisHandlerMock);
8282

83-
public function saveHandlerProvider()
84-
{
85-
return [
86-
['db'],
87-
['redis'],
88-
['files'],
89-
[false],
90-
];
83+
$sessionConfig = $this->objectManager->create(ConfigInterface::class);
84+
/** @var SaveHandler $saveHandler */
85+
$saveHandler = $this->objectManager->create(SaveHandler::class, ['sessionConfig' => $sessionConfig]);
86+
$result = $saveHandler->open('explicit_save_path', 'test_session_id');
87+
$this->assertTrue($result);
9188
}
9289

9390
/**
94-
* Retrieve expected session.save_handler
95-
*
96-
* @param string $deploymentConfigHandler
97-
* @param string $iniHandler
98-
* @return string
91+
* @return void
9992
*/
100-
private function getExpectedSaveHandler($deploymentConfigHandler, $iniHandler)
101-
{
102-
if ($deploymentConfigHandler) {
103-
return $deploymentConfigHandler;
104-
} elseif ($iniHandler) {
105-
return $iniHandler;
106-
} else {
107-
return SaveHandlerInterface::DEFAULT_HANDLER;
108-
}
109-
}
110-
111-
public function testConstructorWithException()
93+
public function testRedisSaveHandlerFallbackToDefaultOnSessionException(): void
11294
{
11395
$this->deploymentConfigMock->method('get')
114-
->willReturnCallback(function ($configPath) {
115-
switch ($configPath) {
116-
case Config::PARAM_SESSION_SAVE_METHOD:
117-
return 'db';
118-
case Config::PARAM_SESSION_CACHE_LIMITER:
119-
return 'private_no_expire';
120-
case Config::PARAM_SESSION_SAVE_PATH:
121-
return 'explicit_save_path';
122-
default:
123-
return null;
124-
}
125-
});
96+
->willReturnMap(
97+
[
98+
[Config::PARAM_SESSION_SAVE_METHOD, null, 'redis'],
99+
[Config::PARAM_SESSION_SAVE_PATH, null, 'explicit_save_path'],
100+
]
101+
);
102+
103+
$redisHandlerMock = $this->getMockBuilder(SaveHandler\Redis::class)
104+
->disableOriginalConstructor()
105+
->getMock();
106+
$redisHandlerMock->method('open')
107+
->with('explicit_save_path', 'test_session_id')
108+
->willThrowException(new SessionException(new Phrase('Session Exception')));
109+
110+
$defaultHandlerMock = $this->getMockBuilder(SaveHandler\Native::class)
111+
->disableOriginalConstructor()
112+
->getMock();
113+
$defaultHandlerMock->expects($this->once())->method('open')->with('explicit_save_path', 'test_session_id');
126114

127115
$this->saveHandlerFactoryMock->expects($this->at(0))
128116
->method('create')
129-
->willThrowException(new SessionException(new Phrase('Session Exception')));
117+
->with('redis')
118+
->willReturn($redisHandlerMock);
130119
$this->saveHandlerFactoryMock->expects($this->at(1))
131120
->method('create')
132-
->with(SaveHandlerInterface::DEFAULT_HANDLER);
133-
$sessionConfig = $this->objectManager->create(ConfigInterface::class);
134-
$this->objectManager->create(SaveHandler::class, ['sessionConfig' => $sessionConfig]);
121+
->with(SaveHandlerInterface::DEFAULT_HANDLER)
122+
->willReturn($defaultHandlerMock);
135123

136-
// Test expectation
137-
$this->assertEquals(
138-
'db',
139-
$sessionConfig->getOption('session.save_handler')
140-
);
124+
$sessionConfig = $this->objectManager->create(ConfigInterface::class);
125+
/** @var SaveHandler $saveHandler */
126+
$saveHandler = $this->objectManager->create(SaveHandler::class, ['sessionConfig' => $sessionConfig]);
127+
$saveHandler->open('explicit_save_path', 'test_session_id');
141128
}
142129
}

lib/internal/Magento/Framework/Session/SaveHandler.php

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
namespace Magento\Framework\Session;
77

88
use Magento\Framework\Session\Config\ConfigInterface;
9-
use \Magento\Framework\Exception\SessionException;
9+
use Magento\Framework\Exception\SessionException;
1010

1111
/**
1212
* Magento session save handler
@@ -21,8 +21,26 @@ class SaveHandler implements SaveHandlerInterface
2121
protected $saveHandlerAdapter;
2222

2323
/**
24-
* Constructor
25-
*
24+
* @var SaveHandlerFactory
25+
*/
26+
private $saveHandlerFactory;
27+
28+
/**
29+
* @var ConfigInterface
30+
*/
31+
private $sessionConfig;
32+
33+
/**
34+
* @var string
35+
*/
36+
private $defaultHandler;
37+
38+
/**
39+
* @var string
40+
*/
41+
private $saveHandler;
42+
43+
/**
2644
* @param SaveHandlerFactory $saveHandlerFactory
2745
* @param ConfigInterface $sessionConfig
2846
* @param string $default
@@ -32,19 +50,10 @@ public function __construct(
3250
ConfigInterface $sessionConfig,
3351
$default = self::DEFAULT_HANDLER
3452
) {
35-
/**
36-
* Session handler
37-
*
38-
* Save handler may be set to custom value in deployment config, which will override everything else.
39-
* Otherwise, try to read PHP settings for session.save_handler value. Otherwise, use 'files' as default.
40-
*/
41-
$saveMethod = $sessionConfig->getOption('session.save_handler') ?: $default;
42-
43-
try {
44-
$this->saveHandlerAdapter = $saveHandlerFactory->create($saveMethod);
45-
} catch (SessionException $e) {
46-
$this->saveHandlerAdapter = $saveHandlerFactory->create($default);
47-
}
53+
$this->saveHandlerFactory = $saveHandlerFactory;
54+
$this->sessionConfig = $sessionConfig;
55+
$this->defaultHandler = $default;
56+
$this->saveHandler = $this->sessionConfig->getOption('session.save_handler') ?: $this->defaultHandler;
4857
}
4958

5059
/**
@@ -56,7 +65,7 @@ public function __construct(
5665
*/
5766
public function open($savePath, $name)
5867
{
59-
return $this->saveHandlerAdapter->open($savePath, $name);
68+
return $this->callSafely('open', $savePath, $name);
6069
}
6170

6271
/**
@@ -66,7 +75,7 @@ public function open($savePath, $name)
6675
*/
6776
public function close()
6877
{
69-
return $this->saveHandlerAdapter->close();
78+
return $this->callSafely('close');
7079
}
7180

7281
/**
@@ -77,7 +86,7 @@ public function close()
7786
*/
7887
public function read($sessionId)
7988
{
80-
return $this->saveHandlerAdapter->read($sessionId);
89+
return $this->callSafely('read', $sessionId);
8190
}
8291

8392
/**
@@ -89,7 +98,7 @@ public function read($sessionId)
8998
*/
9099
public function write($sessionId, $data)
91100
{
92-
return $this->saveHandlerAdapter->write($sessionId, $data);
101+
return $this->callSafely('write', $sessionId, $data);
93102
}
94103

95104
/**
@@ -100,19 +109,41 @@ public function write($sessionId, $data)
100109
*/
101110
public function destroy($sessionId)
102111
{
103-
return $this->saveHandlerAdapter->destroy($sessionId);
112+
return $this->callSafely('destroy', $sessionId);
104113
}
105114

106115
/**
107-
* Garbage Collection - remove old session data older
108-
* than $maxLifetime (in seconds)
116+
* Garbage Collection - remove old session data older than $maxLifetime (in seconds)
109117
*
110118
* @param int $maxLifetime
111119
* @return bool
112120
* @SuppressWarnings(PHPMD.ShortMethodName)
113121
*/
114122
public function gc($maxLifetime)
115123
{
116-
return $this->saveHandlerAdapter->gc($maxLifetime);
124+
return $this->callSafely('gc', $maxLifetime);
125+
}
126+
127+
/**
128+
* Call save handler adapter method.
129+
*
130+
* In case custom handler failed, default files handler is used.
131+
*
132+
* @param string $method
133+
* @param mixed $arguments
134+
*
135+
* @return mixed
136+
*/
137+
private function callSafely(string $method, ...$arguments)
138+
{
139+
try {
140+
if ($this->saveHandlerAdapter === null) {
141+
$this->saveHandlerAdapter = $this->saveHandlerFactory->create($this->saveHandler);
142+
}
143+
return $this->saveHandlerAdapter->{$method}(...$arguments);
144+
} catch (SessionException $exception) {
145+
$this->saveHandlerAdapter = $this->saveHandlerFactory->create($this->defaultHandler);
146+
return $this->saveHandlerAdapter->{$method}(...$arguments);
147+
}
117148
}
118149
}

lib/internal/Magento/Framework/Session/SaveHandler/Redis.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
use Magento\Framework\Filesystem;
1515
use Magento\Framework\App\Filesystem\DirectoryList;
1616

17+
/**
18+
* Redis session save handler
19+
*/
1720
class Redis implements \SessionHandlerInterface
1821
{
1922
/**
@@ -40,7 +43,6 @@ class Redis implements \SessionHandlerInterface
4043
* @param ConfigInterface $config
4144
* @param LoggerInterface $logger
4245
* @param Filesystem $filesystem
43-
* @throws SessionException
4446
*/
4547
public function __construct(ConfigInterface $config, LoggerInterface $logger, Filesystem $filesystem)
4648
{

0 commit comments

Comments
 (0)