Skip to content

Commit 4d4c9b3

Browse files
committed
OXDEV-9078 Improve user integration tests
1 parent 5689118 commit 4d4c9b3

1 file changed

Lines changed: 46 additions & 71 deletions

File tree

tests/Integration/Shared/Model/UserTest.php

Lines changed: 46 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,14 @@
1616
use OxidEsales\Eshop\Core\Request;
1717
use OxidEsales\Eshop\Core\Utils;
1818
use OxidEsales\EshopCommunity\Core\Di\ContainerFacade;
19-
use OxidEsales\EshopCommunity\Internal\Framework\Module\Facade\ModuleSettingServiceInterface;
2019
use DateTimeImmutable;
2120
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\OTP\Infrastructure\Repository\OtpChallengeStateRepositoryInterface;
2221
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\AuthorizeService;
23-
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Settings\TwoFASettings;
22+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Settings\TwoFASettingsInterface;
2423
use OxidEsales\SecurityModule\Captcha\Service\ModuleSettingsServiceInterface as CaptchaSettingsServiceInterface;
25-
use OxidEsales\SecurityModule\Core\Module;
24+
use OxidEsales\SecurityModule\Shared\Model\User as SecurityModuleUser;
2625
use OxidEsales\SecurityModule\Tests\Integration\IntegrationTestCase;
2726

28-
// todo-critical: rework the 2FA part of the test. it changes the real configs on the fly and causing side effects
2927
class UserTest extends IntegrationTestCase
3028
{
3129
private const OTP_USER_NAME = 'user@oxid-esales.com';
@@ -47,12 +45,6 @@ public function setUp(): void
4745
Registry::getSession()->setVariable('captcha_expiration', time() + 60);
4846
}
4947

50-
public function tearDown(): void
51-
{
52-
$this->disableTwoFactorAuth();
53-
parent::tearDown();
54-
}
55-
5648
public function testCheckValuesWithInvalidCaptcha()
5749
{
5850
$this->requestMock
@@ -68,7 +60,7 @@ public function testCheckValuesWithInvalidCaptcha()
6860
$message = Registry::getLang()->translateString("ERROR_INVALID_CAPTCHA");
6961
$this->expectExceptionMessage($message);
7062

71-
$subject = oxNew(User::class);
63+
$subject = $this->createUserMock(captchaEnabled: true, twoFaEnabled: false);
7264
$subject->checkValues('', '', '', [], []);
7365
}
7466

@@ -87,42 +79,48 @@ public function testCheckValuesWithEmptyCaptcha()
8779
$message = Registry::getLang()->translateString("ERROR_EMPTY_CAPTCHA");
8880
$this->expectExceptionMessage($message);
8981

90-
$subject = oxNew(User::class);
82+
$subject = $this->createUserMock(captchaEnabled: true, twoFaEnabled: false);
9183
$subject->checkValues('', '', '', [], []);
9284
}
9385

9486
public function testLoginWithInvalidCaptcha()
9587
{
9688
$this->requestMock
9789
->method('getRequestParameter')
98-
->with('captcha')
99-
->willReturn('invalid_captcha');
90+
->willReturnCallback(function ($param) {
91+
if ($param === 'captcha') {
92+
return 'invalid_captcha';
93+
}
94+
return null;
95+
});
10096

10197
$this->expectException(UserException::class);
10298
$this->expectExceptionMessage("ERROR_INVALID_CAPTCHA");
10399

104-
$subject = oxNew(User::class);
100+
$subject = $this->createUserMock(captchaEnabled: true, twoFaEnabled: false);
105101
$subject->login('', '');
106102
}
107103

108104
public function testLoginWithEmptyCaptcha()
109105
{
110106
$this->requestMock
111107
->method('getRequestParameter')
112-
->with('captcha')
113-
->willReturn('');
108+
->willReturnCallback(function ($param) {
109+
if ($param === 'captcha') {
110+
return '';
111+
}
112+
return null;
113+
});
114114

115115
$this->expectException(UserException::class);
116116
$this->expectExceptionMessage("ERROR_EMPTY_CAPTCHA");
117117

118-
$subject = oxNew(User::class);
118+
$subject = $this->createUserMock(captchaEnabled: true, twoFaEnabled: false);
119119
$subject->login('', '');
120120
}
121121

