Skip to content

Commit 01dc5a4

Browse files
test(listener): add unit tests for UserDeletedListener functionality
Added comprehensive unit tests for the UserDeletedListener to ensure proper handling of user deletion events, including scenarios with no accounts, single and multiple accounts, client exceptions, and partial failures. This enhances test coverage and reliability of the mail account deletion process. Signed-off-by: Misha M.-Kupriyanov <[email protected]>
1 parent 95dc9dc commit 01dc5a4

File tree

1 file changed

+199
-0
lines changed

1 file changed

+199
-0
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Mail\Tests\Unit\Listener;
11+
12+
use ChristophWurst\Nextcloud\Testing\TestCase;
13+
use OCA\Mail\Account;
14+
use OCA\Mail\Exception\ClientException;
15+
use OCA\Mail\Listener\UserDeletedListener;
16+
use OCA\Mail\Service\AccountService;
17+
use OCP\EventDispatcher\Event;
18+
use OCP\IUser;
19+
use OCP\User\Events\UserDeletedEvent;
20+
use PHPUnit\Framework\MockObject\MockObject;
21+
use Psr\Log\LoggerInterface;
22+
23+
class UserDeletedListenerTest extends TestCase {
24+
private AccountService&MockObject $accountService;
25+
private LoggerInterface&MockObject $logger;
26+
private UserDeletedListener $listener;
27+
28+
protected function setUp(): void {
29+
parent::setUp();
30+
31+
$this->accountService = $this->createMock(AccountService::class);
32+
$this->logger = $this->createMock(LoggerInterface::class);
33+
34+
$this->listener = new UserDeletedListener(
35+
$this->accountService,
36+
$this->logger
37+
);
38+
}
39+
40+
private function createUserMock(string $userId = 'test-user'): IUser&MockObject {
41+
$user = $this->createMock(IUser::class);
42+
$user->method('getUID')->willReturn($userId);
43+
return $user;
44+
}
45+
46+
private function createAccountMock(int $id): Account&MockObject {
47+
$account = $this->createMock(Account::class);
48+
$account->method('getId')->willReturn($id);
49+
return $account;
50+
}
51+
52+
public function testImplementsIEventListener(): void {
53+
$this->assertInstanceOf(\OCP\EventDispatcher\IEventListener::class, $this->listener);
54+
}
55+
56+
public function testHandleMethodHasOverrideAttribute(): void {
57+
$reflection = new \ReflectionMethod(UserDeletedListener::class, 'handle');
58+
$attributes = $reflection->getAttributes(\Override::class);
59+
60+
$this->assertNotEmpty(
61+
$attributes,
62+
sprintf('The method %s::handle does not have the #[Override] attribute.', UserDeletedListener::class)
63+
);
64+
}
65+
66+
public function testHandleUnrelated(): void {
67+
$event = new Event();
68+
69+
$this->accountService->expects($this->never())
70+
->method('findByUserId');
71+
72+
$this->listener->handle($event);
73+
74+
$this->addToAssertionCount(1);
75+
}
76+
77+
public function testHandleUserDeletedWithNoAccounts(): void {
78+
$user = $this->createUserMock();
79+
$event = new UserDeletedEvent($user);
80+
81+
$this->accountService->expects($this->once())
82+
->method('findByUserId')
83+
->with('test-user')
84+
->willReturn([]);
85+
86+
$this->accountService->expects($this->never())
87+
->method('delete');
88+
89+
$this->logger->expects($this->never())
90+
->method('error');
91+
92+
$this->listener->handle($event);
93+
}
94+
95+
public function testHandleUserDeletedWithSingleAccount(): void {
96+
$user = $this->createUserMock();
97+
$account = $this->createAccountMock(42);
98+
$event = new UserDeletedEvent($user);
99+
100+
$this->accountService->expects($this->once())
101+
->method('findByUserId')
102+
->with('test-user')
103+
->willReturn([$account]);
104+
105+
$this->accountService->expects($this->once())
106+
->method('delete')
107+
->with('test-user', 42);
108+
109+
$this->logger->expects($this->never())
110+
->method('error');
111+
112+
$this->listener->handle($event);
113+
}
114+
115+
public function testHandleUserDeletedWithMultipleAccounts(): void {
116+
$user = $this->createUserMock();
117+
$account1 = $this->createAccountMock(1);
118+
$account2 = $this->createAccountMock(2);
119+
$account3 = $this->createAccountMock(3);
120+
$event = new UserDeletedEvent($user);
121+
122+
$this->accountService->expects($this->once())
123+
->method('findByUserId')
124+
->with('test-user')
125+
->willReturn([$account1, $account2, $account3]);
126+
127+
$this->accountService->expects($this->exactly(3))
128+
->method('delete')
129+
->willReturnCallback(function ($userId, $accountId) {
130+
$this->assertSame('test-user', $userId);
131+
$this->assertContains($accountId, [1, 2, 3]);
132+
});
133+
134+
$this->logger->expects($this->never())
135+
->method('error');
136+
137+
$this->listener->handle($event);
138+
}
139+
140+
public function testHandleUserDeletedWithClientException(): void {
141+
$user = $this->createUserMock();
142+
$account = $this->createAccountMock(42);
143+
$event = new UserDeletedEvent($user);
144+
145+
$exception = new ClientException('Test exception');
146+
147+
$this->accountService->expects($this->once())
148+
->method('findByUserId')
149+
->with('test-user')
150+
->willReturn([$account]);
151+
152+
$this->accountService->expects($this->once())
153+
->method('delete')
154+
->with('test-user', 42)
155+
->willThrowException($exception);
156+
157+
$this->logger->expects($this->once())
158+
->method('error')
159+
->with(
160+
'Could not delete user\'s Mail account: Test exception',
161+
['exception' => $exception]
162+
);
163+
164+
$this->listener->handle($event);
165+
}
166+
167+
public function testHandleUserDeletedWithPartialFailure(): void {
168+
$user = $this->createUserMock();
169+
$account1 = $this->createAccountMock(1);
170+
$account2 = $this->createAccountMock(2);
171+
$account3 = $this->createAccountMock(3);
172+
$event = new UserDeletedEvent($user);
173+
174+
$exception = new ClientException('Failed to delete account 2');
175+
176+
$this->accountService->expects($this->once())
177+
->method('findByUserId')
178+
->with('test-user')
179+
->willReturn([$account1, $account2, $account3]);
180+
181+
$this->accountService->expects($this->exactly(3))
182+
->method('delete')
183+
->willReturnCallback(function ($userId, $accountId) use ($exception) {
184+
$this->assertSame('test-user', $userId);
185+
if ($accountId === 2) {
186+
throw $exception;
187+
}
188+
});
189+
190+
$this->logger->expects($this->once())
191+
->method('error')
192+
->with(
193+
'Could not delete user\'s Mail account: Failed to delete account 2',
194+
['exception' => $exception]
195+
);
196+
197+
$this->listener->handle($event);
198+
}
199+
}

0 commit comments

Comments
 (0)