122122
public function testLoginWithValidCaptchaAndValidCredentials(): void
123123
{
124-
$this->disableTwoFactorAuth();
125-
126124
$this->requestMock
127125
->method('getRequestParameter')
128126
->willReturnCallback(function ($param) {
@@ -132,22 +130,19 @@ public function testLoginWithValidCaptchaAndValidCredentials(): void
132130
return null;
133131
});
134132

135-
$subject = oxNew(User::class);
133+
$subject = $this->createUserMock(captchaEnabled: true, twoFaEnabled: false);
136134
$result = $subject->login(self::OTP_USER_NAME, self::OTP_USER_PASSWORD);
137135

138136
$this->assertTrue($result);
139137
}
140138

141139
public function testLoginWithOTPEnabledAndValidCredentialsRedirectsToOTP(): void
142140
{
143-
$this->disableCaptcha();
144-
$this->enableTwoFactorAuth();
145-
146141
$utilsMock = $this->createMock(Utils::class);
147142
$utilsMock->expects($this->once())->method('redirect');
148143
Registry::set(Utils::class, $utilsMock);
149144

150-
$subject = oxNew(User::class);
145+
$subject = $this->createUserMock(captchaEnabled: false, twoFaEnabled: true);
151146
$subject->login(self::OTP_USER_NAME, self::OTP_USER_PASSWORD);
152147

153148
$this->assertNotNull(
@@ -157,34 +152,25 @@ public function testLoginWithOTPEnabledAndValidCredentialsRedirectsToOTP(): void
157152

158153
public function testLoginWithOTPEnabledAndInvalidCredentialsThrowsException(): void
159154
{
160-
$this->disableCaptcha();
161-
$this->enableTwoFactorAuth();
162-
163155
$this->expectException(UserException::class);
164156
$this->expectExceptionMessage('ERROR_MESSAGE_USER_NOVALIDLOGIN');
165157

166-
$subject = oxNew(User::class);
158+
$subject = $this->createUserMock(captchaEnabled: false, twoFaEnabled: true);
167159
$subject->login(self::OTP_USER_NAME, uniqid());
168160
}
169161

170162
public function testLoginWithOTPEnabledAndNonExistentUserThrowsException(): void
171163
{
172-
$this->disableCaptcha();
173-
$this->enableTwoFactorAuth();
174-
175164
$this->expectException(UserException::class);
176165
$this->expectExceptionMessage('ERROR_MESSAGE_USER_NOVALIDLOGIN');
177166

178-
$subject = oxNew(User::class);
167+
$subject = $this->createUserMock(captchaEnabled: false, twoFaEnabled: true);
179168
$subject->login('nonexistent@test.com', 'anypassword');
180169
}
181170

182171
public function testLoginWithOTPDisabledCallsParentLogin(): void
183172
{
184-
$this->disableCaptcha();
185-
$this->disableTwoFactorAuth();
186-
187-
$subject = oxNew(User::class);
173+
$subject = $this->createUserMock(captchaEnabled: false, twoFaEnabled: false);
188174
$result = $subject->login(self::OTP_USER_NAME, self::OTP_USER_PASSWORD);
189175

190176
$this->assertTrue($result);
@@ -195,14 +181,11 @@ public function testLoginWithOTPDisabledCallsParentLogin(): void
195181

196182
public function testLoginWithOTPEnabledStoresUserIdInSession(): void
197183
{
198-
$this->disableCaptcha();
199-
$this->enableTwoFactorAuth();
200-
201184
$utilsMock = $this->createMock(Utils::class);
202185
$utilsMock->method('redirect');
203186
Registry::set(Utils::class, $utilsMock);
204187

205-
$subject = oxNew(User::class);
188+
$subject = $this->createUserMock(captchaEnabled: false, twoFaEnabled: true);
206189
$subject->login(self::OTP_USER_NAME, self::OTP_USER_PASSWORD);
207190

208191
$sessionUserId = Registry::getSession()->getVariable(AuthorizeService::USER_SESSION_KEY);
@@ -222,24 +205,22 @@ public function testLoginWithVerifiedChallengeStateSkipsOTPRedirect(): void
222205
$utilsMock->expects($this->never())->method('redirect');
223206
Registry::set(Utils::class, $utilsMock);
224207

225-
$result = oxNew(User::class)->login(self::OTP_USER_NAME, self::OTP_USER_PASSWORD);
208+
$subject = $this->createUserMock(captchaEnabled: false, twoFaEnabled: true);
209+
$result = $subject->login(self::OTP_USER_NAME, self::OTP_USER_PASSWORD);
226210

227211
$this->assertTrue($result);
228212
}
229213

230214
public function testLoginWithOTPPassSessionVariableMismatchTriggersOTPFlow(): void
231215
{
232-
$this->disableCaptcha();
233-
$this->enableTwoFactorAuth();
234-
235216
$mismatchedUserId = 'different-user-id';
236217
Registry::getSession()->setVariable('OTP_PASS', $mismatchedUserId);
237218

238219
$utilsMock = $this->createMock(Utils::class);
239220
$utilsMock->method('redirect');
240221
Registry::set(Utils::class, $utilsMock);
241222

242-
$subject = oxNew(User::class);
223+
$subject = $this->createUserMock(captchaEnabled: false, twoFaEnabled: true);
243224
$subject->login(self::OTP_USER_NAME, self::OTP_USER_PASSWORD);
244225

245226
$this->assertNotNull(
@@ -253,35 +234,29 @@ public function testLoginWithOTPPassSessionVariableMismatchTriggersOTPFlow(): vo
253234
);
254235
}
255236

256-
private function enableTwoFactorAuth(): void
237+
private function createUserMock(bool $captchaEnabled, bool $twoFaEnabled): SecurityModuleUser
257238
{
258-
$moduleSettingService = ContainerFacade::get(ModuleSettingServiceInterface::class);
259-
$moduleSettingService->saveBoolean(
260-
TwoFASettings::ACTIVE,
261-
true,
262-
Module::MODULE_ID
263-
);
264-
$moduleSettingService->saveString(
265-
TwoFASettings::TWO_FACTOR_TYPE,
266-
'otp',
267-
Module::MODULE_ID
268-
);
269-
}
239+
$captchaSettings = $this->createMock(CaptchaSettingsServiceInterface::class);
240+
$captchaSettings->method('isCaptchaEnabled')->willReturn($captchaEnabled);
241+
$captchaSettings->method('isHoneyPotCaptchaEnabled')->willReturn(false);
270242

271-
private function disableTwoFactorAuth(): void
272-
{
273-
$moduleSettingService = ContainerFacade::get(ModuleSettingServiceInterface::class);
274-
$moduleSettingService->saveBoolean(
275-
TwoFASettings::ACTIVE,
276-
false,
277-
Module::MODULE_ID
243+
$twoFaSettings = $this->createMock(TwoFASettingsInterface::class);
244+
$twoFaSettings->method('isTwoFactorAuthEnabled')->willReturn($twoFaEnabled);
245+
246+
$serviceMocks = [
247+
CaptchaSettingsServiceInterface::class => $captchaSettings,
248+
TwoFASettingsInterface::class => $twoFaSettings,
249+
];
250+
251+
/** @var SecurityModuleUser $userMock */
252+
$userMock = $this->getMockBuilder(SecurityModuleUser::class)
253+
->onlyMethods(['getService'])
254+
->getMock();
255+
$userMock->method('getService')->willReturnCallback(
256+
fn(string $id) => $serviceMocks[$id] ?? ContainerFacade::get($id)
278257
);
279-
}
280258

281-
private function disableCaptcha(): void
282-
{
283-
$captchaSettings = ContainerFacade::get(CaptchaSettingsServiceInterface::class);
284-
$captchaSettings->saveIsCaptchaEnabled(false);
259+
return $userMock;
285260
}
286261

287262
private function getOTPUserId(): string

0 commit comments

Comments
 (0)