Completed
Push — master ( 5d14f8...2337bd )
by Robin
27:19 queued 16s
created
apps/federatedfilesharing/tests/NotificationsTest.php 1 patch
Indentation   +101 added lines, -101 removed lines patch added patch discarded remove patch
@@ -21,117 +21,117 @@
 block discarded – undo
21 21
 use Psr\Log\LoggerInterface;
22 22
 
23 23
 class NotificationsTest extends \Test\TestCase {
24
-	private AddressHandler&MockObject $addressHandler;
25
-	private IClientService&MockObject $httpClientService;
26
-	private IDiscoveryService&MockObject $discoveryService;
27
-	private IJobList&MockObject $jobList;
28
-	private ICloudFederationProviderManager&MockObject $cloudFederationProviderManager;
29
-	private ICloudFederationFactory&MockObject $cloudFederationFactory;
30
-	private IEventDispatcher&MockObject $eventDispatcher;
31
-	private LoggerInterface&MockObject $logger;
24
+    private AddressHandler&MockObject $addressHandler;
25
+    private IClientService&MockObject $httpClientService;
26
+    private IDiscoveryService&MockObject $discoveryService;
27
+    private IJobList&MockObject $jobList;
28
+    private ICloudFederationProviderManager&MockObject $cloudFederationProviderManager;
29
+    private ICloudFederationFactory&MockObject $cloudFederationFactory;
30
+    private IEventDispatcher&MockObject $eventDispatcher;
31
+    private LoggerInterface&MockObject $logger;
32 32
 
33
-	protected function setUp(): void {
34
-		parent::setUp();
33
+    protected function setUp(): void {
34
+        parent::setUp();
35 35
 
36
-		$this->jobList = $this->createMock(IJobList::class);
37
-		$this->discoveryService = $this->createMock(IDiscoveryService::class);
38
-		$this->httpClientService = $this->createMock(IClientService::class);
39
-		$this->addressHandler = $this->createMock(AddressHandler::class);
40
-		$this->logger = $this->createMock(LoggerInterface::class);
41
-		$this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class);
42
-		$this->cloudFederationFactory = $this->createMock(ICloudFederationFactory::class);
43
-		$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
44
-	}
36
+        $this->jobList = $this->createMock(IJobList::class);
37
+        $this->discoveryService = $this->createMock(IDiscoveryService::class);
38
+        $this->httpClientService = $this->createMock(IClientService::class);
39
+        $this->addressHandler = $this->createMock(AddressHandler::class);
40
+        $this->logger = $this->createMock(LoggerInterface::class);
41
+        $this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class);
42
+        $this->cloudFederationFactory = $this->createMock(ICloudFederationFactory::class);
43
+        $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
44
+    }
45 45
 
46
-	/**
47
-	 * @return Notifications|MockObject
48
-	 */
49
-	private function getInstance(array $mockedMethods = []) {
50
-		if (empty($mockedMethods)) {
51
-			return new Notifications(
52
-				$this->addressHandler,
53
-				$this->httpClientService,
54
-				$this->discoveryService,
55
-				$this->jobList,
56
-				$this->cloudFederationProviderManager,
57
-				$this->cloudFederationFactory,
58
-				$this->eventDispatcher,
59
-				$this->logger,
60
-			);
61
-		}
46
+    /**
47
+     * @return Notifications|MockObject
48
+     */
49
+    private function getInstance(array $mockedMethods = []) {
50
+        if (empty($mockedMethods)) {
51
+            return new Notifications(
52
+                $this->addressHandler,
53
+                $this->httpClientService,
54
+                $this->discoveryService,
55
+                $this->jobList,
56
+                $this->cloudFederationProviderManager,
57
+                $this->cloudFederationFactory,
58
+                $this->eventDispatcher,
59
+                $this->logger,
60
+            );
61
+        }
62 62
 
63
-		return $this->getMockBuilder(Notifications::class)
64
-			->setConstructorArgs(
65
-				[
66
-					$this->addressHandler,
67
-					$this->httpClientService,
68
-					$this->discoveryService,
69
-					$this->jobList,
70
-					$this->cloudFederationProviderManager,
71
-					$this->cloudFederationFactory,
72
-					$this->eventDispatcher,
73
-					$this->logger,
74
-				]
75
-			)
76
-			->onlyMethods($mockedMethods)
77
-			->getMock();
78
-	}
63
+        return $this->getMockBuilder(Notifications::class)
64
+            ->setConstructorArgs(
65
+                [
66
+                    $this->addressHandler,
67
+                    $this->httpClientService,
68
+                    $this->discoveryService,
69
+                    $this->jobList,
70
+                    $this->cloudFederationProviderManager,
71
+                    $this->cloudFederationFactory,
72
+                    $this->eventDispatcher,
73
+                    $this->logger,
74
+                ]
75
+            )
76
+            ->onlyMethods($mockedMethods)
77
+            ->getMock();
78
+    }
79 79
 
80 80
 
81
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestSendUpdateToRemote')]
82
-	public function testSendUpdateToRemote(int $try, array $httpRequestResult, bool $expected): void {
83
-		$remote = 'http://remote';
84
-		$id = 42;
85
-		$timestamp = 63576;
86
-		$token = 'token';
87
-		$action = 'unshare';
88
-		$instance = $this->getInstance(['tryHttpPostToShareEndpoint', 'getTimestamp']);
81
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestSendUpdateToRemote')]
82
+    public function testSendUpdateToRemote(int $try, array $httpRequestResult, bool $expected): void {
83
+        $remote = 'http://remote';
84
+        $id = 42;
85
+        $timestamp = 63576;
86
+        $token = 'token';
87
+        $action = 'unshare';
88
+        $instance = $this->getInstance(['tryHttpPostToShareEndpoint', 'getTimestamp']);
89 89
 
90
-		$instance->expects($this->any())->method('getTimestamp')->willReturn($timestamp);
90
+        $instance->expects($this->any())->method('getTimestamp')->willReturn($timestamp);
91 91
 
92
-		$instance->expects($this->once())->method('tryHttpPostToShareEndpoint')
93
-			->with($remote, '/' . $id . '/unshare', ['token' => $token, 'data1Key' => 'data1Value', 'remoteId' => $id], $action)
94
-			->willReturn($httpRequestResult);
92
+        $instance->expects($this->once())->method('tryHttpPostToShareEndpoint')
93
+            ->with($remote, '/' . $id . '/unshare', ['token' => $token, 'data1Key' => 'data1Value', 'remoteId' => $id], $action)
94
+            ->willReturn($httpRequestResult);
95 95
 
96
-		// only add background job on first try
97
-		if ($try === 0 && $expected === false) {
98
-			$this->jobList->expects($this->once())->method('add')
99
-				->with(
100
-					RetryJob::class,
101
-					[
102
-						'remote' => $remote,
103
-						'remoteId' => $id,
104
-						'action' => 'unshare',
105
-						'data' => json_encode(['data1Key' => 'data1Value']),
106
-						'token' => $token,
107
-						'try' => $try,
108
-						'lastRun' => $timestamp
109
-					]
110
-				);
111
-		} else {
112
-			$this->jobList->expects($this->never())->method('add');
113
-		}
96
+        // only add background job on first try
97
+        if ($try === 0 && $expected === false) {
98
+            $this->jobList->expects($this->once())->method('add')
99
+                ->with(
100
+                    RetryJob::class,
101
+                    [
102
+                        'remote' => $remote,
103
+                        'remoteId' => $id,
104
+                        'action' => 'unshare',
105
+                        'data' => json_encode(['data1Key' => 'data1Value']),
106
+                        'token' => $token,
107
+                        'try' => $try,
108
+                        'lastRun' => $timestamp
109
+                    ]
110
+                );
111
+        } else {
112
+            $this->jobList->expects($this->never())->method('add');
113
+        }
114 114
 
115
-		$this->assertSame($expected,
116
-			$instance->sendUpdateToRemote($remote, $id, $token, $action, ['data1Key' => 'data1Value'], $try)
117
-		);
118
-	}
115
+        $this->assertSame($expected,
116
+            $instance->sendUpdateToRemote($remote, $id, $token, $action, ['data1Key' => 'data1Value'], $try)
117
+        );
118
+    }
119 119
 
120 120
 
121
-	public static function dataTestSendUpdateToRemote(): array {
122
-		return [
123
-			// test if background job is added correctly
124
-			[0, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], true],
125
-			[1, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], true],
126
-			[0, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], false],
127
-			[1, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], false],
128
-			// test all combinations of 'statuscode' and 'success'
129
-			[0, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], true],
130
-			[0, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])], true],
131
-			[0, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 400]]])], false],
132
-			[0, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], false],
133
-			[0, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])], false],
134
-			[0, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 400]]])], false],
135
-		];
136
-	}
121
+    public static function dataTestSendUpdateToRemote(): array {
122
+        return [
123
+            // test if background job is added correctly
124
+            [0, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], true],
125
+            [1, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], true],
126
+            [0, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], false],
127
+            [1, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], false],
128
+            // test all combinations of 'statuscode' and 'success'
129
+            [0, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], true],
130
+            [0, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])], true],
131
+            [0, ['success' => true, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 400]]])], false],
132
+            [0, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 200]]])], false],
133
+            [0, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 100]]])], false],
134
+            [0, ['success' => false, 'result' => json_encode(['ocs' => ['meta' => ['statuscode' => 400]]])], false],
135
+        ];
136
+    }
137 137
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/tests/FederatedShareProviderTest.php 1 patch
Indentation   +912 added lines, -912 removed lines patch added patch discarded remove patch
@@ -39,916 +39,916 @@
 block discarded – undo
39 39
  * @group DB
40 40
  */
41 41
 class FederatedShareProviderTest extends \Test\TestCase {
42
-	protected IDBConnection $connection;
43
-	protected AddressHandler&MockObject $addressHandler;
44
-	protected Notifications&MockObject $notifications;
45
-	protected TokenHandler&MockObject $tokenHandler;
46
-	protected IL10N $l;
47
-	protected LoggerInterface $logger;
48
-	protected IRootFolder&MockObject $rootFolder;
49
-	protected IConfig&MockObject $config;
50
-	protected IUserManager&MockObject $userManager;
51
-	protected \OCP\GlobalScale\IConfig&MockObject $gsConfig;
52
-	protected IManager $shareManager;
53
-	protected FederatedShareProvider $provider;
54
-	protected IContactsManager&MockObject $contactsManager;
55
-	private ICloudIdManager $cloudIdManager;
56
-	private ICloudFederationProviderManager&MockObject $cloudFederationProviderManager;
57
-
58
-	protected function setUp(): void {
59
-		parent::setUp();
60
-
61
-		$this->connection = Server::get(IDBConnection::class);
62
-		$this->notifications = $this->createMock(Notifications::class);
63
-		$this->tokenHandler = $this->createMock(TokenHandler::class);
64
-		$this->l = $this->createMock(IL10N::class);
65
-		$this->l->method('t')
66
-			->willReturnCallback(function ($text, $parameters = []) {
67
-				return vsprintf($text, $parameters);
68
-			});
69
-		$this->logger = $this->createMock(LoggerInterface::class);
70
-		$this->rootFolder = $this->createMock(IRootFolder::class);
71
-		$this->config = $this->createMock(IConfig::class);
72
-		$this->userManager = $this->createMock(IUserManager::class);
73
-		//$this->addressHandler = new AddressHandler(\OC::$server->getURLGenerator(), $this->l);
74
-		$this->addressHandler = $this->createMock(AddressHandler::class);
75
-		$this->contactsManager = $this->createMock(IContactsManager::class);
76
-		$this->cloudIdManager = new CloudIdManager(
77
-			$this->contactsManager,
78
-			$this->createMock(IURLGenerator::class),
79
-			$this->userManager,
80
-			$this->createMock(ICacheFactory::class),
81
-			$this->createMock(IEventDispatcher::class)
82
-		);
83
-		$this->gsConfig = $this->createMock(\OCP\GlobalScale\IConfig::class);
84
-
85
-		$this->userManager->expects($this->any())->method('userExists')->willReturn(true);
86
-
87
-		$this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class);
88
-
89
-		$this->provider = new FederatedShareProvider(
90
-			$this->connection,
91
-			$this->addressHandler,
92
-			$this->notifications,
93
-			$this->tokenHandler,
94
-			$this->l,
95
-			$this->rootFolder,
96
-			$this->config,
97
-			$this->userManager,
98
-			$this->cloudIdManager,
99
-			$this->gsConfig,
100
-			$this->cloudFederationProviderManager,
101
-			$this->logger,
102
-		);
103
-
104
-		$this->shareManager = Server::get(IManager::class);
105
-	}
106
-
107
-	protected function tearDown(): void {
108
-		$this->connection->getQueryBuilder()->delete('share')->executeStatement();
109
-
110
-		parent::tearDown();
111
-	}
112
-
113
-	public static function dataTestCreate(): array {
114
-		return [
115
-			[null, null],
116
-			[new \DateTime('2020-03-01T01:02:03'), '2020-03-01 01:02:03'],
117
-		];
118
-	}
119
-
120
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestCreate')]
121
-	public function testCreate(?\DateTime $expirationDate, ?string $expectedDataDate): void {
122
-		$share = $this->shareManager->newShare();
123
-
124
-		/** @var File&MockObject $node */
125
-		$node = $this->createMock(File::class);
126
-		$node->method('getId')->willReturn(42);
127
-		$node->method('getName')->willReturn('myFile');
128
-
129
-		$share->setSharedWith('[email protected]')
130
-			->setSharedBy('sharedBy')
131
-			->setShareOwner('shareOwner')
132
-			->setPermissions(19)
133
-			->setShareType(IShare::TYPE_REMOTE)
134
-			->setExpirationDate($expirationDate)
135
-			->setNode($node);
136
-
137
-		$this->tokenHandler->method('generateToken')->willReturn('token');
138
-
139
-		$this->addressHandler->expects($this->any())->method('generateRemoteURL')
140
-			->willReturn('http://localhost/');
141
-		$this->addressHandler->expects($this->any())->method('splitUserRemote')
142
-			->willReturn(['user', 'server.com']);
143
-
144
-		$this->notifications->expects($this->once())
145
-			->method('sendRemoteShare')
146
-			->with(
147
-				$this->equalTo('token'),
148
-				$this->equalTo('[email protected]'),
149
-				$this->equalTo('myFile'),
150
-				$this->anything(),
151
-				'shareOwner',
152
-				'shareOwner@http://localhost',
153
-				'sharedBy',
154
-				'sharedBy@http://localhost'
155
-			)
156
-			->willReturn(true);
157
-
158
-		$this->rootFolder->expects($this->never())->method($this->anything());
159
-
160
-		$this->contactsManager->expects($this->any())
161
-			->method('search')
162
-			->willReturn([]);
163
-
164
-		$share = $this->provider->create($share);
165
-
166
-		$qb = $this->connection->getQueryBuilder();
167
-		$stmt = $qb->select('*')
168
-			->from('share')
169
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
170
-			->executeQuery();
171
-
172
-		$data = $stmt->fetch();
173
-		$stmt->closeCursor();
174
-
175
-		$expected = [
176
-			'share_type' => IShare::TYPE_REMOTE,
177
-			'share_with' => '[email protected]',
178
-			'uid_owner' => 'shareOwner',
179
-			'uid_initiator' => 'sharedBy',
180
-			'item_type' => 'file',
181
-			'item_source' => 42,
182
-			'file_source' => 42,
183
-			'permissions' => 19,
184
-			'accepted' => 0,
185
-			'token' => 'token',
186
-			'expiration' => $expectedDataDate,
187
-		];
188
-		foreach (array_keys($expected) as $key) {
189
-			$this->assertEquals($expected[$key], $data[$key], "Assert that value for key '$key' is the same");
190
-		}
191
-
192
-		$this->assertEquals($data['id'], $share->getId());
193
-		$this->assertEquals(IShare::TYPE_REMOTE, $share->getShareType());
194
-		$this->assertEquals('[email protected]', $share->getSharedWith());
195
-		$this->assertEquals('sharedBy', $share->getSharedBy());
196
-		$this->assertEquals('shareOwner', $share->getShareOwner());
197
-		$this->assertEquals('file', $share->getNodeType());
198
-		$this->assertEquals(42, $share->getNodeId());
199
-		$this->assertEquals(19, $share->getPermissions());
200
-		$this->assertEquals('token', $share->getToken());
201
-		$this->assertEquals($expirationDate, $share->getExpirationDate());
202
-	}
203
-
204
-	public function testCreateCouldNotFindServer(): void {
205
-		$share = $this->shareManager->newShare();
206
-
207
-		$node = $this->createMock(File::class);
208
-		$node->method('getId')->willReturn(42);
209
-		$node->method('getName')->willReturn('myFile');
210
-
211
-		$share->setSharedWith('[email protected]')
212
-			->setSharedBy('sharedBy')
213
-			->setShareOwner('shareOwner')
214
-			->setPermissions(19)
215
-			->setShareType(IShare::TYPE_REMOTE)
216
-			->setNode($node);
217
-
218
-		$this->tokenHandler->method('generateToken')->willReturn('token');
219
-
220
-		$this->addressHandler->expects($this->any())->method('generateRemoteURL')
221
-			->willReturn('http://localhost/');
222
-		$this->addressHandler->expects($this->any())->method('splitUserRemote')
223
-			->willReturn(['user', 'server.com']);
224
-
225
-		$this->notifications->expects($this->once())
226
-			->method('sendRemoteShare')
227
-			->with(
228
-				$this->equalTo('token'),
229
-				$this->equalTo('[email protected]'),
230
-				$this->equalTo('myFile'),
231
-				$this->anything(),
232
-				'shareOwner',
233
-				'shareOwner@http://localhost',
234
-				'sharedBy',
235
-				'sharedBy@http://localhost'
236
-			)->willReturn(false);
237
-
238
-		$this->rootFolder->method('getById')
239
-			->with('42')
240
-			->willReturn([$node]);
241
-
242
-		$this->contactsManager->expects($this->any())
243
-			->method('search')
244
-			->willReturn([]);
245
-
246
-		try {
247
-			$share = $this->provider->create($share);
248
-			$this->fail();
249
-		} catch (\Exception $e) {
250
-			$this->assertEquals('Sharing myFile failed, could not find [email protected], maybe the server is currently unreachable or uses a self-signed certificate.', $e->getMessage());
251
-		}
252
-
253
-		$qb = $this->connection->getQueryBuilder();
254
-		$stmt = $qb->select('*')
255
-			->from('share')
256
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
257
-			->executeQuery();
258
-
259
-		$data = $stmt->fetch();
260
-		$stmt->closeCursor();
261
-
262
-		$this->assertFalse($data);
263
-	}
264
-
265
-	public function testCreateException(): void {
266
-		$share = $this->shareManager->newShare();
267
-
268
-		$node = $this->createMock(File::class);
269
-		$node->method('getId')->willReturn(42);
270
-		$node->method('getName')->willReturn('myFile');
271
-
272
-		$share->setSharedWith('[email protected]')
273
-			->setSharedBy('sharedBy')
274
-			->setShareOwner('shareOwner')
275
-			->setPermissions(19)
276
-			->setShareType(IShare::TYPE_REMOTE)
277
-			->setNode($node);
278
-
279
-		$this->tokenHandler->method('generateToken')->willReturn('token');
280
-
281
-		$this->addressHandler->expects($this->any())->method('generateRemoteURL')
282
-			->willReturn('http://localhost/');
283
-		$this->addressHandler->expects($this->any())->method('splitUserRemote')
284
-			->willReturn(['user', 'server.com']);
285
-
286
-		$this->notifications->expects($this->once())
287
-			->method('sendRemoteShare')
288
-			->with(
289
-				$this->equalTo('token'),
290
-				$this->equalTo('[email protected]'),
291
-				$this->equalTo('myFile'),
292
-				$this->anything(),
293
-				'shareOwner',
294
-				'shareOwner@http://localhost',
295
-				'sharedBy',
296
-				'sharedBy@http://localhost'
297
-			)->willThrowException(new \Exception('dummy'));
298
-
299
-		$this->rootFolder->method('getById')
300
-			->with('42')
301
-			->willReturn([$node]);
302
-
303
-		$this->contactsManager->expects($this->any())
304
-			->method('search')
305
-			->willReturn([]);
306
-
307
-		try {
308
-			$share = $this->provider->create($share);
309
-			$this->fail();
310
-		} catch (\Exception $e) {
311
-			$this->assertEquals('Sharing myFile failed, could not find [email protected], maybe the server is currently unreachable or uses a self-signed certificate.', $e->getMessage());
312
-		}
313
-
314
-		$qb = $this->connection->getQueryBuilder();
315
-		$stmt = $qb->select('*')
316
-			->from('share')
317
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
318
-			->executeQuery();
319
-
320
-		$data = $stmt->fetch();
321
-		$stmt->closeCursor();
322
-
323
-		$this->assertFalse($data);
324
-	}
325
-
326
-	public function testCreateShareWithSelf(): void {
327
-		$share = $this->shareManager->newShare();
328
-
329
-		$node = $this->createMock(File::class);
330
-		$node->method('getId')->willReturn(42);
331
-		$node->method('getName')->willReturn('myFile');
332
-
333
-		$this->addressHandler->expects($this->any())->method('compareAddresses')
334
-			->willReturn(true);
335
-
336
-		$shareWith = 'sharedBy@localhost';
337
-
338
-		$share->setSharedWith($shareWith)
339
-			->setSharedBy('sharedBy')
340
-			->setShareOwner('shareOwner')
341
-			->setPermissions(19)
342
-			->setNode($node);
343
-
344
-		$this->contactsManager->expects($this->any())
345
-			->method('search')
346
-			->willReturn([]);
347
-
348
-		$this->rootFolder->expects($this->never())->method($this->anything());
349
-
350
-		try {
351
-			$share = $this->provider->create($share);
352
-			$this->fail();
353
-		} catch (\Exception $e) {
354
-			$this->assertEquals('Not allowed to create a federated share to the same account', $e->getMessage());
355
-		}
356
-
357
-		$qb = $this->connection->getQueryBuilder();
358
-		$stmt = $qb->select('*')
359
-			->from('share')
360
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
361
-			->executeQuery();
362
-
363
-		$data = $stmt->fetch();
364
-		$stmt->closeCursor();
365
-
366
-		$this->assertFalse($data);
367
-	}
368
-
369
-	public function testCreateAlreadyShared(): void {
370
-		$share = $this->shareManager->newShare();
371
-
372
-		$node = $this->createMock(File::class);
373
-		$node->method('getId')->willReturn(42);
374
-		$node->method('getName')->willReturn('myFile');
375
-
376
-
377
-		$this->addressHandler->expects($this->any())->method('splitUserRemote')
378
-			->willReturn(['user', 'server.com']);
379
-
380
-		$share->setSharedWith('[email protected]')
381
-			->setSharedBy('sharedBy')
382
-			->setShareOwner('shareOwner')
383
-			->setPermissions(19)
384
-			->setShareType(IShare::TYPE_REMOTE)
385
-			->setNode($node);
386
-
387
-		$this->tokenHandler->method('generateToken')->willReturn('token');
388
-
389
-		$this->addressHandler->expects($this->any())->method('generateRemoteURL')
390
-			->willReturn('http://localhost/');
391
-
392
-		$this->notifications->expects($this->once())
393
-			->method('sendRemoteShare')
394
-			->with(
395
-				$this->equalTo('token'),
396
-				$this->equalTo('[email protected]'),
397
-				$this->equalTo('myFile'),
398
-				$this->anything(),
399
-				'shareOwner',
400
-				'shareOwner@http://localhost',
401
-				'sharedBy',
402
-				'sharedBy@http://localhost'
403
-			)->willReturn(true);
404
-
405
-		$this->rootFolder->expects($this->never())->method($this->anything());
406
-
407
-		$this->contactsManager->expects($this->any())
408
-			->method('search')
409
-			->willReturn([]);
410
-
411
-		$this->provider->create($share);
412
-
413
-		try {
414
-			$this->provider->create($share);
415
-		} catch (\Exception $e) {
416
-			$this->assertEquals('Sharing myFile failed, because this item is already shared with the account [email protected]', $e->getMessage());
417
-		}
418
-	}
419
-
420
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestUpdate')]
421
-	public function testUpdate(string $owner, string $sharedBy, ?\DateTime $expirationDate): void {
422
-		$this->provider = $this->getMockBuilder(FederatedShareProvider::class)
423
-			->setConstructorArgs(
424
-				[
425
-					$this->connection,
426
-					$this->addressHandler,
427
-					$this->notifications,
428
-					$this->tokenHandler,
429
-					$this->l,
430
-					$this->rootFolder,
431
-					$this->config,
432
-					$this->userManager,
433
-					$this->cloudIdManager,
434
-					$this->gsConfig,
435
-					$this->cloudFederationProviderManager,
436
-					$this->logger,
437
-				]
438
-			)
439
-			->onlyMethods(['sendPermissionUpdate'])
440
-			->getMock();
441
-
442
-		$share = $this->shareManager->newShare();
443
-
444
-		$node = $this->createMock(File::class);
445
-		$node->method('getId')->willReturn(42);
446
-		$node->method('getName')->willReturn('myFile');
447
-
448
-		$this->addressHandler->expects($this->any())->method('splitUserRemote')
449
-			->willReturn(['user', 'server.com']);
450
-
451
-		$share->setSharedWith('[email protected]')
452
-			->setSharedBy($sharedBy)
453
-			->setShareOwner($owner)
454
-			->setPermissions(19)
455
-			->setShareType(IShare::TYPE_REMOTE)
456
-			->setExpirationDate(new \DateTime('2019-02-01T01:02:03'))
457
-			->setNode($node);
458
-
459
-		$this->tokenHandler->method('generateToken')->willReturn('token');
460
-		$this->addressHandler->expects($this->any())->method('generateRemoteURL')
461
-			->willReturn('http://localhost/');
462
-
463
-		$this->notifications->expects($this->once())
464
-			->method('sendRemoteShare')
465
-			->with(
466
-				$this->equalTo('token'),
467
-				$this->equalTo('[email protected]'),
468
-				$this->equalTo('myFile'),
469
-				$this->anything(),
470
-				$owner,
471
-				$owner . '@http://localhost',
472
-				$sharedBy,
473
-				$sharedBy . '@http://localhost'
474
-			)->willReturn(true);
475
-
476
-		if ($owner === $sharedBy) {
477
-			$this->provider->expects($this->never())->method('sendPermissionUpdate');
478
-		} else {
479
-			$this->provider->expects($this->once())->method('sendPermissionUpdate');
480
-		}
481
-
482
-		$this->rootFolder->expects($this->never())->method($this->anything());
483
-
484
-		$this->contactsManager->expects($this->any())
485
-			->method('search')
486
-			->willReturn([]);
487
-
488
-		$share = $this->provider->create($share);
489
-
490
-		$share->setPermissions(1);
491
-		$share->setExpirationDate($expirationDate);
492
-		$this->provider->update($share);
493
-
494
-		$share = $this->provider->getShareById($share->getId());
495
-
496
-		$this->assertEquals(1, $share->getPermissions());
497
-		$this->assertEquals($expirationDate, $share->getExpirationDate());
498
-	}
499
-
500
-	public static function dataTestUpdate(): array {
501
-		return [
502
-			['sharedBy', 'shareOwner', new \DateTime('2020-03-01T01:02:03')],
503
-			['shareOwner', 'shareOwner', null],
504
-		];
505
-	}
506
-
507
-	public function testGetSharedBy(): void {
508
-		$node = $this->createMock(File::class);
509
-		$node->method('getId')->willReturn(42);
510
-		$node->method('getName')->willReturn('myFile');
511
-
512
-		$this->addressHandler->expects($this->never())->method('splitUserRemote');
513
-
514
-		$this->addressHandler->method('generateRemoteURL')
515
-			->willReturn('remoteurl.com');
516
-
517
-		$this->tokenHandler->method('generateToken')->willReturn('token');
518
-		$this->notifications
519
-			->method('sendRemoteShare')
520
-			->willReturn(true);
521
-
522
-		$this->rootFolder->expects($this->never())->method($this->anything());
523
-
524
-		$this->contactsManager->expects($this->any())
525
-			->method('search')
526
-			->willReturn([]);
527
-
528
-		$share = $this->shareManager->newShare();
529
-		$share->setSharedWith('[email protected]')
530
-			->setSharedBy('sharedBy')
531
-			->setShareOwner('shareOwner')
532
-			->setPermissions(19)
533
-			->setShareType(IShare::TYPE_REMOTE)
534
-			->setNode($node);
535
-		$this->provider->create($share);
536
-
537
-		$share2 = $this->shareManager->newShare();
538
-		$share2->setSharedWith('[email protected]')
539
-			->setSharedBy('sharedBy2')
540
-			->setShareOwner('shareOwner')
541
-			->setPermissions(19)
542
-			->setShareType(IShare::TYPE_REMOTE)
543
-			->setNode($node);
544
-		$this->provider->create($share2);
545
-
546
-		$shares = $this->provider->getSharesBy('sharedBy', IShare::TYPE_REMOTE, null, false, -1, 0);
547
-
548
-		$this->assertCount(1, $shares);
549
-		$this->assertEquals('[email protected]', $shares[0]->getSharedWith());
550
-		$this->assertEquals('sharedBy', $shares[0]->getSharedBy());
551
-	}
552
-
553
-	public function testGetSharedByWithNode(): void {
554
-		$node = $this->createMock(File::class);
555
-		$node->method('getId')->willReturn(42);
556
-		$node->method('getName')->willReturn('myFile');
557
-
558
-		$this->tokenHandler->method('generateToken')->willReturn('token');
559
-		$this->notifications
560
-			->method('sendRemoteShare')
561
-			->willReturn(true);
562
-
563
-		$this->rootFolder->expects($this->never())->method($this->anything());
564
-
565
-		$this->addressHandler->method('generateRemoteURL')
566
-			->willReturn('remoteurl.com');
567
-
568
-		$this->contactsManager->expects($this->any())
569
-			->method('search')
570
-			->willReturn([]);
571
-
572
-		$share = $this->shareManager->newShare();
573
-		$share->setSharedWith('[email protected]')
574
-			->setSharedBy('sharedBy')
575
-			->setShareOwner('shareOwner')
576
-			->setPermissions(19)
577
-			->setShareType(IShare::TYPE_REMOTE)
578
-			->setNode($node);
579
-		$this->provider->create($share);
580
-
581
-		$node2 = $this->getMockBuilder(File::class)->getMock();
582
-		$node2->method('getId')->willReturn(43);
583
-		$node2->method('getName')->willReturn('myOtherFile');
584
-
585
-		$share2 = $this->shareManager->newShare();
586
-		$share2->setSharedWith('[email protected]')
587
-			->setSharedBy('sharedBy')
588
-			->setShareOwner('shareOwner')
589
-			->setPermissions(19)
590
-			->setShareType(IShare::TYPE_REMOTE)
591
-			->setNode($node2);
592
-		$this->provider->create($share2);
593
-
594
-		$shares = $this->provider->getSharesBy('sharedBy', IShare::TYPE_REMOTE, $node2, false, -1, 0);
595
-
596
-		$this->assertCount(1, $shares);
597
-		$this->assertEquals(43, $shares[0]->getNodeId());
598
-	}
599
-
600
-	public function testGetSharedByWithReshares(): void {
601
-		$node = $this->createMock(File::class);
602
-		$node->method('getId')->willReturn(42);
603
-		$node->method('getName')->willReturn('myFile');
604
-
605
-		$this->tokenHandler->method('generateToken')->willReturn('token');
606
-		$this->notifications
607
-			->method('sendRemoteShare')
608
-			->willReturn(true);
609
-
610
-		$this->rootFolder->expects($this->never())->method($this->anything());
611
-
612
-		$this->addressHandler->method('generateRemoteURL')
613
-			->willReturn('remoteurl.com');
614
-
615
-		$this->contactsManager->expects($this->any())
616
-			->method('search')
617
-			->willReturn([]);
618
-
619
-		$share = $this->shareManager->newShare();
620
-		$share->setSharedWith('[email protected]')
621
-			->setSharedBy('shareOwner')
622
-			->setShareOwner('shareOwner')
623
-			->setPermissions(19)
624
-			->setShareType(IShare::TYPE_REMOTE)
625
-			->setNode($node);
626
-		$this->provider->create($share);
627
-
628
-		$share2 = $this->shareManager->newShare();
629
-		$share2->setSharedWith('[email protected]')
630
-			->setSharedBy('sharedBy')
631
-			->setShareOwner('shareOwner')
632
-			->setPermissions(19)
633
-			->setShareType(IShare::TYPE_REMOTE)
634
-			->setNode($node);
635
-		$this->provider->create($share2);
636
-
637
-		$shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_REMOTE, null, true, -1, 0);
638
-
639
-		$this->assertCount(2, $shares);
640
-	}
641
-
642
-	public function testGetSharedByWithLimit(): void {
643
-		$node = $this->createMock(File::class);
644
-		$node->method('getId')->willReturn(42);
645
-		$node->method('getName')->willReturn('myFile');
646
-
647
-		$this->addressHandler->expects($this->any())->method('splitUserRemote')
648
-			->willReturnCallback(function ($uid) {
649
-				if ($uid === '[email protected]') {
650
-					return ['user', 'server.com'];
651
-				}
652
-				return ['user2', 'server.com'];
653
-			});
654
-
655
-		$this->tokenHandler->method('generateToken')->willReturn('token');
656
-		$this->notifications
657
-			->method('sendRemoteShare')
658
-			->willReturn(true);
659
-
660
-		$this->rootFolder->expects($this->never())->method($this->anything());
661
-
662
-		$this->addressHandler->method('generateRemoteURL')
663
-			->willReturn('remoteurl.com');
664
-
665
-		$this->contactsManager->expects($this->any())
666
-			->method('search')
667
-			->willReturn([]);
668
-
669
-		$share = $this->shareManager->newShare();
670
-		$share->setSharedWith('[email protected]')
671
-			->setSharedBy('sharedBy')
672
-			->setShareOwner('shareOwner')
673
-			->setPermissions(19)
674
-			->setShareType(IShare::TYPE_REMOTE)
675
-			->setNode($node);
676
-		$this->provider->create($share);
677
-
678
-		$share2 = $this->shareManager->newShare();
679
-		$share2->setSharedWith('[email protected]')
680
-			->setSharedBy('sharedBy')
681
-			->setShareOwner('shareOwner')
682
-			->setPermissions(19)
683
-			->setShareType(IShare::TYPE_REMOTE)
684
-			->setNode($node);
685
-		$this->provider->create($share2);
686
-
687
-		$shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_REMOTE, null, true, 1, 1);
688
-
689
-		$this->assertCount(1, $shares);
690
-		$this->assertEquals('[email protected]', $shares[0]->getSharedWith());
691
-	}
692
-
693
-	public static function dataDeleteUser(): array {
694
-		return [
695
-			['a', 'b', 'c', 'a', true],
696
-			['a', 'b', 'c', 'b', false],
697
-			// The recipient is non local.
698
-			['a', 'b', 'c', 'c', false],
699
-			['a', 'b', 'c', 'd', false],
700
-		];
701
-	}
702
-
703
-	/**
704
-	 *
705
-	 * @param string $owner The owner of the share (uid)
706
-	 * @param string $initiator The initiator of the share (uid)
707
-	 * @param string $recipient The recipient of the share (uid/gid/pass)
708
-	 * @param string $deletedUser The user that is deleted
709
-	 * @param bool $rowDeleted Is the row deleted in this setup
710
-	 */
711
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataDeleteUser')]
712
-	public function testDeleteUser(string $owner, string $initiator, string $recipient, string $deletedUser, bool $rowDeleted): void {
713
-		$qb = $this->connection->getQueryBuilder();
714
-		$qb->insert('share')
715
-			->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))
716
-			->setValue('uid_owner', $qb->createNamedParameter($owner))
717
-			->setValue('uid_initiator', $qb->createNamedParameter($initiator))
718
-			->setValue('share_with', $qb->createNamedParameter($recipient))
719
-			->setValue('item_type', $qb->createNamedParameter('file'))
720
-			->setValue('item_source', $qb->createNamedParameter(42))
721
-			->setValue('file_source', $qb->createNamedParameter(42))
722
-			->executeStatement();
723
-
724
-		$id = $qb->getLastInsertId();
725
-
726
-		$this->provider->userDeleted($deletedUser, IShare::TYPE_REMOTE);
727
-
728
-		$qb = $this->connection->getQueryBuilder();
729
-		$qb->select('*')
730
-			->from('share')
731
-			->where(
732
-				$qb->expr()->eq('id', $qb->createNamedParameter($id))
733
-			);
734
-		$cursor = $qb->executeQuery();
735
-		$data = $cursor->fetchAll();
736
-		$cursor->closeCursor();
737
-
738
-		$this->assertCount($rowDeleted ? 0 : 1, $data);
739
-	}
740
-
741
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsOutgoingServer2serverShareEnabled')]
742
-	public function testIsOutgoingServer2serverShareEnabled(bool $internalOnly, string $isEnabled, bool $expected): void {
743
-		$this->gsConfig->expects($this->once())->method('onlyInternalFederation')
744
-			->willReturn($internalOnly);
745
-		$this->config->expects($this->any())->method('getAppValue')
746
-			->with('files_sharing', 'outgoing_server2server_share_enabled', 'yes')
747
-			->willReturn($isEnabled);
748
-
749
-		$this->assertSame($expected,
750
-			$this->provider->isOutgoingServer2serverShareEnabled()
751
-		);
752
-	}
753
-
754
-	public static function dataTestIsOutgoingServer2serverShareEnabled(): array {
755
-		return [
756
-			[false, 'yes', true],
757
-			[false, 'no', false],
758
-			[true, 'yes', false],
759
-			[true, 'no', false],
760
-		];
761
-	}
762
-
763
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsIncomingServer2serverShareEnabled')]
764
-	public function testIsIncomingServer2serverShareEnabled(bool $onlyInternal, string $isEnabled, bool $expected): void {
765
-		$this->gsConfig->expects($this->once())->method('onlyInternalFederation')
766
-			->willReturn($onlyInternal);
767
-		$this->config->expects($this->any())->method('getAppValue')
768
-			->with('files_sharing', 'incoming_server2server_share_enabled', 'yes')
769
-			->willReturn($isEnabled);
770
-
771
-		$this->assertSame($expected,
772
-			$this->provider->isIncomingServer2serverShareEnabled()
773
-		);
774
-	}
775
-
776
-	public static function dataTestIsIncomingServer2serverShareEnabled(): array {
777
-		return [
778
-			[false, 'yes', true],
779
-			[false, 'no', false],
780
-			[true, 'yes', false],
781
-			[true, 'no', false],
782
-		];
783
-	}
784
-
785
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsLookupServerQueriesEnabled')]
786
-	public function testIsLookupServerQueriesEnabled(bool $gsEnabled, string $isEnabled, bool $expected): void {
787
-		$this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled')
788
-			->willReturn($gsEnabled);
789
-		$this->config->expects($this->any())->method('getAppValue')
790
-			->with('files_sharing', 'lookupServerEnabled', 'no')
791
-			->willReturn($isEnabled);
792
-
793
-		$this->assertSame($expected,
794
-			$this->provider->isLookupServerQueriesEnabled()
795
-		);
796
-	}
797
-
798
-
799
-	public static function dataTestIsLookupServerQueriesEnabled(): array {
800
-		return [
801
-			[true, 'yes', true],
802
-			[true, 'no', true],
803
-			// TODO: reenable if we use the lookup server for non-global scale
804
-			// [false, 'yes', true],
805
-			// [false, 'no', false],
806
-			[false, 'no', false],
807
-			[false, 'yes', false],
808
-		];
809
-	}
810
-
811
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsLookupServerUploadEnabled')]
812
-	public function testIsLookupServerUploadEnabled(bool $gsEnabled, string $isEnabled, bool $expected): void {
813
-		$this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled')
814
-			->willReturn($gsEnabled);
815
-		$this->config->expects($this->any())->method('getAppValue')
816
-			->with('files_sharing', 'lookupServerUploadEnabled', 'no')
817
-			->willReturn($isEnabled);
818
-
819
-		$this->assertSame($expected,
820
-			$this->provider->isLookupServerUploadEnabled()
821
-		);
822
-	}
823
-
824
-	public static function dataTestIsLookupServerUploadEnabled(): array {
825
-		return [
826
-			[true, 'yes', false],
827
-			[true, 'no', false],
828
-			// TODO: reenable if we use the lookup server again
829
-			// [false, 'yes', true],
830
-			// [false, 'no', false],
831
-			[false, 'yes', false],
832
-			[false, 'no', false],
833
-		];
834
-	}
835
-
836
-	public function testGetSharesInFolder(): void {
837
-		$userManager = Server::get(IUserManager::class);
838
-		$rootFolder = Server::get(IRootFolder::class);
839
-
840
-		$u1 = $userManager->createUser('testFed', md5((string)time()));
841
-		$u2 = $userManager->createUser('testFed2', md5((string)time()));
842
-
843
-		$folder1 = $rootFolder->getUserFolder($u1->getUID())->newFolder('foo');
844
-		$file1 = $folder1->newFile('bar1');
845
-		$file2 = $folder1->newFile('bar2');
846
-
847
-		$this->tokenHandler->method('generateToken')->willReturn('token');
848
-		$this->notifications
849
-			->method('sendRemoteShare')
850
-			->willReturn(true);
851
-
852
-		$this->addressHandler->method('generateRemoteURL')
853
-			->willReturn('remoteurl.com');
854
-
855
-		$this->contactsManager->expects($this->any())
856
-			->method('search')
857
-			->willReturn([]);
858
-
859
-		$share1 = $this->shareManager->newShare();
860
-		$share1->setSharedWith('[email protected]')
861
-			->setSharedBy($u1->getUID())
862
-			->setShareOwner($u1->getUID())
863
-			->setPermissions(Constants::PERMISSION_READ)
864
-			->setShareType(IShare::TYPE_REMOTE)
865
-			->setNode($file1);
866
-		$this->provider->create($share1);
867
-
868
-		$share2 = $this->shareManager->newShare();
869
-		$share2->setSharedWith('[email protected]')
870
-			->setSharedBy($u2->getUID())
871
-			->setShareOwner($u1->getUID())
872
-			->setPermissions(Constants::PERMISSION_READ)
873
-			->setShareType(IShare::TYPE_REMOTE)
874
-			->setNode($file2);
875
-		$this->provider->create($share2);
876
-
877
-		$result = $this->provider->getSharesInFolder($u1->getUID(), $folder1, false);
878
-		$this->assertCount(1, $result);
879
-		$this->assertCount(1, $result[$file1->getId()]);
880
-
881
-		$result = $this->provider->getSharesInFolder($u1->getUID(), $folder1, true);
882
-		$this->assertCount(2, $result);
883
-		$this->assertCount(1, $result[$file1->getId()]);
884
-		$this->assertCount(1, $result[$file2->getId()]);
885
-
886
-		$u1->delete();
887
-		$u2->delete();
888
-	}
889
-
890
-	public function testGetAccessList(): void {
891
-		$userManager = Server::get(IUserManager::class);
892
-		$rootFolder = Server::get(IRootFolder::class);
893
-
894
-		$u1 = $userManager->createUser('testFed', md5((string)time()));
895
-
896
-		$folder1 = $rootFolder->getUserFolder($u1->getUID())->newFolder('foo');
897
-		$file1 = $folder1->newFile('bar1');
898
-
899
-		$this->tokenHandler->expects($this->exactly(2))
900
-			->method('generateToken')
901
-			->willReturnOnConsecutiveCalls('token1', 'token2');
902
-		$this->notifications->expects($this->atLeastOnce())
903
-			->method('sendRemoteShare')
904
-			->willReturn(true);
905
-
906
-		$this->contactsManager->expects($this->any())
907
-			->method('search')
908
-			->willReturn([]);
909
-
910
-		$result = $this->provider->getAccessList([$file1], true);
911
-		$this->assertEquals(['remote' => []], $result);
912
-
913
-		$result = $this->provider->getAccessList([$file1], false);
914
-		$this->assertEquals(['remote' => false], $result);
915
-
916
-		$this->addressHandler->method('generateRemoteURL')
917
-			->willReturn('remoteurl.com');
918
-
919
-		$share1 = $this->shareManager->newShare();
920
-		$share1->setSharedWith('[email protected]')
921
-			->setSharedBy($u1->getUID())
922
-			->setShareOwner($u1->getUID())
923
-			->setPermissions(Constants::PERMISSION_READ)
924
-			->setShareType(IShare::TYPE_REMOTE)
925
-			->setNode($file1);
926
-		$this->provider->create($share1);
927
-
928
-		$share2 = $this->shareManager->newShare();
929
-		$share2->setSharedWith('foobar@localhost')
930
-			->setSharedBy($u1->getUID())
931
-			->setShareOwner($u1->getUID())
932
-			->setPermissions(Constants::PERMISSION_READ)
933
-			->setShareType(IShare::TYPE_REMOTE)
934
-			->setNode($file1);
935
-		$this->provider->create($share2);
936
-
937
-		$result = $this->provider->getAccessList([$file1], true);
938
-		$this->assertEquals(['remote' => [
939
-			'[email protected]' => [
940
-				'token' => 'token1',
941
-				'node_id' => $file1->getId(),
942
-			],
943
-			'foobar@localhost' => [
944
-				'token' => 'token2',
945
-				'node_id' => $file1->getId(),
946
-			],
947
-		]], $result);
948
-
949
-		$result = $this->provider->getAccessList([$file1], false);
950
-		$this->assertEquals(['remote' => true], $result);
951
-
952
-		$u1->delete();
953
-	}
42
+    protected IDBConnection $connection;
43
+    protected AddressHandler&MockObject $addressHandler;
44
+    protected Notifications&MockObject $notifications;
45
+    protected TokenHandler&MockObject $tokenHandler;
46
+    protected IL10N $l;
47
+    protected LoggerInterface $logger;
48
+    protected IRootFolder&MockObject $rootFolder;
49
+    protected IConfig&MockObject $config;
50
+    protected IUserManager&MockObject $userManager;
51
+    protected \OCP\GlobalScale\IConfig&MockObject $gsConfig;
52
+    protected IManager $shareManager;
53
+    protected FederatedShareProvider $provider;
54
+    protected IContactsManager&MockObject $contactsManager;
55
+    private ICloudIdManager $cloudIdManager;
56
+    private ICloudFederationProviderManager&MockObject $cloudFederationProviderManager;
57
+
58
+    protected function setUp(): void {
59
+        parent::setUp();
60
+
61
+        $this->connection = Server::get(IDBConnection::class);
62
+        $this->notifications = $this->createMock(Notifications::class);
63
+        $this->tokenHandler = $this->createMock(TokenHandler::class);
64
+        $this->l = $this->createMock(IL10N::class);
65
+        $this->l->method('t')
66
+            ->willReturnCallback(function ($text, $parameters = []) {
67
+                return vsprintf($text, $parameters);
68
+            });
69
+        $this->logger = $this->createMock(LoggerInterface::class);
70
+        $this->rootFolder = $this->createMock(IRootFolder::class);
71
+        $this->config = $this->createMock(IConfig::class);
72
+        $this->userManager = $this->createMock(IUserManager::class);
73
+        //$this->addressHandler = new AddressHandler(\OC::$server->getURLGenerator(), $this->l);
74
+        $this->addressHandler = $this->createMock(AddressHandler::class);
75
+        $this->contactsManager = $this->createMock(IContactsManager::class);
76
+        $this->cloudIdManager = new CloudIdManager(
77
+            $this->contactsManager,
78
+            $this->createMock(IURLGenerator::class),
79
+            $this->userManager,
80
+            $this->createMock(ICacheFactory::class),
81
+            $this->createMock(IEventDispatcher::class)
82
+        );
83
+        $this->gsConfig = $this->createMock(\OCP\GlobalScale\IConfig::class);
84
+
85
+        $this->userManager->expects($this->any())->method('userExists')->willReturn(true);
86
+
87
+        $this->cloudFederationProviderManager = $this->createMock(ICloudFederationProviderManager::class);
88
+
89
+        $this->provider = new FederatedShareProvider(
90
+            $this->connection,
91
+            $this->addressHandler,
92
+            $this->notifications,
93
+            $this->tokenHandler,
94
+            $this->l,
95
+            $this->rootFolder,
96
+            $this->config,
97
+            $this->userManager,
98
+            $this->cloudIdManager,
99
+            $this->gsConfig,
100
+            $this->cloudFederationProviderManager,
101
+            $this->logger,
102
+        );
103
+
104
+        $this->shareManager = Server::get(IManager::class);
105
+    }
106
+
107
+    protected function tearDown(): void {
108
+        $this->connection->getQueryBuilder()->delete('share')->executeStatement();
109
+
110
+        parent::tearDown();
111
+    }
112
+
113
+    public static function dataTestCreate(): array {
114
+        return [
115
+            [null, null],
116
+            [new \DateTime('2020-03-01T01:02:03'), '2020-03-01 01:02:03'],
117
+        ];
118
+    }
119
+
120
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestCreate')]
121
+    public function testCreate(?\DateTime $expirationDate, ?string $expectedDataDate): void {
122
+        $share = $this->shareManager->newShare();
123
+
124
+        /** @var File&MockObject $node */
125
+        $node = $this->createMock(File::class);
126
+        $node->method('getId')->willReturn(42);
127
+        $node->method('getName')->willReturn('myFile');
128
+
129
+        $share->setSharedWith('[email protected]')
130
+            ->setSharedBy('sharedBy')
131
+            ->setShareOwner('shareOwner')
132
+            ->setPermissions(19)
133
+            ->setShareType(IShare::TYPE_REMOTE)
134
+            ->setExpirationDate($expirationDate)
135
+            ->setNode($node);
136
+
137
+        $this->tokenHandler->method('generateToken')->willReturn('token');
138
+
139
+        $this->addressHandler->expects($this->any())->method('generateRemoteURL')
140
+            ->willReturn('http://localhost/');
141
+        $this->addressHandler->expects($this->any())->method('splitUserRemote')
142
+            ->willReturn(['user', 'server.com']);
143
+
144
+        $this->notifications->expects($this->once())
145
+            ->method('sendRemoteShare')
146
+            ->with(
147
+                $this->equalTo('token'),
148
+                $this->equalTo('[email protected]'),
149
+                $this->equalTo('myFile'),
150
+                $this->anything(),
151
+                'shareOwner',
152
+                'shareOwner@http://localhost',
153
+                'sharedBy',
154
+                'sharedBy@http://localhost'
155
+            )
156
+            ->willReturn(true);
157
+
158
+        $this->rootFolder->expects($this->never())->method($this->anything());
159
+
160
+        $this->contactsManager->expects($this->any())
161
+            ->method('search')
162
+            ->willReturn([]);
163
+
164
+        $share = $this->provider->create($share);
165
+
166
+        $qb = $this->connection->getQueryBuilder();
167
+        $stmt = $qb->select('*')
168
+            ->from('share')
169
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
170
+            ->executeQuery();
171
+
172
+        $data = $stmt->fetch();
173
+        $stmt->closeCursor();
174
+
175
+        $expected = [
176
+            'share_type' => IShare::TYPE_REMOTE,
177
+            'share_with' => '[email protected]',
178
+            'uid_owner' => 'shareOwner',
179
+            'uid_initiator' => 'sharedBy',
180
+            'item_type' => 'file',
181
+            'item_source' => 42,
182
+            'file_source' => 42,
183
+            'permissions' => 19,
184
+            'accepted' => 0,
185
+            'token' => 'token',
186
+            'expiration' => $expectedDataDate,
187
+        ];
188
+        foreach (array_keys($expected) as $key) {
189
+            $this->assertEquals($expected[$key], $data[$key], "Assert that value for key '$key' is the same");
190
+        }
191
+
192
+        $this->assertEquals($data['id'], $share->getId());
193
+        $this->assertEquals(IShare::TYPE_REMOTE, $share->getShareType());
194
+        $this->assertEquals('[email protected]', $share->getSharedWith());
195
+        $this->assertEquals('sharedBy', $share->getSharedBy());
196
+        $this->assertEquals('shareOwner', $share->getShareOwner());
197
+        $this->assertEquals('file', $share->getNodeType());
198
+        $this->assertEquals(42, $share->getNodeId());
199
+        $this->assertEquals(19, $share->getPermissions());
200
+        $this->assertEquals('token', $share->getToken());
201
+        $this->assertEquals($expirationDate, $share->getExpirationDate());
202
+    }
203
+
204
+    public function testCreateCouldNotFindServer(): void {
205
+        $share = $this->shareManager->newShare();
206
+
207
+        $node = $this->createMock(File::class);
208
+        $node->method('getId')->willReturn(42);
209
+        $node->method('getName')->willReturn('myFile');
210
+
211
+        $share->setSharedWith('[email protected]')
212
+            ->setSharedBy('sharedBy')
213
+            ->setShareOwner('shareOwner')
214
+            ->setPermissions(19)
215
+            ->setShareType(IShare::TYPE_REMOTE)
216
+            ->setNode($node);
217
+
218
+        $this->tokenHandler->method('generateToken')->willReturn('token');
219
+
220
+        $this->addressHandler->expects($this->any())->method('generateRemoteURL')
221
+            ->willReturn('http://localhost/');
222
+        $this->addressHandler->expects($this->any())->method('splitUserRemote')
223
+            ->willReturn(['user', 'server.com']);
224
+
225
+        $this->notifications->expects($this->once())
226
+            ->method('sendRemoteShare')
227
+            ->with(
228
+                $this->equalTo('token'),
229
+                $this->equalTo('[email protected]'),
230
+                $this->equalTo('myFile'),
231
+                $this->anything(),
232
+                'shareOwner',
233
+                'shareOwner@http://localhost',
234
+                'sharedBy',
235
+                'sharedBy@http://localhost'
236
+            )->willReturn(false);
237
+
238
+        $this->rootFolder->method('getById')
239
+            ->with('42')
240
+            ->willReturn([$node]);
241
+
242
+        $this->contactsManager->expects($this->any())
243
+            ->method('search')
244
+            ->willReturn([]);
245
+
246
+        try {
247
+            $share = $this->provider->create($share);
248
+            $this->fail();
249
+        } catch (\Exception $e) {
250
+            $this->assertEquals('Sharing myFile failed, could not find [email protected], maybe the server is currently unreachable or uses a self-signed certificate.', $e->getMessage());
251
+        }
252
+
253
+        $qb = $this->connection->getQueryBuilder();
254
+        $stmt = $qb->select('*')
255
+            ->from('share')
256
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
257
+            ->executeQuery();
258
+
259
+        $data = $stmt->fetch();
260
+        $stmt->closeCursor();
261
+
262
+        $this->assertFalse($data);
263
+    }
264
+
265
+    public function testCreateException(): void {
266
+        $share = $this->shareManager->newShare();
267
+
268
+        $node = $this->createMock(File::class);
269
+        $node->method('getId')->willReturn(42);
270
+        $node->method('getName')->willReturn('myFile');
271
+
272
+        $share->setSharedWith('[email protected]')
273
+            ->setSharedBy('sharedBy')
274
+            ->setShareOwner('shareOwner')
275
+            ->setPermissions(19)
276
+            ->setShareType(IShare::TYPE_REMOTE)
277
+            ->setNode($node);
278
+
279
+        $this->tokenHandler->method('generateToken')->willReturn('token');
280
+
281
+        $this->addressHandler->expects($this->any())->method('generateRemoteURL')
282
+            ->willReturn('http://localhost/');
283
+        $this->addressHandler->expects($this->any())->method('splitUserRemote')
284
+            ->willReturn(['user', 'server.com']);
285
+
286
+        $this->notifications->expects($this->once())
287
+            ->method('sendRemoteShare')
288
+            ->with(
289
+                $this->equalTo('token'),
290
+                $this->equalTo('[email protected]'),
291
+                $this->equalTo('myFile'),
292
+                $this->anything(),
293
+                'shareOwner',
294
+                'shareOwner@http://localhost',
295
+                'sharedBy',
296
+                'sharedBy@http://localhost'
297
+            )->willThrowException(new \Exception('dummy'));
298
+
299
+        $this->rootFolder->method('getById')
300
+            ->with('42')
301
+            ->willReturn([$node]);
302
+
303
+        $this->contactsManager->expects($this->any())
304
+            ->method('search')
305
+            ->willReturn([]);
306
+
307
+        try {
308
+            $share = $this->provider->create($share);
309
+            $this->fail();
310
+        } catch (\Exception $e) {
311
+            $this->assertEquals('Sharing myFile failed, could not find [email protected], maybe the server is currently unreachable or uses a self-signed certificate.', $e->getMessage());
312
+        }
313
+
314
+        $qb = $this->connection->getQueryBuilder();
315
+        $stmt = $qb->select('*')
316
+            ->from('share')
317
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
318
+            ->executeQuery();
319
+
320
+        $data = $stmt->fetch();
321
+        $stmt->closeCursor();
322
+
323
+        $this->assertFalse($data);
324
+    }
325
+
326
+    public function testCreateShareWithSelf(): void {
327
+        $share = $this->shareManager->newShare();
328
+
329
+        $node = $this->createMock(File::class);
330
+        $node->method('getId')->willReturn(42);
331
+        $node->method('getName')->willReturn('myFile');
332
+
333
+        $this->addressHandler->expects($this->any())->method('compareAddresses')
334
+            ->willReturn(true);
335
+
336
+        $shareWith = 'sharedBy@localhost';
337
+
338
+        $share->setSharedWith($shareWith)
339
+            ->setSharedBy('sharedBy')
340
+            ->setShareOwner('shareOwner')
341
+            ->setPermissions(19)
342
+            ->setNode($node);
343
+
344
+        $this->contactsManager->expects($this->any())
345
+            ->method('search')
346
+            ->willReturn([]);
347
+
348
+        $this->rootFolder->expects($this->never())->method($this->anything());
349
+
350
+        try {
351
+            $share = $this->provider->create($share);
352
+            $this->fail();
353
+        } catch (\Exception $e) {
354
+            $this->assertEquals('Not allowed to create a federated share to the same account', $e->getMessage());
355
+        }
356
+
357
+        $qb = $this->connection->getQueryBuilder();
358
+        $stmt = $qb->select('*')
359
+            ->from('share')
360
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
361
+            ->executeQuery();
362
+
363
+        $data = $stmt->fetch();
364
+        $stmt->closeCursor();
365
+
366
+        $this->assertFalse($data);
367
+    }
368
+
369
+    public function testCreateAlreadyShared(): void {
370
+        $share = $this->shareManager->newShare();
371
+
372
+        $node = $this->createMock(File::class);
373
+        $node->method('getId')->willReturn(42);
374
+        $node->method('getName')->willReturn('myFile');
375
+
376
+
377
+        $this->addressHandler->expects($this->any())->method('splitUserRemote')
378
+            ->willReturn(['user', 'server.com']);
379
+
380
+        $share->setSharedWith('[email protected]')
381
+            ->setSharedBy('sharedBy')
382
+            ->setShareOwner('shareOwner')
383
+            ->setPermissions(19)
384
+            ->setShareType(IShare::TYPE_REMOTE)
385
+            ->setNode($node);
386
+
387
+        $this->tokenHandler->method('generateToken')->willReturn('token');
388
+
389
+        $this->addressHandler->expects($this->any())->method('generateRemoteURL')
390
+            ->willReturn('http://localhost/');
391
+
392
+        $this->notifications->expects($this->once())
393
+            ->method('sendRemoteShare')
394
+            ->with(
395
+                $this->equalTo('token'),
396
+                $this->equalTo('[email protected]'),
397
+                $this->equalTo('myFile'),
398
+                $this->anything(),
399
+                'shareOwner',
400
+                'shareOwner@http://localhost',
401
+                'sharedBy',
402
+                'sharedBy@http://localhost'
403
+            )->willReturn(true);
404
+
405
+        $this->rootFolder->expects($this->never())->method($this->anything());
406
+
407
+        $this->contactsManager->expects($this->any())
408
+            ->method('search')
409
+            ->willReturn([]);
410
+
411
+        $this->provider->create($share);
412
+
413
+        try {
414
+            $this->provider->create($share);
415
+        } catch (\Exception $e) {
416
+            $this->assertEquals('Sharing myFile failed, because this item is already shared with the account [email protected]', $e->getMessage());
417
+        }
418
+    }
419
+
420
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestUpdate')]
421
+    public function testUpdate(string $owner, string $sharedBy, ?\DateTime $expirationDate): void {
422
+        $this->provider = $this->getMockBuilder(FederatedShareProvider::class)
423
+            ->setConstructorArgs(
424
+                [
425
+                    $this->connection,
426
+                    $this->addressHandler,
427
+                    $this->notifications,
428
+                    $this->tokenHandler,
429
+                    $this->l,
430
+                    $this->rootFolder,
431
+                    $this->config,
432
+                    $this->userManager,
433
+                    $this->cloudIdManager,
434
+                    $this->gsConfig,
435
+                    $this->cloudFederationProviderManager,
436
+                    $this->logger,
437
+                ]
438
+            )
439
+            ->onlyMethods(['sendPermissionUpdate'])
440
+            ->getMock();
441
+
442
+        $share = $this->shareManager->newShare();
443
+
444
+        $node = $this->createMock(File::class);
445
+        $node->method('getId')->willReturn(42);
446
+        $node->method('getName')->willReturn('myFile');
447
+
448
+        $this->addressHandler->expects($this->any())->method('splitUserRemote')
449
+            ->willReturn(['user', 'server.com']);
450
+
451
+        $share->setSharedWith('[email protected]')
452
+            ->setSharedBy($sharedBy)
453
+            ->setShareOwner($owner)
454
+            ->setPermissions(19)
455
+            ->setShareType(IShare::TYPE_REMOTE)
456
+            ->setExpirationDate(new \DateTime('2019-02-01T01:02:03'))
457
+            ->setNode($node);
458
+
459
+        $this->tokenHandler->method('generateToken')->willReturn('token');
460
+        $this->addressHandler->expects($this->any())->method('generateRemoteURL')
461
+            ->willReturn('http://localhost/');
462
+
463
+        $this->notifications->expects($this->once())
464
+            ->method('sendRemoteShare')
465
+            ->with(
466
+                $this->equalTo('token'),
467
+                $this->equalTo('[email protected]'),
468
+                $this->equalTo('myFile'),
469
+                $this->anything(),
470
+                $owner,
471
+                $owner . '@http://localhost',
472
+                $sharedBy,
473
+                $sharedBy . '@http://localhost'
474
+            )->willReturn(true);
475
+
476
+        if ($owner === $sharedBy) {
477
+            $this->provider->expects($this->never())->method('sendPermissionUpdate');
478
+        } else {
479
+            $this->provider->expects($this->once())->method('sendPermissionUpdate');
480
+        }
481
+
482
+        $this->rootFolder->expects($this->never())->method($this->anything());
483
+
484
+        $this->contactsManager->expects($this->any())
485
+            ->method('search')
486
+            ->willReturn([]);
487
+
488
+        $share = $this->provider->create($share);
489
+
490
+        $share->setPermissions(1);
491
+        $share->setExpirationDate($expirationDate);
492
+        $this->provider->update($share);
493
+
494
+        $share = $this->provider->getShareById($share->getId());
495
+
496
+        $this->assertEquals(1, $share->getPermissions());
497
+        $this->assertEquals($expirationDate, $share->getExpirationDate());
498
+    }
499
+
500
+    public static function dataTestUpdate(): array {
501
+        return [
502
+            ['sharedBy', 'shareOwner', new \DateTime('2020-03-01T01:02:03')],
503
+            ['shareOwner', 'shareOwner', null],
504
+        ];
505
+    }
506
+
507
+    public function testGetSharedBy(): void {
508
+        $node = $this->createMock(File::class);
509
+        $node->method('getId')->willReturn(42);
510
+        $node->method('getName')->willReturn('myFile');
511
+
512
+        $this->addressHandler->expects($this->never())->method('splitUserRemote');
513
+
514
+        $this->addressHandler->method('generateRemoteURL')
515
+            ->willReturn('remoteurl.com');
516
+
517
+        $this->tokenHandler->method('generateToken')->willReturn('token');
518
+        $this->notifications
519
+            ->method('sendRemoteShare')
520
+            ->willReturn(true);
521
+
522
+        $this->rootFolder->expects($this->never())->method($this->anything());
523
+
524
+        $this->contactsManager->expects($this->any())
525
+            ->method('search')
526
+            ->willReturn([]);
527
+
528
+        $share = $this->shareManager->newShare();
529
+        $share->setSharedWith('[email protected]')
530
+            ->setSharedBy('sharedBy')
531
+            ->setShareOwner('shareOwner')
532
+            ->setPermissions(19)
533
+            ->setShareType(IShare::TYPE_REMOTE)
534
+            ->setNode($node);
535
+        $this->provider->create($share);
536
+
537
+        $share2 = $this->shareManager->newShare();
538
+        $share2->setSharedWith('[email protected]')
539
+            ->setSharedBy('sharedBy2')
540
+            ->setShareOwner('shareOwner')
541
+            ->setPermissions(19)
542
+            ->setShareType(IShare::TYPE_REMOTE)
543
+            ->setNode($node);
544
+        $this->provider->create($share2);
545
+
546
+        $shares = $this->provider->getSharesBy('sharedBy', IShare::TYPE_REMOTE, null, false, -1, 0);
547
+
548
+        $this->assertCount(1, $shares);
549
+        $this->assertEquals('[email protected]', $shares[0]->getSharedWith());
550
+        $this->assertEquals('sharedBy', $shares[0]->getSharedBy());
551
+    }
552
+
553
+    public function testGetSharedByWithNode(): void {
554
+        $node = $this->createMock(File::class);
555
+        $node->method('getId')->willReturn(42);
556
+        $node->method('getName')->willReturn('myFile');
557
+
558
+        $this->tokenHandler->method('generateToken')->willReturn('token');
559
+        $this->notifications
560
+            ->method('sendRemoteShare')
561
+            ->willReturn(true);
562
+
563
+        $this->rootFolder->expects($this->never())->method($this->anything());
564
+
565
+        $this->addressHandler->method('generateRemoteURL')
566
+            ->willReturn('remoteurl.com');
567
+
568
+        $this->contactsManager->expects($this->any())
569
+            ->method('search')
570
+            ->willReturn([]);
571
+
572
+        $share = $this->shareManager->newShare();
573
+        $share->setSharedWith('[email protected]')
574
+            ->setSharedBy('sharedBy')
575
+            ->setShareOwner('shareOwner')
576
+            ->setPermissions(19)
577
+            ->setShareType(IShare::TYPE_REMOTE)
578
+            ->setNode($node);
579
+        $this->provider->create($share);
580
+
581
+        $node2 = $this->getMockBuilder(File::class)->getMock();
582
+        $node2->method('getId')->willReturn(43);
583
+        $node2->method('getName')->willReturn('myOtherFile');
584
+
585
+        $share2 = $this->shareManager->newShare();
586
+        $share2->setSharedWith('[email protected]')
587
+            ->setSharedBy('sharedBy')
588
+            ->setShareOwner('shareOwner')
589
+            ->setPermissions(19)
590
+            ->setShareType(IShare::TYPE_REMOTE)
591
+            ->setNode($node2);
592
+        $this->provider->create($share2);
593
+
594
+        $shares = $this->provider->getSharesBy('sharedBy', IShare::TYPE_REMOTE, $node2, false, -1, 0);
595
+
596
+        $this->assertCount(1, $shares);
597
+        $this->assertEquals(43, $shares[0]->getNodeId());
598
+    }
599
+
600
+    public function testGetSharedByWithReshares(): void {
601
+        $node = $this->createMock(File::class);
602
+        $node->method('getId')->willReturn(42);
603
+        $node->method('getName')->willReturn('myFile');
604
+
605
+        $this->tokenHandler->method('generateToken')->willReturn('token');
606
+        $this->notifications
607
+            ->method('sendRemoteShare')
608
+            ->willReturn(true);
609
+
610
+        $this->rootFolder->expects($this->never())->method($this->anything());
611
+
612
+        $this->addressHandler->method('generateRemoteURL')
613
+            ->willReturn('remoteurl.com');
614
+
615
+        $this->contactsManager->expects($this->any())
616
+            ->method('search')
617
+            ->willReturn([]);
618
+
619
+        $share = $this->shareManager->newShare();
620
+        $share->setSharedWith('[email protected]')
621
+            ->setSharedBy('shareOwner')
622
+            ->setShareOwner('shareOwner')
623
+            ->setPermissions(19)
624
+            ->setShareType(IShare::TYPE_REMOTE)
625
+            ->setNode($node);
626
+        $this->provider->create($share);
627
+
628
+        $share2 = $this->shareManager->newShare();
629
+        $share2->setSharedWith('[email protected]')
630
+            ->setSharedBy('sharedBy')
631
+            ->setShareOwner('shareOwner')
632
+            ->setPermissions(19)
633
+            ->setShareType(IShare::TYPE_REMOTE)
634
+            ->setNode($node);
635
+        $this->provider->create($share2);
636
+
637
+        $shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_REMOTE, null, true, -1, 0);
638
+
639
+        $this->assertCount(2, $shares);
640
+    }
641
+
642
+    public function testGetSharedByWithLimit(): void {
643
+        $node = $this->createMock(File::class);
644
+        $node->method('getId')->willReturn(42);
645
+        $node->method('getName')->willReturn('myFile');
646
+
647
+        $this->addressHandler->expects($this->any())->method('splitUserRemote')
648
+            ->willReturnCallback(function ($uid) {
649
+                if ($uid === '[email protected]') {
650
+                    return ['user', 'server.com'];
651
+                }
652
+                return ['user2', 'server.com'];
653
+            });
654
+
655
+        $this->tokenHandler->method('generateToken')->willReturn('token');
656
+        $this->notifications
657
+            ->method('sendRemoteShare')
658
+            ->willReturn(true);
659
+
660
+        $this->rootFolder->expects($this->never())->method($this->anything());
661
+
662
+        $this->addressHandler->method('generateRemoteURL')
663
+            ->willReturn('remoteurl.com');
664
+
665
+        $this->contactsManager->expects($this->any())
666
+            ->method('search')
667
+            ->willReturn([]);
668
+
669
+        $share = $this->shareManager->newShare();
670
+        $share->setSharedWith('[email protected]')
671
+            ->setSharedBy('sharedBy')
672
+            ->setShareOwner('shareOwner')
673
+            ->setPermissions(19)
674
+            ->setShareType(IShare::TYPE_REMOTE)
675
+            ->setNode($node);
676
+        $this->provider->create($share);
677
+
678
+        $share2 = $this->shareManager->newShare();
679
+        $share2->setSharedWith('[email protected]')
680
+            ->setSharedBy('sharedBy')
681
+            ->setShareOwner('shareOwner')
682
+            ->setPermissions(19)
683
+            ->setShareType(IShare::TYPE_REMOTE)
684
+            ->setNode($node);
685
+        $this->provider->create($share2);
686
+
687
+        $shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_REMOTE, null, true, 1, 1);
688
+
689
+        $this->assertCount(1, $shares);
690
+        $this->assertEquals('[email protected]', $shares[0]->getSharedWith());
691
+    }
692
+
693
+    public static function dataDeleteUser(): array {
694
+        return [
695
+            ['a', 'b', 'c', 'a', true],
696
+            ['a', 'b', 'c', 'b', false],
697
+            // The recipient is non local.
698
+            ['a', 'b', 'c', 'c', false],
699
+            ['a', 'b', 'c', 'd', false],
700
+        ];
701
+    }
702
+
703
+    /**
704
+     *
705
+     * @param string $owner The owner of the share (uid)
706
+     * @param string $initiator The initiator of the share (uid)
707
+     * @param string $recipient The recipient of the share (uid/gid/pass)
708
+     * @param string $deletedUser The user that is deleted
709
+     * @param bool $rowDeleted Is the row deleted in this setup
710
+     */
711
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataDeleteUser')]
712
+    public function testDeleteUser(string $owner, string $initiator, string $recipient, string $deletedUser, bool $rowDeleted): void {
713
+        $qb = $this->connection->getQueryBuilder();
714
+        $qb->insert('share')
715
+            ->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE))
716
+            ->setValue('uid_owner', $qb->createNamedParameter($owner))
717
+            ->setValue('uid_initiator', $qb->createNamedParameter($initiator))
718
+            ->setValue('share_with', $qb->createNamedParameter($recipient))
719
+            ->setValue('item_type', $qb->createNamedParameter('file'))
720
+            ->setValue('item_source', $qb->createNamedParameter(42))
721
+            ->setValue('file_source', $qb->createNamedParameter(42))
722
+            ->executeStatement();
723
+
724
+        $id = $qb->getLastInsertId();
725
+
726
+        $this->provider->userDeleted($deletedUser, IShare::TYPE_REMOTE);
727
+
728
+        $qb = $this->connection->getQueryBuilder();
729
+        $qb->select('*')
730
+            ->from('share')
731
+            ->where(
732
+                $qb->expr()->eq('id', $qb->createNamedParameter($id))
733
+            );
734
+        $cursor = $qb->executeQuery();
735
+        $data = $cursor->fetchAll();
736
+        $cursor->closeCursor();
737
+
738
+        $this->assertCount($rowDeleted ? 0 : 1, $data);
739
+    }
740
+
741
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsOutgoingServer2serverShareEnabled')]
742
+    public function testIsOutgoingServer2serverShareEnabled(bool $internalOnly, string $isEnabled, bool $expected): void {
743
+        $this->gsConfig->expects($this->once())->method('onlyInternalFederation')
744
+            ->willReturn($internalOnly);
745
+        $this->config->expects($this->any())->method('getAppValue')
746
+            ->with('files_sharing', 'outgoing_server2server_share_enabled', 'yes')
747
+            ->willReturn($isEnabled);
748
+
749
+        $this->assertSame($expected,
750
+            $this->provider->isOutgoingServer2serverShareEnabled()
751
+        );
752
+    }
753
+
754
+    public static function dataTestIsOutgoingServer2serverShareEnabled(): array {
755
+        return [
756
+            [false, 'yes', true],
757
+            [false, 'no', false],
758
+            [true, 'yes', false],
759
+            [true, 'no', false],
760
+        ];
761
+    }
762
+
763
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsIncomingServer2serverShareEnabled')]
764
+    public function testIsIncomingServer2serverShareEnabled(bool $onlyInternal, string $isEnabled, bool $expected): void {
765
+        $this->gsConfig->expects($this->once())->method('onlyInternalFederation')
766
+            ->willReturn($onlyInternal);
767
+        $this->config->expects($this->any())->method('getAppValue')
768
+            ->with('files_sharing', 'incoming_server2server_share_enabled', 'yes')
769
+            ->willReturn($isEnabled);
770
+
771
+        $this->assertSame($expected,
772
+            $this->provider->isIncomingServer2serverShareEnabled()
773
+        );
774
+    }
775
+
776
+    public static function dataTestIsIncomingServer2serverShareEnabled(): array {
777
+        return [
778
+            [false, 'yes', true],
779
+            [false, 'no', false],
780
+            [true, 'yes', false],
781
+            [true, 'no', false],
782
+        ];
783
+    }
784
+
785
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsLookupServerQueriesEnabled')]
786
+    public function testIsLookupServerQueriesEnabled(bool $gsEnabled, string $isEnabled, bool $expected): void {
787
+        $this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled')
788
+            ->willReturn($gsEnabled);
789
+        $this->config->expects($this->any())->method('getAppValue')
790
+            ->with('files_sharing', 'lookupServerEnabled', 'no')
791
+            ->willReturn($isEnabled);
792
+
793
+        $this->assertSame($expected,
794
+            $this->provider->isLookupServerQueriesEnabled()
795
+        );
796
+    }
797
+
798
+
799
+    public static function dataTestIsLookupServerQueriesEnabled(): array {
800
+        return [
801
+            [true, 'yes', true],
802
+            [true, 'no', true],
803
+            // TODO: reenable if we use the lookup server for non-global scale
804
+            // [false, 'yes', true],
805
+            // [false, 'no', false],
806
+            [false, 'no', false],
807
+            [false, 'yes', false],
808
+        ];
809
+    }
810
+
811
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsLookupServerUploadEnabled')]
812
+    public function testIsLookupServerUploadEnabled(bool $gsEnabled, string $isEnabled, bool $expected): void {
813
+        $this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled')
814
+            ->willReturn($gsEnabled);
815
+        $this->config->expects($this->any())->method('getAppValue')
816
+            ->with('files_sharing', 'lookupServerUploadEnabled', 'no')
817
+            ->willReturn($isEnabled);
818
+
819
+        $this->assertSame($expected,
820
+            $this->provider->isLookupServerUploadEnabled()
821
+        );
822
+    }
823
+
824
+    public static function dataTestIsLookupServerUploadEnabled(): array {
825
+        return [
826
+            [true, 'yes', false],
827
+            [true, 'no', false],
828
+            // TODO: reenable if we use the lookup server again
829
+            // [false, 'yes', true],
830
+            // [false, 'no', false],
831
+            [false, 'yes', false],
832
+            [false, 'no', false],
833
+        ];
834
+    }
835
+
836
+    public function testGetSharesInFolder(): void {
837
+        $userManager = Server::get(IUserManager::class);
838
+        $rootFolder = Server::get(IRootFolder::class);
839
+
840
+        $u1 = $userManager->createUser('testFed', md5((string)time()));
841
+        $u2 = $userManager->createUser('testFed2', md5((string)time()));
842
+
843
+        $folder1 = $rootFolder->getUserFolder($u1->getUID())->newFolder('foo');
844
+        $file1 = $folder1->newFile('bar1');
845
+        $file2 = $folder1->newFile('bar2');
846
+
847
+        $this->tokenHandler->method('generateToken')->willReturn('token');
848
+        $this->notifications
849
+            ->method('sendRemoteShare')
850
+            ->willReturn(true);
851
+
852
+        $this->addressHandler->method('generateRemoteURL')
853
+            ->willReturn('remoteurl.com');
854
+
855
+        $this->contactsManager->expects($this->any())
856
+            ->method('search')
857
+            ->willReturn([]);
858
+
859
+        $share1 = $this->shareManager->newShare();
860
+        $share1->setSharedWith('[email protected]')
861
+            ->setSharedBy($u1->getUID())
862
+            ->setShareOwner($u1->getUID())
863
+            ->setPermissions(Constants::PERMISSION_READ)
864
+            ->setShareType(IShare::TYPE_REMOTE)
865
+            ->setNode($file1);
866
+        $this->provider->create($share1);
867
+
868
+        $share2 = $this->shareManager->newShare();
869
+        $share2->setSharedWith('[email protected]')
870
+            ->setSharedBy($u2->getUID())
871
+            ->setShareOwner($u1->getUID())
872
+            ->setPermissions(Constants::PERMISSION_READ)
873
+            ->setShareType(IShare::TYPE_REMOTE)
874
+            ->setNode($file2);
875
+        $this->provider->create($share2);
876
+
877
+        $result = $this->provider->getSharesInFolder($u1->getUID(), $folder1, false);
878
+        $this->assertCount(1, $result);
879
+        $this->assertCount(1, $result[$file1->getId()]);
880
+
881
+        $result = $this->provider->getSharesInFolder($u1->getUID(), $folder1, true);
882
+        $this->assertCount(2, $result);
883
+        $this->assertCount(1, $result[$file1->getId()]);
884
+        $this->assertCount(1, $result[$file2->getId()]);
885
+
886
+        $u1->delete();
887
+        $u2->delete();
888
+    }
889
+
890
+    public function testGetAccessList(): void {
891
+        $userManager = Server::get(IUserManager::class);
892
+        $rootFolder = Server::get(IRootFolder::class);
893
+
894
+        $u1 = $userManager->createUser('testFed', md5((string)time()));
895
+
896
+        $folder1 = $rootFolder->getUserFolder($u1->getUID())->newFolder('foo');
897
+        $file1 = $folder1->newFile('bar1');
898
+
899
+        $this->tokenHandler->expects($this->exactly(2))
900
+            ->method('generateToken')
901
+            ->willReturnOnConsecutiveCalls('token1', 'token2');
902
+        $this->notifications->expects($this->atLeastOnce())
903
+            ->method('sendRemoteShare')
904
+            ->willReturn(true);
905
+
906
+        $this->contactsManager->expects($this->any())
907
+            ->method('search')
908
+            ->willReturn([]);
909
+
910
+        $result = $this->provider->getAccessList([$file1], true);
911
+        $this->assertEquals(['remote' => []], $result);
912
+
913
+        $result = $this->provider->getAccessList([$file1], false);
914
+        $this->assertEquals(['remote' => false], $result);
915
+
916
+        $this->addressHandler->method('generateRemoteURL')
917
+            ->willReturn('remoteurl.com');
918
+
919
+        $share1 = $this->shareManager->newShare();
920
+        $share1->setSharedWith('[email protected]')
921
+            ->setSharedBy($u1->getUID())
922
+            ->setShareOwner($u1->getUID())
923
+            ->setPermissions(Constants::PERMISSION_READ)
924
+            ->setShareType(IShare::TYPE_REMOTE)
925
+            ->setNode($file1);
926
+        $this->provider->create($share1);
927
+
928
+        $share2 = $this->shareManager->newShare();
929
+        $share2->setSharedWith('foobar@localhost')
930
+            ->setSharedBy($u1->getUID())
931
+            ->setShareOwner($u1->getUID())
932
+            ->setPermissions(Constants::PERMISSION_READ)
933
+            ->setShareType(IShare::TYPE_REMOTE)
934
+            ->setNode($file1);
935
+        $this->provider->create($share2);
936
+
937
+        $result = $this->provider->getAccessList([$file1], true);
938
+        $this->assertEquals(['remote' => [
939
+            '[email protected]' => [
940
+                'token' => 'token1',
941
+                'node_id' => $file1->getId(),
942
+            ],
943
+            'foobar@localhost' => [
944
+                'token' => 'token2',
945
+                'node_id' => $file1->getId(),
946
+            ],
947
+        ]], $result);
948
+
949
+        $result = $this->provider->getAccessList([$file1], false);
950
+        $this->assertEquals(['remote' => true], $result);
951
+
952
+        $u1->delete();
953
+    }
954 954
 }
Please login to merge, or discard this patch.
federatedfilesharing/tests/Controller/MountPublicLinkControllerTest.php 1 patch
Indentation   +122 added lines, -122 removed lines patch added patch discarded remove patch
@@ -33,138 +33,138 @@
 block discarded – undo
33 33
 use Psr\Log\LoggerInterface;
34 34
 
35 35
 class MountPublicLinkControllerTest extends \Test\TestCase {
36
-	protected IContactsManager&MockObject $contactsManager;
37
-	private IRequest&MockObject $request;
38
-	private FederatedShareProvider&MockObject $federatedShareProvider;
39
-	private IManager&MockObject $shareManager;
40
-	private AddressHandler&MockObject $addressHandler;
41
-	private IRootFolder&MockObject $rootFolder;
42
-	private IUserManager&MockObject $userManager;
43
-	private ISession&MockObject $session;
44
-	private IL10N&MockObject $l10n;
45
-	private IUserSession&MockObject $userSession;
46
-	private IClientService&MockObject $clientService;
47
-	private IShare $share;
48
-	private ICloudIdManager $cloudIdManager;
49
-	private MountPublicLinkController $controller;
36
+    protected IContactsManager&MockObject $contactsManager;
37
+    private IRequest&MockObject $request;
38
+    private FederatedShareProvider&MockObject $federatedShareProvider;
39
+    private IManager&MockObject $shareManager;
40
+    private AddressHandler&MockObject $addressHandler;
41
+    private IRootFolder&MockObject $rootFolder;
42
+    private IUserManager&MockObject $userManager;
43
+    private ISession&MockObject $session;
44
+    private IL10N&MockObject $l10n;
45
+    private IUserSession&MockObject $userSession;
46
+    private IClientService&MockObject $clientService;
47
+    private IShare $share;
48
+    private ICloudIdManager $cloudIdManager;
49
+    private MountPublicLinkController $controller;
50 50
 
51
-	protected function setUp(): void {
52
-		parent::setUp();
51
+    protected function setUp(): void {
52
+        parent::setUp();
53 53
 
54
-		$this->request = $this->createMock(IRequest::class);
55
-		$this->federatedShareProvider = $this->createMock(FederatedShareProvider::class);
56
-		$this->shareManager = $this->createMock(IManager::class);
57
-		$this->addressHandler = $this->createMock(AddressHandler::class);
58
-		$this->rootFolder = $this->createMock(IRootFolder::class);
59
-		$this->userManager = $this->createMock(IUserManager::class);
60
-		$this->share = new Share($this->rootFolder, $this->userManager);
61
-		$this->session = $this->createMock(ISession::class);
62
-		$this->l10n = $this->createMock(IL10N::class);
63
-		$this->userSession = $this->createMock(IUserSession::class);
64
-		$this->clientService = $this->createMock(IClientService::class);
65
-		$this->contactsManager = $this->createMock(IContactsManager::class);
66
-		$this->cloudIdManager = new CloudIdManager(
67
-			$this->contactsManager,
68
-			$this->createMock(IURLGenerator::class),
69
-			$this->userManager,
70
-			$this->createMock(ICacheFactory::class),
71
-			$this->createMock(IEventDispatcher::class)
72
-		);
54
+        $this->request = $this->createMock(IRequest::class);
55
+        $this->federatedShareProvider = $this->createMock(FederatedShareProvider::class);
56
+        $this->shareManager = $this->createMock(IManager::class);
57
+        $this->addressHandler = $this->createMock(AddressHandler::class);
58
+        $this->rootFolder = $this->createMock(IRootFolder::class);
59
+        $this->userManager = $this->createMock(IUserManager::class);
60
+        $this->share = new Share($this->rootFolder, $this->userManager);
61
+        $this->session = $this->createMock(ISession::class);
62
+        $this->l10n = $this->createMock(IL10N::class);
63
+        $this->userSession = $this->createMock(IUserSession::class);
64
+        $this->clientService = $this->createMock(IClientService::class);
65
+        $this->contactsManager = $this->createMock(IContactsManager::class);
66
+        $this->cloudIdManager = new CloudIdManager(
67
+            $this->contactsManager,
68
+            $this->createMock(IURLGenerator::class),
69
+            $this->userManager,
70
+            $this->createMock(ICacheFactory::class),
71
+            $this->createMock(IEventDispatcher::class)
72
+        );
73 73
 
74
-		$this->controller = new MountPublicLinkController(
75
-			'federatedfilesharing', $this->request,
76
-			$this->federatedShareProvider,
77
-			$this->shareManager,
78
-			$this->addressHandler,
79
-			$this->session,
80
-			$this->l10n,
81
-			$this->userSession,
82
-			$this->clientService,
83
-			$this->cloudIdManager,
84
-			$this->createMock(LoggerInterface::class),
85
-		);
86
-	}
74
+        $this->controller = new MountPublicLinkController(
75
+            'federatedfilesharing', $this->request,
76
+            $this->federatedShareProvider,
77
+            $this->shareManager,
78
+            $this->addressHandler,
79
+            $this->session,
80
+            $this->l10n,
81
+            $this->userSession,
82
+            $this->clientService,
83
+            $this->cloudIdManager,
84
+            $this->createMock(LoggerInterface::class),
85
+        );
86
+    }
87 87
 
88
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestCreateFederatedShare')]
89
-	public function testCreateFederatedShare(
90
-		string $shareWith,
91
-		bool $outgoingSharesAllowed,
92
-		bool $validShareWith,
93
-		string $token,
94
-		bool $validToken,
95
-		bool $createSuccessful,
96
-		string $expectedReturnData,
97
-		int $permissions,
98
-	): void {
99
-		$this->federatedShareProvider->expects($this->any())
100
-			->method('isOutgoingServer2serverShareEnabled')
101
-			->willReturn($outgoingSharesAllowed);
88
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestCreateFederatedShare')]
89
+    public function testCreateFederatedShare(
90
+        string $shareWith,
91
+        bool $outgoingSharesAllowed,
92
+        bool $validShareWith,
93
+        string $token,
94
+        bool $validToken,
95
+        bool $createSuccessful,
96
+        string $expectedReturnData,
97
+        int $permissions,
98
+    ): void {
99
+        $this->federatedShareProvider->expects($this->any())
100
+            ->method('isOutgoingServer2serverShareEnabled')
101
+            ->willReturn($outgoingSharesAllowed);
102 102
 
103
-		$this->addressHandler->expects($this->any())->method('splitUserRemote')
104
-			->with($shareWith)
105
-			->willReturnCallback(
106
-				function ($shareWith) use ($validShareWith, $expectedReturnData) {
107
-					if ($validShareWith) {
108
-						return ['user', 'server'];
109
-					}
110
-					throw new HintException($expectedReturnData, $expectedReturnData);
111
-				}
112
-			);
103
+        $this->addressHandler->expects($this->any())->method('splitUserRemote')
104
+            ->with($shareWith)
105
+            ->willReturnCallback(
106
+                function ($shareWith) use ($validShareWith, $expectedReturnData) {
107
+                    if ($validShareWith) {
108
+                        return ['user', 'server'];
109
+                    }
110
+                    throw new HintException($expectedReturnData, $expectedReturnData);
111
+                }
112
+            );
113 113
 
114
-		$share = $this->share;
115
-		$share->setPermissions($permissions);
114
+        $share = $this->share;
115
+        $share->setPermissions($permissions);
116 116
 
117
-		$this->shareManager->expects($this->any())->method('getShareByToken')
118
-			->with($token)
119
-			->willReturnCallback(
120
-				function ($token) use ($validToken, $share, $expectedReturnData) {
121
-					if ($validToken) {
122
-						return $share;
123
-					}
124
-					throw new HintException($expectedReturnData, $expectedReturnData);
125
-				}
126
-			);
117
+        $this->shareManager->expects($this->any())->method('getShareByToken')
118
+            ->with($token)
119
+            ->willReturnCallback(
120
+                function ($token) use ($validToken, $share, $expectedReturnData) {
121
+                    if ($validToken) {
122
+                        return $share;
123
+                    }
124
+                    throw new HintException($expectedReturnData, $expectedReturnData);
125
+                }
126
+            );
127 127
 
128
-		$this->federatedShareProvider->expects($this->any())->method('create')
129
-			->with($share)
130
-			->willReturnCallback(
131
-				function (IShare $share) use ($createSuccessful, $shareWith, $expectedReturnData) {
132
-					$this->assertEquals($shareWith, $share->getSharedWith());
133
-					if ($createSuccessful) {
134
-						return $share;
135
-					}
136
-					throw new HintException($expectedReturnData, $expectedReturnData);
137
-				}
138
-			);
128
+        $this->federatedShareProvider->expects($this->any())->method('create')
129
+            ->with($share)
130
+            ->willReturnCallback(
131
+                function (IShare $share) use ($createSuccessful, $shareWith, $expectedReturnData) {
132
+                    $this->assertEquals($shareWith, $share->getSharedWith());
133
+                    if ($createSuccessful) {
134
+                        return $share;
135
+                    }
136
+                    throw new HintException($expectedReturnData, $expectedReturnData);
137
+                }
138
+            );
139 139
 
140
-		$result = $this->controller->createFederatedShare($shareWith, $token);
140
+        $result = $this->controller->createFederatedShare($shareWith, $token);
141 141
 
142
-		$errorCase = !$validShareWith || !$validToken || !$createSuccessful || !$outgoingSharesAllowed;
142
+        $errorCase = !$validShareWith || !$validToken || !$createSuccessful || !$outgoingSharesAllowed;
143 143
 
144
-		if ($errorCase) {
145
-			$this->assertSame(Http::STATUS_BAD_REQUEST, $result->getStatus());
146
-			$this->assertTrue(isset($result->getData()['message']));
147
-			$this->assertSame($expectedReturnData, $result->getData()['message']);
148
-		} else {
149
-			$this->assertSame(Http::STATUS_OK, $result->getStatus());
150
-			$this->assertTrue(isset($result->getData()['remoteUrl']));
151
-			$this->assertSame($expectedReturnData, $result->getData()['remoteUrl']);
152
-		}
153
-	}
144
+        if ($errorCase) {
145
+            $this->assertSame(Http::STATUS_BAD_REQUEST, $result->getStatus());
146
+            $this->assertTrue(isset($result->getData()['message']));
147
+            $this->assertSame($expectedReturnData, $result->getData()['message']);
148
+        } else {
149
+            $this->assertSame(Http::STATUS_OK, $result->getStatus());
150
+            $this->assertTrue(isset($result->getData()['remoteUrl']));
151
+            $this->assertSame($expectedReturnData, $result->getData()['remoteUrl']);
152
+        }
153
+    }
154 154
 
155
-	public static function dataTestCreateFederatedShare(): array {
156
-		return [
157
-			//shareWith, outgoingSharesAllowed, validShareWith, token, validToken, createSuccessful, expectedReturnData
158
-			['user@server', true, true, 'token', true, true, 'server', 31],
159
-			['user@server', true, true, 'token', false, false, 'server', 4],
160
-			['user@server', true, false, 'token', true, true, 'invalid federated cloud id', 31],
161
-			['user@server', true, false, 'token', false, true, 'invalid federated cloud id', 31],
162
-			['user@server', true, false, 'token', false, false, 'invalid federated cloud id', 31],
163
-			['user@server', true, false, 'token', true, false, 'invalid federated cloud id', 31],
164
-			['user@server', true, true, 'token', false, true, 'invalid token', 31],
165
-			['user@server', true, true, 'token', false, false, 'invalid token', 31],
166
-			['user@server', true, true, 'token', true, false, 'can not create share', 31],
167
-			['user@server', false, true, 'token', true, true, 'This server doesn\'t support outgoing federated shares', 31],
168
-		];
169
-	}
155
+    public static function dataTestCreateFederatedShare(): array {
156
+        return [
157
+            //shareWith, outgoingSharesAllowed, validShareWith, token, validToken, createSuccessful, expectedReturnData
158
+            ['user@server', true, true, 'token', true, true, 'server', 31],
159
+            ['user@server', true, true, 'token', false, false, 'server', 4],
160
+            ['user@server', true, false, 'token', true, true, 'invalid federated cloud id', 31],
161
+            ['user@server', true, false, 'token', false, true, 'invalid federated cloud id', 31],
162
+            ['user@server', true, false, 'token', false, false, 'invalid federated cloud id', 31],
163
+            ['user@server', true, false, 'token', true, false, 'invalid federated cloud id', 31],
164
+            ['user@server', true, true, 'token', false, true, 'invalid token', 31],
165
+            ['user@server', true, true, 'token', false, false, 'invalid token', 31],
166
+            ['user@server', true, true, 'token', true, false, 'can not create share', 31],
167
+            ['user@server', false, true, 'token', true, true, 'This server doesn\'t support outgoing federated shares', 31],
168
+        ];
169
+    }
170 170
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/tests/Settings/AdminTest.php 2 patches
Indentation   +98 added lines, -98 removed lines patch added patch discarded remove patch
@@ -18,110 +18,110 @@
 block discarded – undo
18 18
 use Test\TestCase;
19 19
 
20 20
 class AdminTest extends TestCase {
21
-	private FederatedShareProvider&MockObject $federatedShareProvider;
22
-	private IConfig $gsConfig;
23
-	private IInitialState&MockObject $initialState;
24
-	private Admin $admin;
21
+    private FederatedShareProvider&MockObject $federatedShareProvider;
22
+    private IConfig $gsConfig;
23
+    private IInitialState&MockObject $initialState;
24
+    private Admin $admin;
25 25
 
26
-	protected function setUp(): void {
27
-		parent::setUp();
28
-		$this->federatedShareProvider = $this->createMock(FederatedShareProvider::class);
29
-		$this->gsConfig = $this->createMock(IConfig::class);
30
-		$this->initialState = $this->createMock(IInitialState::class);
31
-		$urlGenerator = $this->createMock(IURLGenerator::class);
32
-		$urlGenerator->expects($this->any())
33
-			->method('linkToDocs')
34
-			->willReturn('doc-link');
26
+    protected function setUp(): void {
27
+        parent::setUp();
28
+        $this->federatedShareProvider = $this->createMock(FederatedShareProvider::class);
29
+        $this->gsConfig = $this->createMock(IConfig::class);
30
+        $this->initialState = $this->createMock(IInitialState::class);
31
+        $urlGenerator = $this->createMock(IURLGenerator::class);
32
+        $urlGenerator->expects($this->any())
33
+            ->method('linkToDocs')
34
+            ->willReturn('doc-link');
35 35
 
36
-		$this->admin = new Admin(
37
-			$this->federatedShareProvider,
38
-			$this->gsConfig,
39
-			$this->createMock(IL10N::class),
40
-			$urlGenerator,
41
-			$this->initialState
42
-		);
43
-	}
36
+        $this->admin = new Admin(
37
+            $this->federatedShareProvider,
38
+            $this->gsConfig,
39
+            $this->createMock(IL10N::class),
40
+            $urlGenerator,
41
+            $this->initialState
42
+        );
43
+    }
44 44
 
45
-	public static function sharingStateProvider(): array {
46
-		return [
47
-			[
48
-				true,
49
-			],
50
-			[
51
-				false,
52
-			]
53
-		];
54
-	}
45
+    public static function sharingStateProvider(): array {
46
+        return [
47
+            [
48
+                true,
49
+            ],
50
+            [
51
+                false,
52
+            ]
53
+        ];
54
+    }
55 55
 
56
-	#[\PHPUnit\Framework\Attributes\DataProvider('sharingStateProvider')]
57
-	public function testGetForm(bool $state): void {
58
-		$this->federatedShareProvider
59
-			->expects($this->once())
60
-			->method('isOutgoingServer2serverShareEnabled')
61
-			->willReturn($state);
62
-		$this->federatedShareProvider
63
-			->expects($this->once())
64
-			->method('isIncomingServer2serverShareEnabled')
65
-			->willReturn($state);
66
-		$this->federatedShareProvider
67
-			->expects($this->once())
68
-			->method('isIncomingServer2serverShareEnabled')
69
-			->willReturn($state);
70
-		$this->federatedShareProvider
71
-			->expects($this->once())
72
-			->method('isLookupServerQueriesEnabled')
73
-			->willReturn($state);
74
-		$this->federatedShareProvider
75
-			->expects($this->once())
76
-			->method('isLookupServerUploadEnabled')
77
-			->willReturn($state);
78
-		$this->federatedShareProvider
79
-			->expects($this->once())
80
-			->method('isFederatedGroupSharingSupported')
81
-			->willReturn($state);
82
-		$this->federatedShareProvider
83
-			->expects($this->once())
84
-			->method('isOutgoingServer2serverGroupShareEnabled')
85
-			->willReturn($state);
86
-		$this->federatedShareProvider
87
-			->expects($this->once())
88
-			->method('isIncomingServer2serverGroupShareEnabled')
89
-			->willReturn($state);
90
-		$this->federatedShareProvider
91
-			->expects($this->once())
92
-			->method('isFederatedTrustedShareAutoAccept')
93
-			->willReturn($state);
94
-		$this->gsConfig->expects($this->once())->method('onlyInternalFederation')
95
-			->willReturn($state);
56
+    #[\PHPUnit\Framework\Attributes\DataProvider('sharingStateProvider')]
57
+    public function testGetForm(bool $state): void {
58
+        $this->federatedShareProvider
59
+            ->expects($this->once())
60
+            ->method('isOutgoingServer2serverShareEnabled')
61
+            ->willReturn($state);
62
+        $this->federatedShareProvider
63
+            ->expects($this->once())
64
+            ->method('isIncomingServer2serverShareEnabled')
65
+            ->willReturn($state);
66
+        $this->federatedShareProvider
67
+            ->expects($this->once())
68
+            ->method('isIncomingServer2serverShareEnabled')
69
+            ->willReturn($state);
70
+        $this->federatedShareProvider
71
+            ->expects($this->once())
72
+            ->method('isLookupServerQueriesEnabled')
73
+            ->willReturn($state);
74
+        $this->federatedShareProvider
75
+            ->expects($this->once())
76
+            ->method('isLookupServerUploadEnabled')
77
+            ->willReturn($state);
78
+        $this->federatedShareProvider
79
+            ->expects($this->once())
80
+            ->method('isFederatedGroupSharingSupported')
81
+            ->willReturn($state);
82
+        $this->federatedShareProvider
83
+            ->expects($this->once())
84
+            ->method('isOutgoingServer2serverGroupShareEnabled')
85
+            ->willReturn($state);
86
+        $this->federatedShareProvider
87
+            ->expects($this->once())
88
+            ->method('isIncomingServer2serverGroupShareEnabled')
89
+            ->willReturn($state);
90
+        $this->federatedShareProvider
91
+            ->expects($this->once())
92
+            ->method('isFederatedTrustedShareAutoAccept')
93
+            ->willReturn($state);
94
+        $this->gsConfig->expects($this->once())->method('onlyInternalFederation')
95
+            ->willReturn($state);
96 96
 
97
-		$calls = [
98
-			['internalOnly', $state],
99
-			['sharingFederatedDocUrl', 'doc-link'],
100
-			['outgoingServer2serverShareEnabled', $state],
101
-			['incomingServer2serverShareEnabled', $state],
102
-			['federatedGroupSharingSupported', $state],
103
-			['outgoingServer2serverGroupShareEnabled', $state],
104
-			['incomingServer2serverGroupShareEnabled', $state],
105
-			['lookupServerEnabled', $state],
106
-			['lookupServerUploadEnabled', $state],
107
-			['federatedTrustedShareAutoAccept', $state],
108
-		];
109
-		$this->initialState->expects($this->exactly(10))
110
-			->method('provideInitialState')
111
-			->willReturnCallback(function () use (&$calls): void {
112
-				$expected = array_shift($calls);
113
-				$this->assertSame($expected, func_get_args());
114
-			});
97
+        $calls = [
98
+            ['internalOnly', $state],
99
+            ['sharingFederatedDocUrl', 'doc-link'],
100
+            ['outgoingServer2serverShareEnabled', $state],
101
+            ['incomingServer2serverShareEnabled', $state],
102
+            ['federatedGroupSharingSupported', $state],
103
+            ['outgoingServer2serverGroupShareEnabled', $state],
104
+            ['incomingServer2serverGroupShareEnabled', $state],
105
+            ['lookupServerEnabled', $state],
106
+            ['lookupServerUploadEnabled', $state],
107
+            ['federatedTrustedShareAutoAccept', $state],
108
+        ];
109
+        $this->initialState->expects($this->exactly(10))
110
+            ->method('provideInitialState')
111
+            ->willReturnCallback(function () use (&$calls): void {
112
+                $expected = array_shift($calls);
113
+                $this->assertSame($expected, func_get_args());
114
+            });
115 115
 
116
-		$expected = new TemplateResponse('federatedfilesharing', 'settings-admin', [], '');
117
-		$this->assertEquals($expected, $this->admin->getForm());
118
-	}
116
+        $expected = new TemplateResponse('federatedfilesharing', 'settings-admin', [], '');
117
+        $this->assertEquals($expected, $this->admin->getForm());
118
+    }
119 119
 
120
-	public function testGetSection(): void {
121
-		$this->assertSame('sharing', $this->admin->getSection());
122
-	}
120
+    public function testGetSection(): void {
121
+        $this->assertSame('sharing', $this->admin->getSection());
122
+    }
123 123
 
124
-	public function testGetPriority(): void {
125
-		$this->assertSame(20, $this->admin->getPriority());
126
-	}
124
+    public function testGetPriority(): void {
125
+        $this->assertSame(20, $this->admin->getPriority());
126
+    }
127 127
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -108,7 +108,7 @@
 block discarded – undo
108 108
 		];
109 109
 		$this->initialState->expects($this->exactly(10))
110 110
 			->method('provideInitialState')
111
-			->willReturnCallback(function () use (&$calls): void {
111
+			->willReturnCallback(function() use (&$calls): void {
112 112
 				$expected = array_shift($calls);
113 113
 				$this->assertSame($expected, func_get_args());
114 114
 			});
Please login to merge, or discard this patch.
apps/federatedfilesharing/tests/AddressHandlerTest.php 1 patch
Indentation   +151 added lines, -151 removed lines patch added patch discarded remove patch
@@ -20,155 +20,155 @@
 block discarded – undo
20 20
 use PHPUnit\Framework\MockObject\MockObject;
21 21
 
22 22
 class AddressHandlerTest extends \Test\TestCase {
23
-	protected IManager&MockObject $contactsManager;
24
-	private IURLGenerator&MockObject $urlGenerator;
25
-	private IL10N&MockObject $il10n;
26
-	private CloudIdManager $cloudIdManager;
27
-	private AddressHandler $addressHandler;
28
-
29
-	protected function setUp(): void {
30
-		parent::setUp();
31
-
32
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
33
-		$this->il10n = $this->createMock(IL10N::class);
34
-		$this->contactsManager = $this->createMock(IManager::class);
35
-
36
-		$this->cloudIdManager = new CloudIdManager(
37
-			$this->contactsManager,
38
-			$this->urlGenerator,
39
-			$this->createMock(IUserManager::class),
40
-			$this->createMock(ICacheFactory::class),
41
-			$this->createMock(IEventDispatcher::class)
42
-		);
43
-
44
-		$this->addressHandler = new AddressHandler($this->urlGenerator, $this->il10n, $this->cloudIdManager);
45
-	}
46
-
47
-	public static function dataTestSplitUserRemote(): array {
48
-		$userPrefix = ['user@name', 'username'];
49
-		$protocols = ['', 'http://', 'https://'];
50
-		$remotes = [
51
-			'localhost',
52
-			'local.host',
53
-			'dev.local.host',
54
-			'dev.local.host/path',
55
-			'dev.local.host/at@inpath',
56
-			'127.0.0.1',
57
-			'::1',
58
-			'::192.0.2.128',
59
-			'::192.0.2.128/at@inpath',
60
-		];
61
-
62
-		$testCases = [];
63
-		foreach ($userPrefix as $user) {
64
-			foreach ($remotes as $remote) {
65
-				foreach ($protocols as $protocol) {
66
-					$baseUrl = $user . '@' . $protocol . $remote;
67
-
68
-					if ($protocol === '') {
69
-						// https:// protocol is expected in the final result
70
-						$protocol = 'https://';
71
-					}
72
-
73
-					$testCases[] = [$baseUrl, $user, $protocol . $remote];
74
-					$testCases[] = [$baseUrl . '/', $user, $protocol . $remote];
75
-					$testCases[] = [$baseUrl . '/index.php', $user, $protocol . $remote];
76
-					$testCases[] = [$baseUrl . '/index.php/s/token', $user, $protocol . $remote];
77
-				}
78
-			}
79
-		}
80
-		return $testCases;
81
-	}
82
-
83
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestSplitUserRemote')]
84
-	public function testSplitUserRemote(string $remote, string $expectedUser, string $expectedUrl): void {
85
-		$this->contactsManager->expects($this->any())
86
-			->method('search')
87
-			->willReturn([]);
88
-
89
-		[$remoteUser, $remoteUrl] = $this->addressHandler->splitUserRemote($remote);
90
-		$this->assertSame($expectedUser, $remoteUser);
91
-		$this->assertSame($expectedUrl, $remoteUrl);
92
-	}
93
-
94
-	public static function dataTestSplitUserRemoteError(): array {
95
-		return [
96
-			// Invalid path
97
-			['user@'],
98
-
99
-			// Invalid user
100
-			['@server'],
101
-			['us/er@server'],
102
-			['us:er@server'],
103
-
104
-			// Invalid splitting
105
-			['user'],
106
-			[''],
107
-			['us/erserver'],
108
-			['us:erserver'],
109
-		];
110
-	}
111
-
112
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestSplitUserRemoteError')]
113
-	public function testSplitUserRemoteError(string $id): void {
114
-		$this->expectException(HintException::class);
115
-
116
-		$this->addressHandler->splitUserRemote($id);
117
-	}
118
-
119
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestCompareAddresses')]
120
-	public function testCompareAddresses(string $user1, string $server1, string $user2, string $server2, bool $expected): void {
121
-		$this->assertSame($expected,
122
-			$this->addressHandler->compareAddresses($user1, $server1, $user2, $server2)
123
-		);
124
-	}
125
-
126
-	public static function dataTestCompareAddresses(): array {
127
-		return [
128
-			['user1', 'http://server1', 'user1', 'http://server1', true],
129
-			['user1', 'https://server1', 'user1', 'http://server1', true],
130
-			['user1', 'http://serVer1', 'user1', 'http://server1', true],
131
-			['user1', 'http://server1/',  'user1', 'http://server1', true],
132
-			['user1', 'server1', 'user1', 'http://server1', true],
133
-			['user1', 'http://server1', 'user1', 'http://server2', false],
134
-			['user1', 'https://server1', 'user1', 'http://server2', false],
135
-			['user1', 'http://serVer1', 'user1', 'http://serer2', false],
136
-			['user1', 'http://server1/', 'user1', 'http://server2', false],
137
-			['user1', 'server1', 'user1', 'http://server2', false],
138
-			['user1', 'http://server1', 'user2', 'http://server1', false],
139
-			['user1', 'https://server1', 'user2', 'http://server1', false],
140
-			['user1', 'http://serVer1', 'user2', 'http://server1', false],
141
-			['user1', 'http://server1/',  'user2', 'http://server1', false],
142
-			['user1', 'server1', 'user2', 'http://server1', false],
143
-		];
144
-	}
145
-
146
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestRemoveProtocolFromUrl')]
147
-	public function testRemoveProtocolFromUrl(string $url, string $expectedResult): void {
148
-		$result = $this->addressHandler->removeProtocolFromUrl($url);
149
-		$this->assertSame($expectedResult, $result);
150
-	}
151
-
152
-	public static function dataTestRemoveProtocolFromUrl(): array {
153
-		return [
154
-			['http://example.tld', 'example.tld'],
155
-			['https://example.tld', 'example.tld'],
156
-			['example.tld', 'example.tld'],
157
-		];
158
-	}
159
-
160
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestUrlContainProtocol')]
161
-	public function testUrlContainProtocol(string $url, bool $expectedResult): void {
162
-		$result = $this->addressHandler->urlContainProtocol($url);
163
-		$this->assertSame($expectedResult, $result);
164
-	}
165
-
166
-	public static function dataTestUrlContainProtocol(): array {
167
-		return [
168
-			['http://nextcloud.com', true],
169
-			['https://nextcloud.com', true],
170
-			['nextcloud.com', false],
171
-			['httpserver.com', false],
172
-		];
173
-	}
23
+    protected IManager&MockObject $contactsManager;
24
+    private IURLGenerator&MockObject $urlGenerator;
25
+    private IL10N&MockObject $il10n;
26
+    private CloudIdManager $cloudIdManager;
27
+    private AddressHandler $addressHandler;
28
+
29
+    protected function setUp(): void {
30
+        parent::setUp();
31
+
32
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
33
+        $this->il10n = $this->createMock(IL10N::class);
34
+        $this->contactsManager = $this->createMock(IManager::class);
35
+
36
+        $this->cloudIdManager = new CloudIdManager(
37
+            $this->contactsManager,
38
+            $this->urlGenerator,
39
+            $this->createMock(IUserManager::class),
40
+            $this->createMock(ICacheFactory::class),
41
+            $this->createMock(IEventDispatcher::class)
42
+        );
43
+
44
+        $this->addressHandler = new AddressHandler($this->urlGenerator, $this->il10n, $this->cloudIdManager);
45
+    }
46
+
47
+    public static function dataTestSplitUserRemote(): array {
48
+        $userPrefix = ['user@name', 'username'];
49
+        $protocols = ['', 'http://', 'https://'];
50
+        $remotes = [
51
+            'localhost',
52
+            'local.host',
53
+            'dev.local.host',
54
+            'dev.local.host/path',
55
+            'dev.local.host/at@inpath',
56
+            '127.0.0.1',
57
+            '::1',
58
+            '::192.0.2.128',
59
+            '::192.0.2.128/at@inpath',
60
+        ];
61
+
62
+        $testCases = [];
63
+        foreach ($userPrefix as $user) {
64
+            foreach ($remotes as $remote) {
65
+                foreach ($protocols as $protocol) {
66
+                    $baseUrl = $user . '@' . $protocol . $remote;
67
+
68
+                    if ($protocol === '') {
69
+                        // https:// protocol is expected in the final result
70
+                        $protocol = 'https://';
71
+                    }
72
+
73
+                    $testCases[] = [$baseUrl, $user, $protocol . $remote];
74
+                    $testCases[] = [$baseUrl . '/', $user, $protocol . $remote];
75
+                    $testCases[] = [$baseUrl . '/index.php', $user, $protocol . $remote];
76
+                    $testCases[] = [$baseUrl . '/index.php/s/token', $user, $protocol . $remote];
77
+                }
78
+            }
79
+        }
80
+        return $testCases;
81
+    }
82
+
83
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestSplitUserRemote')]
84
+    public function testSplitUserRemote(string $remote, string $expectedUser, string $expectedUrl): void {
85
+        $this->contactsManager->expects($this->any())
86
+            ->method('search')
87
+            ->willReturn([]);
88
+
89
+        [$remoteUser, $remoteUrl] = $this->addressHandler->splitUserRemote($remote);
90
+        $this->assertSame($expectedUser, $remoteUser);
91
+        $this->assertSame($expectedUrl, $remoteUrl);
92
+    }
93
+
94
+    public static function dataTestSplitUserRemoteError(): array {
95
+        return [
96
+            // Invalid path
97
+            ['user@'],
98
+
99
+            // Invalid user
100
+            ['@server'],
101
+            ['us/er@server'],
102
+            ['us:er@server'],
103
+
104
+            // Invalid splitting
105
+            ['user'],
106
+            [''],
107
+            ['us/erserver'],
108
+            ['us:erserver'],
109
+        ];
110
+    }
111
+
112
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestSplitUserRemoteError')]
113
+    public function testSplitUserRemoteError(string $id): void {
114
+        $this->expectException(HintException::class);
115
+
116
+        $this->addressHandler->splitUserRemote($id);
117
+    }
118
+
119
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestCompareAddresses')]
120
+    public function testCompareAddresses(string $user1, string $server1, string $user2, string $server2, bool $expected): void {
121
+        $this->assertSame($expected,
122
+            $this->addressHandler->compareAddresses($user1, $server1, $user2, $server2)
123
+        );
124
+    }
125
+
126
+    public static function dataTestCompareAddresses(): array {
127
+        return [
128
+            ['user1', 'http://server1', 'user1', 'http://server1', true],
129
+            ['user1', 'https://server1', 'user1', 'http://server1', true],
130
+            ['user1', 'http://serVer1', 'user1', 'http://server1', true],
131
+            ['user1', 'http://server1/',  'user1', 'http://server1', true],
132
+            ['user1', 'server1', 'user1', 'http://server1', true],
133
+            ['user1', 'http://server1', 'user1', 'http://server2', false],
134
+            ['user1', 'https://server1', 'user1', 'http://server2', false],
135
+            ['user1', 'http://serVer1', 'user1', 'http://serer2', false],
136
+            ['user1', 'http://server1/', 'user1', 'http://server2', false],
137
+            ['user1', 'server1', 'user1', 'http://server2', false],
138
+            ['user1', 'http://server1', 'user2', 'http://server1', false],
139
+            ['user1', 'https://server1', 'user2', 'http://server1', false],
140
+            ['user1', 'http://serVer1', 'user2', 'http://server1', false],
141
+            ['user1', 'http://server1/',  'user2', 'http://server1', false],
142
+            ['user1', 'server1', 'user2', 'http://server1', false],
143
+        ];
144
+    }
145
+
146
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestRemoveProtocolFromUrl')]
147
+    public function testRemoveProtocolFromUrl(string $url, string $expectedResult): void {
148
+        $result = $this->addressHandler->removeProtocolFromUrl($url);
149
+        $this->assertSame($expectedResult, $result);
150
+    }
151
+
152
+    public static function dataTestRemoveProtocolFromUrl(): array {
153
+        return [
154
+            ['http://example.tld', 'example.tld'],
155
+            ['https://example.tld', 'example.tld'],
156
+            ['example.tld', 'example.tld'],
157
+        ];
158
+    }
159
+
160
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestUrlContainProtocol')]
161
+    public function testUrlContainProtocol(string $url, bool $expectedResult): void {
162
+        $result = $this->addressHandler->urlContainProtocol($url);
163
+        $this->assertSame($expectedResult, $result);
164
+    }
165
+
166
+    public static function dataTestUrlContainProtocol(): array {
167
+        return [
168
+            ['http://nextcloud.com', true],
169
+            ['https://nextcloud.com', true],
170
+            ['nextcloud.com', false],
171
+            ['httpserver.com', false],
172
+        ];
173
+    }
174 174
 }
Please login to merge, or discard this patch.
apps/federatedfilesharing/tests/TestCase.php 1 patch
Indentation   +73 added lines, -73 removed lines patch added patch discarded remove patch
@@ -24,77 +24,77 @@
 block discarded – undo
24 24
  * Base class for sharing tests.
25 25
  */
26 26
 abstract class TestCase extends \Test\TestCase {
27
-	public const TEST_FILES_SHARING_API_USER1 = 'test-share-user1';
28
-	public const TEST_FILES_SHARING_API_USER2 = 'test-share-user2';
29
-
30
-	public static function setUpBeforeClass(): void {
31
-		parent::setUpBeforeClass();
32
-
33
-		// reset backend
34
-		Server::get(IUserManager::class)->clearBackends();
35
-		Server::get(IGroupManager::class)->clearBackends();
36
-
37
-		// create users
38
-		$backend = new \Test\Util\User\Dummy();
39
-		Server::get(IUserManager::class)->registerBackend($backend);
40
-		$backend->createUser(self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER1);
41
-		$backend->createUser(self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER2);
42
-	}
43
-
44
-	protected function setUp(): void {
45
-		parent::setUp();
46
-
47
-		//login as user1
48
-		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
49
-	}
50
-
51
-	public static function tearDownAfterClass(): void {
52
-		// cleanup users
53
-		$user = Server::get(IUserManager::class)->get(self::TEST_FILES_SHARING_API_USER1);
54
-		if ($user !== null) {
55
-			$user->delete();
56
-		}
57
-		$user = Server::get(IUserManager::class)->get(self::TEST_FILES_SHARING_API_USER2);
58
-		if ($user !== null) {
59
-			$user->delete();
60
-		}
61
-
62
-		\OC_Util::tearDownFS();
63
-		\OC_User::setUserId('');
64
-		Filesystem::tearDown();
65
-
66
-		// reset backend
67
-		Server::get(IUserManager::class)->clearBackends();
68
-		Server::get(IUserManager::class)->registerBackend(new \OC\User\Database());
69
-		Server::get(IGroupManager::class)->clearBackends();
70
-		Server::get(IGroupManager::class)->addBackend(new Database());
71
-
72
-		parent::tearDownAfterClass();
73
-	}
74
-
75
-	protected static function loginHelper(string $user, bool $create = false, bool $password = false) {
76
-		if ($password === false) {
77
-			$password = $user;
78
-		}
79
-
80
-		if ($create) {
81
-			$userManager = Server::get(IUserManager::class);
82
-			$groupManager = Server::get(IGroupManager::class);
83
-
84
-			$userObject = $userManager->createUser($user, $password);
85
-			$group = $groupManager->createGroup('group');
86
-
87
-			if ($group and $userObject) {
88
-				$group->addUser($userObject);
89
-			}
90
-		}
91
-
92
-		\OC_Util::tearDownFS();
93
-		Server::get(IUserSession::class)->setUser(null);
94
-		Filesystem::tearDown();
95
-		Server::get(IUserSession::class)->login($user, $password);
96
-		Server::get(IRootFolder::class)->getUserFolder($user);
97
-
98
-		\OC_Util::setupFS($user);
99
-	}
27
+    public const TEST_FILES_SHARING_API_USER1 = 'test-share-user1';
28
+    public const TEST_FILES_SHARING_API_USER2 = 'test-share-user2';
29
+
30
+    public static function setUpBeforeClass(): void {
31
+        parent::setUpBeforeClass();
32
+
33
+        // reset backend
34
+        Server::get(IUserManager::class)->clearBackends();
35
+        Server::get(IGroupManager::class)->clearBackends();
36
+
37
+        // create users
38
+        $backend = new \Test\Util\User\Dummy();
39
+        Server::get(IUserManager::class)->registerBackend($backend);
40
+        $backend->createUser(self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER1);
41
+        $backend->createUser(self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER2);
42
+    }
43
+
44
+    protected function setUp(): void {
45
+        parent::setUp();
46
+
47
+        //login as user1
48
+        self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
49
+    }
50
+
51
+    public static function tearDownAfterClass(): void {
52
+        // cleanup users
53
+        $user = Server::get(IUserManager::class)->get(self::TEST_FILES_SHARING_API_USER1);
54
+        if ($user !== null) {
55
+            $user->delete();
56
+        }
57
+        $user = Server::get(IUserManager::class)->get(self::TEST_FILES_SHARING_API_USER2);
58
+        if ($user !== null) {
59
+            $user->delete();
60
+        }
61
+
62
+        \OC_Util::tearDownFS();
63
+        \OC_User::setUserId('');
64
+        Filesystem::tearDown();
65
+
66
+        // reset backend
67
+        Server::get(IUserManager::class)->clearBackends();
68
+        Server::get(IUserManager::class)->registerBackend(new \OC\User\Database());
69
+        Server::get(IGroupManager::class)->clearBackends();
70
+        Server::get(IGroupManager::class)->addBackend(new Database());
71
+
72
+        parent::tearDownAfterClass();
73
+    }
74
+
75
+    protected static function loginHelper(string $user, bool $create = false, bool $password = false) {
76
+        if ($password === false) {
77
+            $password = $user;
78
+        }
79
+
80
+        if ($create) {
81
+            $userManager = Server::get(IUserManager::class);
82
+            $groupManager = Server::get(IGroupManager::class);
83
+
84
+            $userObject = $userManager->createUser($user, $password);
85
+            $group = $groupManager->createGroup('group');
86
+
87
+            if ($group and $userObject) {
88
+                $group->addUser($userObject);
89
+            }
90
+        }
91
+
92
+        \OC_Util::tearDownFS();
93
+        Server::get(IUserSession::class)->setUser(null);
94
+        Filesystem::tearDown();
95
+        Server::get(IUserSession::class)->login($user, $password);
96
+        Server::get(IRootFolder::class)->getUserFolder($user);
97
+
98
+        \OC_Util::setupFS($user);
99
+    }
100 100
 }
Please login to merge, or discard this patch.
apps/testing/lib/HiddenGroupBackend.php 1 patch
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -13,32 +13,32 @@
 block discarded – undo
13 13
 use OCP\Group\Backend\IHideFromCollaborationBackend;
14 14
 
15 15
 class HiddenGroupBackend extends ABackend implements IHideFromCollaborationBackend {
16
-	public function __construct(
17
-		private string $groupName = 'hidden_group',
18
-	) {
19
-	}
20
-
21
-	public function inGroup($uid, $gid): bool {
22
-		return false;
23
-	}
24
-
25
-	public function getUserGroups($uid): array {
26
-		return [];
27
-	}
28
-
29
-	public function getGroups($search = '', $limit = -1, $offset = 0): array {
30
-		return $offset === 0 ? [$this->groupName] : [];
31
-	}
32
-
33
-	public function groupExists($gid): bool {
34
-		return $gid === $this->groupName;
35
-	}
36
-
37
-	public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0): array {
38
-		return [];
39
-	}
40
-
41
-	public function hideGroup(string $groupId): bool {
42
-		return true;
43
-	}
16
+    public function __construct(
17
+        private string $groupName = 'hidden_group',
18
+    ) {
19
+    }
20
+
21
+    public function inGroup($uid, $gid): bool {
22
+        return false;
23
+    }
24
+
25
+    public function getUserGroups($uid): array {
26
+        return [];
27
+    }
28
+
29
+    public function getGroups($search = '', $limit = -1, $offset = 0): array {
30
+        return $offset === 0 ? [$this->groupName] : [];
31
+    }
32
+
33
+    public function groupExists($gid): bool {
34
+        return $gid === $this->groupName;
35
+    }
36
+
37
+    public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0): array {
38
+        return [];
39
+    }
40
+
41
+    public function hideGroup(string $groupId): bool {
42
+        return true;
43
+    }
44 44
 }
Please login to merge, or discard this patch.
apps/user_ldap/tests/ConnectionTest.php 1 patch
Indentation   +243 added lines, -243 removed lines patch added patch discarded remove patch
@@ -21,247 +21,247 @@
 block discarded – undo
21 21
  * @package OCA\User_LDAP\Tests
22 22
  */
23 23
 class ConnectionTest extends \Test\TestCase {
24
-	protected ILDAPWrapper&MockObject $ldap;
25
-	protected Connection $connection;
26
-
27
-	protected function setUp(): void {
28
-		parent::setUp();
29
-
30
-		$this->ldap = $this->createMock(ILDAPWrapper::class);
31
-		// we use a mock here to replace the cache mechanism, due to missing DI in LDAP backend.
32
-		$this->connection = $this->getMockBuilder(Connection::class)
33
-			->onlyMethods(['getFromCache', 'writeToCache'])
34
-			->setConstructorArgs([$this->ldap, '', null])
35
-			->getMock();
36
-
37
-		$this->ldap->expects($this->any())
38
-			->method('areLDAPFunctionsAvailable')
39
-			->willReturn(true);
40
-	}
41
-
42
-	public function testOriginalAgentUnchangedOnClone(): void {
43
-		//background: upon login a bind is done with the user credentials
44
-		//which is valid for the whole LDAP resource. It needs to be reset
45
-		//to the agent's credentials
46
-		$lw = $this->createMock(ILDAPWrapper::class);
47
-
48
-		$connection = new Connection($lw, '', null);
49
-		$agent = [
50
-			'ldapAgentName' => 'agent',
51
-			'ldapAgentPassword' => '123456',
52
-		];
53
-		$connection->setConfiguration($agent);
54
-
55
-		$testConnection = clone $connection;
56
-		$user = [
57
-			'ldapAgentName' => 'user',
58
-			'ldapAgentPassword' => 'password',
59
-		];
60
-		$testConnection->setConfiguration($user);
61
-
62
-		$agentName = $connection->ldapAgentName;
63
-		$agentPawd = $connection->ldapAgentPassword;
64
-
65
-		$this->assertSame($agentName, $agent['ldapAgentName']);
66
-		$this->assertSame($agentPawd, $agent['ldapAgentPassword']);
67
-	}
68
-
69
-	public function testUseBackupServer(): void {
70
-		$mainHost = 'ldap://nixda.ldap';
71
-		$backupHost = 'ldap://fallback.ldap';
72
-		$config = [
73
-			'ldapConfigurationActive' => true,
74
-			'ldapHost' => $mainHost,
75
-			'ldapPort' => 389,
76
-			'ldapBackupHost' => $backupHost,
77
-			'ldapBackupPort' => 389,
78
-			'ldapAgentName' => 'uid=agent',
79
-			'ldapAgentPassword' => 'SuchASecret'
80
-		];
81
-
82
-		$this->connection->setIgnoreValidation(true);
83
-		$this->connection->setConfiguration($config);
84
-
85
-		$this->ldap->expects($this->any())
86
-			->method('isResource')
87
-			->willReturn(true);
88
-
89
-		$this->ldap->expects($this->any())
90
-			->method('setOption')
91
-			->willReturn(true);
92
-
93
-		$this->ldap->expects($this->exactly(3))
94
-			->method('connect')
95
-			->willReturn(ldap_connect('ldap://example.com'));
96
-
97
-		$this->ldap->expects($this->any())
98
-			->method('errno')
99
-			->willReturn(0);
100
-
101
-		// Not called often enough? Then, the fallback to the backup server is broken.
102
-		$this->connection->expects($this->exactly(2))
103
-			->method('getFromCache')
104
-			->with('overrideMainServer')->willReturnOnConsecutiveCalls(false, false, true, true);
105
-
106
-		$this->connection->expects($this->once())
107
-			->method('writeToCache')
108
-			->with('overrideMainServer', true);
109
-
110
-		$isThrown = false;
111
-		$this->ldap->expects($this->exactly(3))
112
-			->method('bind')
113
-			->willReturnCallback(function () use (&$isThrown) {
114
-				if (!$isThrown) {
115
-					$isThrown = true;
116
-					throw new ServerNotAvailableException();
117
-				}
118
-				return true;
119
-			});
120
-
121
-		$this->connection->init();
122
-		$this->connection->resetConnectionResource();
123
-		// with the second init() we test whether caching works
124
-		$this->connection->init();
125
-	}
126
-
127
-	public function testDontUseBackupServerOnFailedAuth(): void {
128
-		$mainHost = 'ldap://nixda.ldap';
129
-		$backupHost = 'ldap://fallback.ldap';
130
-		$config = [
131
-			'ldapConfigurationActive' => true,
132
-			'ldapHost' => $mainHost,
133
-			'ldapPort' => 389,
134
-			'ldapBackupHost' => $backupHost,
135
-			'ldapBackupPort' => 389,
136
-			'ldapAgentName' => 'uid=agent',
137
-			'ldapAgentPassword' => 'SuchASecret'
138
-		];
139
-
140
-		$this->connection->setIgnoreValidation(true);
141
-		$this->connection->setConfiguration($config);
142
-
143
-		$this->ldap->expects($this->any())
144
-			->method('isResource')
145
-			->willReturn(true);
146
-
147
-		$this->ldap->expects($this->any())
148
-			->method('setOption')
149
-			->willReturn(true);
150
-
151
-		$this->ldap->expects($this->once())
152
-			->method('connect')
153
-			->willReturn(ldap_connect('ldap://example.com'));
154
-
155
-		$this->ldap->expects($this->any())
156
-			->method('errno')
157
-			->willReturn(49);
158
-
159
-		$this->connection->expects($this->any())
160
-			->method('getFromCache')
161
-			->with('overrideMainServer')
162
-			->willReturn(false);
163
-
164
-		$this->connection->expects($this->never())
165
-			->method('writeToCache');
166
-
167
-		$this->ldap->expects($this->exactly(1))
168
-			->method('bind')
169
-			->willReturn(false);
170
-
171
-		$this->connection->init();
172
-	}
173
-
174
-	public function testBindWithInvalidCredentials(): void {
175
-		// background: Bind with invalid credentials should return false
176
-		// and not throw a ServerNotAvailableException.
177
-
178
-		$host = 'ldap://nixda.ldap';
179
-		$config = [
180
-			'ldapConfigurationActive' => true,
181
-			'ldapHost' => $host,
182
-			'ldapPort' => 389,
183
-			'ldapBackupHost' => '',
184
-			'ldapAgentName' => 'user',
185
-			'ldapAgentPassword' => 'password'
186
-		];
187
-
188
-		$this->connection->setIgnoreValidation(true);
189
-		$this->connection->setConfiguration($config);
190
-
191
-		$this->ldap->expects($this->any())
192
-			->method('isResource')
193
-			->willReturn(true);
194
-
195
-		$this->ldap->expects($this->any())
196
-			->method('setOption')
197
-			->willReturn(true);
198
-
199
-		$this->ldap->expects($this->any())
200
-			->method('connect')
201
-			->willReturn(ldap_connect('ldap://example.com'));
202
-
203
-		$this->ldap->expects($this->once())
204
-			->method('bind')
205
-			->willReturn(false);
206
-
207
-		// LDAP_INVALID_CREDENTIALS
208
-		$this->ldap->expects($this->any())
209
-			->method('errno')
210
-			->willReturn(0x31);
211
-
212
-		try {
213
-			$this->assertFalse($this->connection->bind(), 'Connection::bind() should not return true with invalid credentials.');
214
-		} catch (ServerNotAvailableException $e) {
215
-			$this->fail('Failed asserting that exception of type "OC\ServerNotAvailableException" is not thrown.');
216
-		}
217
-	}
218
-
219
-	public function testStartTlsNegotiationFailure(): void {
220
-		// background: If Start TLS negotiation fails,
221
-		// a ServerNotAvailableException should be thrown.
222
-
223
-		$host = 'ldap://nixda.ldap';
224
-		$port = 389;
225
-		$config = [
226
-			'ldapConfigurationActive' => true,
227
-			'ldapHost' => $host,
228
-			'ldapPort' => $port,
229
-			'ldapTLS' => true,
230
-			'ldapBackupHost' => '',
231
-			'ldapAgentName' => 'user',
232
-			'ldapAgentPassword' => 'password'
233
-		];
234
-
235
-		$this->connection->setIgnoreValidation(true);
236
-		$this->connection->setConfiguration($config);
237
-
238
-		$this->ldap->expects($this->any())
239
-			->method('isResource')
240
-			->willReturn(true);
241
-
242
-		$this->ldap->expects($this->any())
243
-			->method('connect')
244
-			->willReturn(ldap_connect('ldap://example.com'));
245
-
246
-		$this->ldap->expects($this->any())
247
-			->method('setOption')
248
-			->willReturn(true);
249
-
250
-		$this->ldap->expects($this->any())
251
-			->method('bind')
252
-			->willReturn(true);
253
-
254
-		$this->ldap->expects($this->any())
255
-			->method('errno')
256
-			->willReturn(0);
257
-
258
-		$this->ldap->expects($this->any())
259
-			->method('startTls')
260
-			->willReturn(false);
261
-
262
-		$this->expectException(ServerNotAvailableException::class);
263
-		$this->expectExceptionMessage('Start TLS failed, when connecting to LDAP host ' . $host . '.');
264
-
265
-		$this->connection->init();
266
-	}
24
+    protected ILDAPWrapper&MockObject $ldap;
25
+    protected Connection $connection;
26
+
27
+    protected function setUp(): void {
28
+        parent::setUp();
29
+
30
+        $this->ldap = $this->createMock(ILDAPWrapper::class);
31
+        // we use a mock here to replace the cache mechanism, due to missing DI in LDAP backend.
32
+        $this->connection = $this->getMockBuilder(Connection::class)
33
+            ->onlyMethods(['getFromCache', 'writeToCache'])
34
+            ->setConstructorArgs([$this->ldap, '', null])
35
+            ->getMock();
36
+
37
+        $this->ldap->expects($this->any())
38
+            ->method('areLDAPFunctionsAvailable')
39
+            ->willReturn(true);
40
+    }
41
+
42
+    public function testOriginalAgentUnchangedOnClone(): void {
43
+        //background: upon login a bind is done with the user credentials
44
+        //which is valid for the whole LDAP resource. It needs to be reset
45
+        //to the agent's credentials
46
+        $lw = $this->createMock(ILDAPWrapper::class);
47
+
48
+        $connection = new Connection($lw, '', null);
49
+        $agent = [
50
+            'ldapAgentName' => 'agent',
51
+            'ldapAgentPassword' => '123456',
52
+        ];
53
+        $connection->setConfiguration($agent);
54
+
55
+        $testConnection = clone $connection;
56
+        $user = [
57
+            'ldapAgentName' => 'user',
58
+            'ldapAgentPassword' => 'password',
59
+        ];
60
+        $testConnection->setConfiguration($user);
61
+
62
+        $agentName = $connection->ldapAgentName;
63
+        $agentPawd = $connection->ldapAgentPassword;
64
+
65
+        $this->assertSame($agentName, $agent['ldapAgentName']);
66
+        $this->assertSame($agentPawd, $agent['ldapAgentPassword']);
67
+    }
68
+
69
+    public function testUseBackupServer(): void {
70
+        $mainHost = 'ldap://nixda.ldap';
71
+        $backupHost = 'ldap://fallback.ldap';
72
+        $config = [
73
+            'ldapConfigurationActive' => true,
74
+            'ldapHost' => $mainHost,
75
+            'ldapPort' => 389,
76
+            'ldapBackupHost' => $backupHost,
77
+            'ldapBackupPort' => 389,
78
+            'ldapAgentName' => 'uid=agent',
79
+            'ldapAgentPassword' => 'SuchASecret'
80
+        ];
81
+
82
+        $this->connection->setIgnoreValidation(true);
83
+        $this->connection->setConfiguration($config);
84
+
85
+        $this->ldap->expects($this->any())
86
+            ->method('isResource')
87
+            ->willReturn(true);
88
+
89
+        $this->ldap->expects($this->any())
90
+            ->method('setOption')
91
+            ->willReturn(true);
92
+
93
+        $this->ldap->expects($this->exactly(3))
94
+            ->method('connect')
95
+            ->willReturn(ldap_connect('ldap://example.com'));
96
+
97
+        $this->ldap->expects($this->any())
98
+            ->method('errno')
99
+            ->willReturn(0);
100
+
101
+        // Not called often enough? Then, the fallback to the backup server is broken.
102
+        $this->connection->expects($this->exactly(2))
103
+            ->method('getFromCache')
104
+            ->with('overrideMainServer')->willReturnOnConsecutiveCalls(false, false, true, true);
105
+
106
+        $this->connection->expects($this->once())
107
+            ->method('writeToCache')
108
+            ->with('overrideMainServer', true);
109
+
110
+        $isThrown = false;
111
+        $this->ldap->expects($this->exactly(3))
112
+            ->method('bind')
113
+            ->willReturnCallback(function () use (&$isThrown) {
114
+                if (!$isThrown) {
115
+                    $isThrown = true;
116
+                    throw new ServerNotAvailableException();
117
+                }
118
+                return true;
119
+            });
120
+
121
+        $this->connection->init();
122
+        $this->connection->resetConnectionResource();
123
+        // with the second init() we test whether caching works
124
+        $this->connection->init();
125
+    }
126
+
127
+    public function testDontUseBackupServerOnFailedAuth(): void {
128
+        $mainHost = 'ldap://nixda.ldap';
129
+        $backupHost = 'ldap://fallback.ldap';
130
+        $config = [
131
+            'ldapConfigurationActive' => true,
132
+            'ldapHost' => $mainHost,
133
+            'ldapPort' => 389,
134
+            'ldapBackupHost' => $backupHost,
135
+            'ldapBackupPort' => 389,
136
+            'ldapAgentName' => 'uid=agent',
137
+            'ldapAgentPassword' => 'SuchASecret'
138
+        ];
139
+
140
+        $this->connection->setIgnoreValidation(true);
141
+        $this->connection->setConfiguration($config);
142
+
143
+        $this->ldap->expects($this->any())
144
+            ->method('isResource')
145
+            ->willReturn(true);
146
+
147
+        $this->ldap->expects($this->any())
148
+            ->method('setOption')
149
+            ->willReturn(true);
150
+
151
+        $this->ldap->expects($this->once())
152
+            ->method('connect')
153
+            ->willReturn(ldap_connect('ldap://example.com'));
154
+
155
+        $this->ldap->expects($this->any())
156
+            ->method('errno')
157
+            ->willReturn(49);
158
+
159
+        $this->connection->expects($this->any())
160
+            ->method('getFromCache')
161
+            ->with('overrideMainServer')
162
+            ->willReturn(false);
163
+
164
+        $this->connection->expects($this->never())
165
+            ->method('writeToCache');
166
+
167
+        $this->ldap->expects($this->exactly(1))
168
+            ->method('bind')
169
+            ->willReturn(false);
170
+
171
+        $this->connection->init();
172
+    }
173
+
174
+    public function testBindWithInvalidCredentials(): void {
175
+        // background: Bind with invalid credentials should return false
176
+        // and not throw a ServerNotAvailableException.
177
+
178
+        $host = 'ldap://nixda.ldap';
179
+        $config = [
180
+            'ldapConfigurationActive' => true,
181
+            'ldapHost' => $host,
182
+            'ldapPort' => 389,
183
+            'ldapBackupHost' => '',
184
+            'ldapAgentName' => 'user',
185
+            'ldapAgentPassword' => 'password'
186
+        ];
187
+
188
+        $this->connection->setIgnoreValidation(true);
189
+        $this->connection->setConfiguration($config);
190
+
191
+        $this->ldap->expects($this->any())
192
+            ->method('isResource')
193
+            ->willReturn(true);
194
+
195
+        $this->ldap->expects($this->any())
196
+            ->method('setOption')
197
+            ->willReturn(true);
198
+
199
+        $this->ldap->expects($this->any())
200
+            ->method('connect')
201
+            ->willReturn(ldap_connect('ldap://example.com'));
202
+
203
+        $this->ldap->expects($this->once())
204
+            ->method('bind')
205
+            ->willReturn(false);
206
+
207
+        // LDAP_INVALID_CREDENTIALS
208
+        $this->ldap->expects($this->any())
209
+            ->method('errno')
210
+            ->willReturn(0x31);
211
+
212
+        try {
213
+            $this->assertFalse($this->connection->bind(), 'Connection::bind() should not return true with invalid credentials.');
214
+        } catch (ServerNotAvailableException $e) {
215
+            $this->fail('Failed asserting that exception of type "OC\ServerNotAvailableException" is not thrown.');
216
+        }
217
+    }
218
+
219
+    public function testStartTlsNegotiationFailure(): void {
220
+        // background: If Start TLS negotiation fails,
221
+        // a ServerNotAvailableException should be thrown.
222
+
223
+        $host = 'ldap://nixda.ldap';
224
+        $port = 389;
225
+        $config = [
226
+            'ldapConfigurationActive' => true,
227
+            'ldapHost' => $host,
228
+            'ldapPort' => $port,
229
+            'ldapTLS' => true,
230
+            'ldapBackupHost' => '',
231
+            'ldapAgentName' => 'user',
232
+            'ldapAgentPassword' => 'password'
233
+        ];
234
+
235
+        $this->connection->setIgnoreValidation(true);
236
+        $this->connection->setConfiguration($config);
237
+
238
+        $this->ldap->expects($this->any())
239
+            ->method('isResource')
240
+            ->willReturn(true);
241
+
242
+        $this->ldap->expects($this->any())
243
+            ->method('connect')
244
+            ->willReturn(ldap_connect('ldap://example.com'));
245
+
246
+        $this->ldap->expects($this->any())
247
+            ->method('setOption')
248
+            ->willReturn(true);
249
+
250
+        $this->ldap->expects($this->any())
251
+            ->method('bind')
252
+            ->willReturn(true);
253
+
254
+        $this->ldap->expects($this->any())
255
+            ->method('errno')
256
+            ->willReturn(0);
257
+
258
+        $this->ldap->expects($this->any())
259
+            ->method('startTls')
260
+            ->willReturn(false);
261
+
262
+        $this->expectException(ServerNotAvailableException::class);
263
+        $this->expectExceptionMessage('Start TLS failed, when connecting to LDAP host ' . $host . '.');
264
+
265
+        $this->connection->init();
266
+    }
267 267
 }
Please login to merge, or discard this patch.
apps/user_ldap/tests/Group_LDAPTest.php 2 patches
Indentation   +1292 added lines, -1292 removed lines patch added patch discarded remove patch
@@ -35,1348 +35,1348 @@
 block discarded – undo
35 35
  * @package OCA\User_LDAP\Tests
36 36
  */
37 37
 class Group_LDAPTest extends TestCase {
38
-	private Access&MockObject $access;
39
-	private GroupPluginManager&MockObject $pluginManager;
40
-	private IConfig&MockObject $config;
41
-	private IUserManager&MockObject $ncUserManager;
42
-	private GroupLDAP $groupBackend;
43
-
44
-	public function setUp(): void {
45
-		parent::setUp();
46
-
47
-		$this->access = $this->getAccessMock();
48
-		$this->pluginManager = $this->createMock(GroupPluginManager::class);
49
-		$this->config = $this->createMock(IConfig::class);
50
-		$this->ncUserManager = $this->createMock(IUserManager::class);
51
-	}
52
-
53
-	public function initBackend(): void {
54
-		$this->groupBackend = new GroupLDAP($this->access, $this->pluginManager, $this->config, $this->ncUserManager);
55
-	}
56
-
57
-	public function testCountEmptySearchString(): void {
58
-		$groupDN = 'cn=group,dc=foo,dc=bar';
59
-
60
-		$this->enableGroups();
61
-
62
-		$this->access->expects($this->any())
63
-			->method('groupname2dn')
64
-			->willReturn($groupDN);
65
-		$this->access->expects($this->any())
66
-			->method('readAttribute')
67
-			->willReturnCallback(function ($dn) use ($groupDN) {
68
-				if ($dn === $groupDN) {
69
-					return [
70
-						'uid=u11,ou=users,dc=foo,dc=bar',
71
-						'uid=u22,ou=users,dc=foo,dc=bar',
72
-						'uid=u33,ou=users,dc=foo,dc=bar',
73
-						'uid=u34,ou=users,dc=foo,dc=bar'
74
-					];
75
-				}
76
-				return [];
77
-			});
78
-		$this->access->expects($this->any())
79
-			->method('isDNPartOfBase')
80
-			->willReturn(true);
81
-		// for primary groups
82
-		$this->access->expects($this->once())
83
-			->method('countUsers')
84
-			->willReturn(2);
85
-
86
-		$this->access->userManager->expects($this->any())
87
-			->method('getAttributes')
88
-			->willReturn(['displayName', 'mail']);
89
-
90
-		$this->initBackend();
91
-		$users = $this->groupBackend->countUsersInGroup('group');
92
-
93
-		$this->assertSame(6, $users);
94
-	}
95
-
96
-	/**
97
-	 * @return MockObject|Access
98
-	 */
99
-	private function getAccessMock() {
100
-		$lw = $this->createMock(ILDAPWrapper::class);
101
-		$connector = $this->getMockBuilder(Connection::class)
102
-			->setConstructorArgs([$lw, '', null])
103
-			->getMock();
104
-
105
-		$this->access = $this->createMock(Access::class);
106
-		$this->access->connection = $connector;
107
-		$this->access->userManager = $this->createMock(Manager::class);
108
-
109
-		return $this->access;
110
-	}
111
-
112
-	private function enableGroups(): void {
113
-		$this->access->connection->expects($this->any())
114
-			->method('__get')
115
-			->willReturnCallback(function ($name) {
116
-				if ($name === 'ldapDynamicGroupMemberURL') {
117
-					return '';
118
-				} elseif ($name === 'ldapBaseGroups') {
119
-					return [];
120
-				}
121
-				return 1;
122
-			});
123
-	}
124
-
125
-	public function testCountWithSearchString(): void {
126
-		$this->enableGroups();
127
-
128
-		$this->access->expects($this->any())
129
-			->method('groupname2dn')
130
-			->willReturn('cn=group,dc=foo,dc=bar');
131
-		$this->access->expects($this->any())
132
-			->method('fetchListOfUsers')
133
-			->willReturn([]);
134
-		$this->access->expects($this->any())
135
-			->method('readAttribute')
136
-			->willReturnCallback(function ($name) {
137
-				//the search operation will call readAttribute, thus we need
138
-				//to analyze the "dn". All other times we just need to return
139
-				//something that is neither null or false, but once an array
140
-				//with the users in the group – so we do so all other times for
141
-				//simplicity.
142
-				if (str_starts_with($name, 'u')) {
143
-					return strpos($name, '3');
144
-				}
145
-				return ['u11', 'u22', 'u33', 'u34'];
146
-			});
147
-		$this->access->expects($this->any())
148
-			->method('dn2username')
149
-			->willReturnCallback(function () {
150
-				return 'foobar' . Server::get(ISecureRandom::class)->generate(7);
151
-			});
152
-		$this->access->expects($this->any())
153
-			->method('isDNPartOfBase')
154
-			->willReturn(true);
155
-		$this->access->expects($this->any())
156
-			->method('escapeFilterPart')
157
-			->willReturnArgument(0);
158
-
159
-		$this->access->userManager->expects($this->any())
160
-			->method('getAttributes')
161
-			->willReturn(['displayName', 'mail']);
162
-
163
-		$this->initBackend();
164
-		$users = $this->groupBackend->countUsersInGroup('group', '3');
165
-
166
-		$this->assertSame(2, $users);
167
-	}
168
-
169
-	public function testCountUsersWithPlugin(): void {
170
-		/** @var GroupPluginManager|MockObject $pluginManager */
171
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
172
-			->onlyMethods(['implementsActions', 'countUsersInGroup'])
173
-			->getMock();
174
-
175
-		$this->pluginManager->expects($this->once())
176
-			->method('implementsActions')
177
-			->with(GroupInterface::COUNT_USERS)
178
-			->willReturn(true);
179
-
180
-		$this->pluginManager->expects($this->once())
181
-			->method('countUsersInGroup')
182
-			->with('gid', 'search')
183
-			->willReturn(42);
184
-
185
-		$this->initBackend();
186
-		$this->assertEquals($this->groupBackend->countUsersInGroup('gid', 'search'), 42);
187
-	}
188
-
189
-	public function testGidNumber2NameSuccess(): void {
190
-		$this->enableGroups();
191
-
192
-		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
193
-
194
-		$this->access->expects($this->once())
195
-			->method('searchGroups')
196
-			->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]);
197
-
198
-		$this->access->expects($this->once())
199
-			->method('dn2groupname')
200
-			->with('cn=foo,dc=barfoo,dc=bar')
201
-			->willReturn('MyGroup');
202
-
203
-		$this->initBackend();
204
-		$group = $this->groupBackend->gidNumber2Name('3117', $userDN);
205
-
206
-		$this->assertSame('MyGroup', $group);
207
-	}
208
-
209
-	public function testGidNumberID2NameNoGroup(): void {
210
-		$this->enableGroups();
211
-
212
-		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
213
-
214
-		$this->access->expects($this->once())
215
-			->method('searchGroups')
216
-			->willReturn([]);
217
-
218
-		$this->access->expects($this->never())
219
-			->method('dn2groupname');
220
-
221
-		$this->initBackend();
222
-		$group = $this->groupBackend->gidNumber2Name('3117', $userDN);
38
+    private Access&MockObject $access;
39
+    private GroupPluginManager&MockObject $pluginManager;
40
+    private IConfig&MockObject $config;
41
+    private IUserManager&MockObject $ncUserManager;
42
+    private GroupLDAP $groupBackend;
43
+
44
+    public function setUp(): void {
45
+        parent::setUp();
46
+
47
+        $this->access = $this->getAccessMock();
48
+        $this->pluginManager = $this->createMock(GroupPluginManager::class);
49
+        $this->config = $this->createMock(IConfig::class);
50
+        $this->ncUserManager = $this->createMock(IUserManager::class);
51
+    }
52
+
53
+    public function initBackend(): void {
54
+        $this->groupBackend = new GroupLDAP($this->access, $this->pluginManager, $this->config, $this->ncUserManager);
55
+    }
56
+
57
+    public function testCountEmptySearchString(): void {
58
+        $groupDN = 'cn=group,dc=foo,dc=bar';
59
+
60
+        $this->enableGroups();
61
+
62
+        $this->access->expects($this->any())
63
+            ->method('groupname2dn')
64
+            ->willReturn($groupDN);
65
+        $this->access->expects($this->any())
66
+            ->method('readAttribute')
67
+            ->willReturnCallback(function ($dn) use ($groupDN) {
68
+                if ($dn === $groupDN) {
69
+                    return [
70
+                        'uid=u11,ou=users,dc=foo,dc=bar',
71
+                        'uid=u22,ou=users,dc=foo,dc=bar',
72
+                        'uid=u33,ou=users,dc=foo,dc=bar',
73
+                        'uid=u34,ou=users,dc=foo,dc=bar'
74
+                    ];
75
+                }
76
+                return [];
77
+            });
78
+        $this->access->expects($this->any())
79
+            ->method('isDNPartOfBase')
80
+            ->willReturn(true);
81
+        // for primary groups
82
+        $this->access->expects($this->once())
83
+            ->method('countUsers')
84
+            ->willReturn(2);
85
+
86
+        $this->access->userManager->expects($this->any())
87
+            ->method('getAttributes')
88
+            ->willReturn(['displayName', 'mail']);
89
+
90
+        $this->initBackend();
91
+        $users = $this->groupBackend->countUsersInGroup('group');
92
+
93
+        $this->assertSame(6, $users);
94
+    }
95
+
96
+    /**
97
+     * @return MockObject|Access
98
+     */
99
+    private function getAccessMock() {
100
+        $lw = $this->createMock(ILDAPWrapper::class);
101
+        $connector = $this->getMockBuilder(Connection::class)
102
+            ->setConstructorArgs([$lw, '', null])
103
+            ->getMock();
104
+
105
+        $this->access = $this->createMock(Access::class);
106
+        $this->access->connection = $connector;
107
+        $this->access->userManager = $this->createMock(Manager::class);
108
+
109
+        return $this->access;
110
+    }
111
+
112
+    private function enableGroups(): void {
113
+        $this->access->connection->expects($this->any())
114
+            ->method('__get')
115
+            ->willReturnCallback(function ($name) {
116
+                if ($name === 'ldapDynamicGroupMemberURL') {
117
+                    return '';
118
+                } elseif ($name === 'ldapBaseGroups') {
119
+                    return [];
120
+                }
121
+                return 1;
122
+            });
123
+    }
124
+
125
+    public function testCountWithSearchString(): void {
126
+        $this->enableGroups();
127
+
128
+        $this->access->expects($this->any())
129
+            ->method('groupname2dn')
130
+            ->willReturn('cn=group,dc=foo,dc=bar');
131
+        $this->access->expects($this->any())
132
+            ->method('fetchListOfUsers')
133
+            ->willReturn([]);
134
+        $this->access->expects($this->any())
135
+            ->method('readAttribute')
136
+            ->willReturnCallback(function ($name) {
137
+                //the search operation will call readAttribute, thus we need
138
+                //to analyze the "dn". All other times we just need to return
139
+                //something that is neither null or false, but once an array
140
+                //with the users in the group – so we do so all other times for
141
+                //simplicity.
142
+                if (str_starts_with($name, 'u')) {
143
+                    return strpos($name, '3');
144
+                }
145
+                return ['u11', 'u22', 'u33', 'u34'];
146
+            });
147
+        $this->access->expects($this->any())
148
+            ->method('dn2username')
149
+            ->willReturnCallback(function () {
150
+                return 'foobar' . Server::get(ISecureRandom::class)->generate(7);
151
+            });
152
+        $this->access->expects($this->any())
153
+            ->method('isDNPartOfBase')
154
+            ->willReturn(true);
155
+        $this->access->expects($this->any())
156
+            ->method('escapeFilterPart')
157
+            ->willReturnArgument(0);
158
+
159
+        $this->access->userManager->expects($this->any())
160
+            ->method('getAttributes')
161
+            ->willReturn(['displayName', 'mail']);
162
+
163
+        $this->initBackend();
164
+        $users = $this->groupBackend->countUsersInGroup('group', '3');
165
+
166
+        $this->assertSame(2, $users);
167
+    }
168
+
169
+    public function testCountUsersWithPlugin(): void {
170
+        /** @var GroupPluginManager|MockObject $pluginManager */
171
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
172
+            ->onlyMethods(['implementsActions', 'countUsersInGroup'])
173
+            ->getMock();
174
+
175
+        $this->pluginManager->expects($this->once())
176
+            ->method('implementsActions')
177
+            ->with(GroupInterface::COUNT_USERS)
178
+            ->willReturn(true);
179
+
180
+        $this->pluginManager->expects($this->once())
181
+            ->method('countUsersInGroup')
182
+            ->with('gid', 'search')
183
+            ->willReturn(42);
184
+
185
+        $this->initBackend();
186
+        $this->assertEquals($this->groupBackend->countUsersInGroup('gid', 'search'), 42);
187
+    }
188
+
189
+    public function testGidNumber2NameSuccess(): void {
190
+        $this->enableGroups();
191
+
192
+        $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
193
+
194
+        $this->access->expects($this->once())
195
+            ->method('searchGroups')
196
+            ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]);
197
+
198
+        $this->access->expects($this->once())
199
+            ->method('dn2groupname')
200
+            ->with('cn=foo,dc=barfoo,dc=bar')
201
+            ->willReturn('MyGroup');
202
+
203
+        $this->initBackend();
204
+        $group = $this->groupBackend->gidNumber2Name('3117', $userDN);
205
+
206
+        $this->assertSame('MyGroup', $group);
207
+    }
208
+
209
+    public function testGidNumberID2NameNoGroup(): void {
210
+        $this->enableGroups();
211
+
212
+        $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
213
+
214
+        $this->access->expects($this->once())
215
+            ->method('searchGroups')
216
+            ->willReturn([]);
217
+
218
+        $this->access->expects($this->never())
219
+            ->method('dn2groupname');
220
+
221
+        $this->initBackend();
222
+        $group = $this->groupBackend->gidNumber2Name('3117', $userDN);
223 223
 
224
-		$this->assertSame(false, $group);
225
-	}
224
+        $this->assertSame(false, $group);
225
+    }
226 226
 
227
-	public function testGidNumberID2NameNoName(): void {
228
-		$this->enableGroups();
227
+    public function testGidNumberID2NameNoName(): void {
228
+        $this->enableGroups();
229 229
 
230
-		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
230
+        $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
231 231
 
232
-		$this->access->expects($this->once())
233
-			->method('searchGroups')
234
-			->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]);
232
+        $this->access->expects($this->once())
233
+            ->method('searchGroups')
234
+            ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]);
235 235
 
236
-		$this->access->expects($this->once())
237
-			->method('dn2groupname')
238
-			->willReturn(false);
236
+        $this->access->expects($this->once())
237
+            ->method('dn2groupname')
238
+            ->willReturn(false);
239 239
 
240
-		$this->initBackend();
241
-		$group = $this->groupBackend->gidNumber2Name('3117', $userDN);
240
+        $this->initBackend();
241
+        $group = $this->groupBackend->gidNumber2Name('3117', $userDN);
242 242
 
243
-		$this->assertSame(false, $group);
244
-	}
243
+        $this->assertSame(false, $group);
244
+    }
245 245
 
246
-	public function testGetEntryGidNumberValue(): void {
247
-		$this->enableGroups();
246
+    public function testGetEntryGidNumberValue(): void {
247
+        $this->enableGroups();
248 248
 
249
-		$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
250
-		$attr = 'gidNumber';
249
+        $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
250
+        $attr = 'gidNumber';
251 251
 
252
-		$this->access->expects($this->once())
253
-			->method('readAttribute')
254
-			->with($dn, $attr)
255
-			->willReturn(['3117']);
252
+        $this->access->expects($this->once())
253
+            ->method('readAttribute')
254
+            ->with($dn, $attr)
255
+            ->willReturn(['3117']);
256 256
 
257
-		$this->initBackend();
258
-		$gid = $this->groupBackend->getGroupGidNumber($dn);
257
+        $this->initBackend();
258
+        $gid = $this->groupBackend->getGroupGidNumber($dn);
259 259
 
260
-		$this->assertSame('3117', $gid);
261
-	}
260
+        $this->assertSame('3117', $gid);
261
+    }
262 262
 
263
-	public function testGetEntryGidNumberNoValue(): void {
264
-		$this->enableGroups();
263
+    public function testGetEntryGidNumberNoValue(): void {
264
+        $this->enableGroups();
265 265
 
266
-		$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
267
-		$attr = 'gidNumber';
266
+        $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
267
+        $attr = 'gidNumber';
268 268
 
269
-		$this->access->expects($this->once())
270
-			->method('readAttribute')
271
-			->with($dn, $attr)
272
-			->willReturn(false);
269
+        $this->access->expects($this->once())
270
+            ->method('readAttribute')
271
+            ->with($dn, $attr)
272
+            ->willReturn(false);
273 273
 
274
-		$this->initBackend();
275
-		$gid = $this->groupBackend->getGroupGidNumber($dn);
274
+        $this->initBackend();
275
+        $gid = $this->groupBackend->getGroupGidNumber($dn);
276 276
 
277
-		$this->assertSame(false, $gid);
278
-	}
277
+        $this->assertSame(false, $gid);
278
+    }
279 279
 
280
-	public function testPrimaryGroupID2NameSuccessCache(): void {
281
-		$this->enableGroups();
280
+    public function testPrimaryGroupID2NameSuccessCache(): void {
281
+        $this->enableGroups();
282 282
 
283
-		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
284
-		$gid = '3117';
283
+        $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
284
+        $gid = '3117';
285 285
 
286
-		/** @var MockObject $connection */
287
-		$connection = $this->access->connection;
288
-		$connection->expects($this->once())
289
-			->method('getFromCache')
290
-			->with('primaryGroupIDtoName_' . $gid)
291
-			->willReturn('MyGroup');
286
+        /** @var MockObject $connection */
287
+        $connection = $this->access->connection;
288
+        $connection->expects($this->once())
289
+            ->method('getFromCache')
290
+            ->with('primaryGroupIDtoName_' . $gid)
291
+            ->willReturn('MyGroup');
292 292
 
293
-		$this->access->expects($this->never())
294
-			->method('getSID');
293
+        $this->access->expects($this->never())
294
+            ->method('getSID');
295 295
 
296
-		$this->access->expects($this->never())
297
-			->method('searchGroups');
296
+        $this->access->expects($this->never())
297
+            ->method('searchGroups');
298 298
 
299
-		$this->access->expects($this->never())
300
-			->method('dn2groupname');
299
+        $this->access->expects($this->never())
300
+            ->method('dn2groupname');
301 301
 
302
-		$this->initBackend();
303
-		$group = $this->groupBackend->primaryGroupID2Name($gid, $userDN);
302
+        $this->initBackend();
303
+        $group = $this->groupBackend->primaryGroupID2Name($gid, $userDN);
304 304
 
305
-		$this->assertSame('MyGroup', $group);
306
-	}
305
+        $this->assertSame('MyGroup', $group);
306
+    }
307 307
 
308
-	public function testPrimaryGroupID2NameSuccess(): void {
309
-		$this->enableGroups();
308
+    public function testPrimaryGroupID2NameSuccess(): void {
309
+        $this->enableGroups();
310 310
 
311
-		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
311
+        $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
312 312
 
313
-		$this->access->expects($this->once())
314
-			->method('getSID')
315
-			->with($userDN)
316
-			->willReturn('S-1-5-21-249921958-728525901-1594176202');
313
+        $this->access->expects($this->once())
314
+            ->method('getSID')
315
+            ->with($userDN)
316
+            ->willReturn('S-1-5-21-249921958-728525901-1594176202');
317 317
 
318
-		$this->access->expects($this->once())
319
-			->method('searchGroups')
320
-			->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]);
318
+        $this->access->expects($this->once())
319
+            ->method('searchGroups')
320
+            ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]);
321 321
 
322
-		$this->access->expects($this->once())
323
-			->method('dn2groupname')
324
-			->with('cn=foo,dc=barfoo,dc=bar')
325
-			->willReturn('MyGroup');
322
+        $this->access->expects($this->once())
323
+            ->method('dn2groupname')
324
+            ->with('cn=foo,dc=barfoo,dc=bar')
325
+            ->willReturn('MyGroup');
326 326
 
327
-		$this->initBackend();
328
-		$group = $this->groupBackend->primaryGroupID2Name('3117', $userDN);
327
+        $this->initBackend();
328
+        $group = $this->groupBackend->primaryGroupID2Name('3117', $userDN);
329 329
 
330
-		$this->assertSame('MyGroup', $group);
331
-	}
330
+        $this->assertSame('MyGroup', $group);
331
+    }
332 332
 
333
-	public function testPrimaryGroupID2NameNoSID(): void {
334
-		$this->enableGroups();
333
+    public function testPrimaryGroupID2NameNoSID(): void {
334
+        $this->enableGroups();
335 335
 
336
-		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
336
+        $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
337 337
 
338
-		$this->access->expects($this->once())
339
-			->method('getSID')
340
-			->with($userDN)
341
-			->willReturn(false);
338
+        $this->access->expects($this->once())
339
+            ->method('getSID')
340
+            ->with($userDN)
341
+            ->willReturn(false);
342 342
 
343
-		$this->access->expects($this->never())
344
-			->method('searchGroups');
343
+        $this->access->expects($this->never())
344
+            ->method('searchGroups');
345 345
 
346
-		$this->access->expects($this->never())
347
-			->method('dn2groupname');
346
+        $this->access->expects($this->never())
347
+            ->method('dn2groupname');
348 348
 
349
-		$this->initBackend();
350
-		$group = $this->groupBackend->primaryGroupID2Name('3117', $userDN);
349
+        $this->initBackend();
350
+        $group = $this->groupBackend->primaryGroupID2Name('3117', $userDN);
351 351
 
352
-		$this->assertSame(false, $group);
353
-	}
352
+        $this->assertSame(false, $group);
353
+    }
354 354
 
355
-	public function testPrimaryGroupID2NameNoGroup(): void {
356
-		$this->enableGroups();
355
+    public function testPrimaryGroupID2NameNoGroup(): void {
356
+        $this->enableGroups();
357 357
 
358
-		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
358
+        $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
359 359
 
360
-		$this->access->expects($this->once())
361
-			->method('getSID')
362
-			->with($userDN)
363
-			->willReturn('S-1-5-21-249921958-728525901-1594176202');
360
+        $this->access->expects($this->once())
361
+            ->method('getSID')
362
+            ->with($userDN)
363
+            ->willReturn('S-1-5-21-249921958-728525901-1594176202');
364 364
 
365
-		$this->access->expects($this->once())
366
-			->method('searchGroups')
367
-			->willReturn([]);
365
+        $this->access->expects($this->once())
366
+            ->method('searchGroups')
367
+            ->willReturn([]);
368 368
 
369
-		$this->access->expects($this->never())
370
-			->method('dn2groupname');
369
+        $this->access->expects($this->never())
370
+            ->method('dn2groupname');
371 371
 
372
-		$this->initBackend();
373
-		$group = $this->groupBackend->primaryGroupID2Name('3117', $userDN);
372
+        $this->initBackend();
373
+        $group = $this->groupBackend->primaryGroupID2Name('3117', $userDN);
374 374
 
375
-		$this->assertSame(false, $group);
376
-	}
375
+        $this->assertSame(false, $group);
376
+    }
377 377
 
378
-	public function testPrimaryGroupID2NameNoName(): void {
379
-		$this->enableGroups();
378
+    public function testPrimaryGroupID2NameNoName(): void {
379
+        $this->enableGroups();
380 380
 
381
-		$userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
381
+        $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
382 382
 
383
-		$this->access->expects($this->once())
384
-			->method('getSID')
385
-			->with($userDN)
386
-			->willReturn('S-1-5-21-249921958-728525901-1594176202');
383
+        $this->access->expects($this->once())
384
+            ->method('getSID')
385
+            ->with($userDN)
386
+            ->willReturn('S-1-5-21-249921958-728525901-1594176202');
387 387
 
388
-		$this->access->expects($this->once())
389
-			->method('searchGroups')
390
-			->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]);
388
+        $this->access->expects($this->once())
389
+            ->method('searchGroups')
390
+            ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]);
391 391
 
392
-		$this->access->expects($this->once())
393
-			->method('dn2groupname')
394
-			->willReturn(false);
392
+        $this->access->expects($this->once())
393
+            ->method('dn2groupname')
394
+            ->willReturn(false);
395 395
 
396
-		$this->initBackend();
397
-		$group = $this->groupBackend->primaryGroupID2Name('3117', $userDN);
398
-
399
-		$this->assertSame(false, $group);
400
-	}
401
-
402
-	public function testGetEntryGroupIDValue(): void {
403
-		//tests getEntryGroupID via getGroupPrimaryGroupID
404
-		//which is basically identical to getUserPrimaryGroupIDs
405
-		$this->enableGroups();
406
-
407
-		$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
408
-		$attr = 'primaryGroupToken';
409
-
410
-		$this->access->expects($this->once())
411
-			->method('readAttribute')
412
-			->with($dn, $attr)
413
-			->willReturn(['3117']);
414
-
415
-		$this->initBackend();
416
-		$gid = $this->groupBackend->getGroupPrimaryGroupID($dn);
417
-
418
-		$this->assertSame('3117', $gid);
419
-	}
420
-
421
-	public function testGetEntryGroupIDNoValue(): void {
422
-		//tests getEntryGroupID via getGroupPrimaryGroupID
423
-		//which is basically identical to getUserPrimaryGroupIDs
424
-		$this->enableGroups();
425
-
426
-		$dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
427
-		$attr = 'primaryGroupToken';
428
-
429
-		$this->access->expects($this->once())
430
-			->method('readAttribute')
431
-			->with($dn, $attr)
432
-			->willReturn(false);
433
-
434
-		$this->initBackend();
435
-		$gid = $this->groupBackend->getGroupPrimaryGroupID($dn);
436
-
437
-		$this->assertSame(false, $gid);
438
-	}
439
-
440
-	/**
441
-	 * tests whether Group Backend behaves correctly when cache with uid and gid
442
-	 * is hit
443
-	 */
444
-	public function testInGroupHitsUidGidCache(): void {
445
-		$this->enableGroups();
446
-
447
-		$uid = 'someUser';
448
-		$gid = 'someGroup';
449
-		$cacheKey = 'inGroup' . $uid . ':' . $gid;
450
-
451
-		$this->access->connection->expects($this->once())
452
-			->method('getFromCache')
453
-			->with($cacheKey)
454
-			->willReturn(true);
455
-
456
-		$this->access->expects($this->never())
457
-			->method('username2dn');
458
-
459
-		$this->initBackend();
460
-		$this->groupBackend->inGroup($uid, $gid);
461
-	}
462
-
463
-	public static function groupWithMembersProvider(): array {
464
-		return [
465
-			[
466
-				'someGroup',
467
-				'cn=someGroup,ou=allTheGroups,ou=someDepartment,dc=someDomain,dc=someTld',
468
-				[
469
-					'uid=oneUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld',
470
-					'uid=someUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld',
471
-					'uid=anotherUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld',
472
-					'uid=differentUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld',
473
-				],
474
-			],
475
-		];
476
-	}
477
-
478
-	#[\PHPUnit\Framework\Attributes\DataProvider('groupWithMembersProvider')]
479
-	public function testInGroupMember(string $gid, string $groupDn, array $memberDNs): void {
480
-		$uid = 'someUser';
481
-		$userDn = $memberDNs[0];
482
-
483
-		$this->access->connection->expects($this->any())
484
-			->method('__get')
485
-			->willReturnCallback(function ($name) {
486
-				switch ($name) {
487
-					case 'ldapGroupMemberAssocAttr':
488
-						return 'member';
489
-					case 'ldapDynamicGroupMemberURL':
490
-						return '';
491
-					case 'hasPrimaryGroups':
492
-					case 'ldapNestedGroups':
493
-						return 0;
494
-					default:
495
-						return 1;
496
-				}
497
-			});
498
-		$this->access->connection->expects($this->any())
499
-			->method('getFromCache')
500
-			->willReturn(null);
501
-
502
-		$this->access->expects($this->once())
503
-			->method('username2dn')
504
-			->with($uid)
505
-			->willReturn($userDn);
506
-		$this->access->expects($this->once())
507
-			->method('groupname2dn')
508
-			->willReturn($groupDn);
509
-		$this->access->expects($this->any())
510
-			->method('readAttribute')
511
-			->willReturn($memberDNs);
512
-
513
-		$this->initBackend();
514
-		$this->assertTrue($this->groupBackend->inGroup($uid, $gid));
515
-	}
516
-
517
-	#[\PHPUnit\Framework\Attributes\DataProvider('groupWithMembersProvider')]
518
-	public function testInGroupMemberNot(string $gid, string $groupDn, array $memberDNs): void {
519
-		$uid = 'unelatedUser';
520
-		$userDn = 'uid=unrelatedUser,ou=unrelatedTeam,ou=unrelatedDepartment,dc=someDomain,dc=someTld';
521
-
522
-		$this->access->connection->expects($this->any())
523
-			->method('__get')
524
-			->willReturnCallback(function ($name) {
525
-				switch ($name) {
526
-					case 'ldapGroupMemberAssocAttr':
527
-						return 'member';
528
-					case 'ldapDynamicGroupMemberURL':
529
-						return '';
530
-					case 'hasPrimaryGroups':
531
-					case 'ldapNestedGroups':
532
-						return 0;
533
-					default:
534
-						return 1;
535
-				}
536
-			});
537
-		$this->access->connection->expects($this->any())
538
-			->method('getFromCache')
539
-			->willReturn(null);
540
-
541
-		$this->access->expects($this->once())
542
-			->method('username2dn')
543
-			->with($uid)
544
-			->willReturn($userDn);
545
-		$this->access->expects($this->once())
546
-			->method('groupname2dn')
547
-			->willReturn($groupDn);
548
-		$this->access->expects($this->any())
549
-			->method('readAttribute')
550
-			->willReturn($memberDNs);
551
-
552
-		$this->initBackend();
553
-		$this->assertFalse($this->groupBackend->inGroup($uid, $gid));
554
-	}
555
-
556
-	#[\PHPUnit\Framework\Attributes\DataProvider('groupWithMembersProvider')]
557
-	public function testInGroupMemberUid(string $gid, string $groupDn, array $memberDNs): void {
558
-		$memberUids = [];
559
-		$userRecords = [];
560
-		foreach ($memberDNs as $dn) {
561
-			$memberUids[] = ldap_explode_dn($dn, 0)[0];
562
-			$userRecords[] = ['dn' => [$dn]];
563
-		}
564
-
565
-		$uid = 'someUser';
566
-		$userDn = $memberDNs[0];
567
-
568
-		$this->access->connection->expects($this->any())
569
-			->method('__get')
570
-			->willReturnCallback(function ($name) {
571
-				switch ($name) {
572
-					case 'ldapGroupMemberAssocAttr':
573
-						return 'memberUid';
574
-					case 'ldapDynamicGroupMemberURL':
575
-						return '';
576
-					case 'ldapLoginFilter':
577
-						return 'uid=%uid';
578
-					case 'hasPrimaryGroups':
579
-					case 'ldapNestedGroups':
580
-						return 0;
581
-					default:
582
-						return 1;
583
-				}
584
-			});
585
-		$this->access->connection->expects($this->any())
586
-			->method('getFromCache')
587
-			->willReturn(null);
588
-
589
-		$this->access->userManager->expects($this->any())
590
-			->method('getAttributes')
591
-			->willReturn(['uid', 'mail', 'displayname']);
592
-
593
-		$this->access->expects($this->once())
594
-			->method('username2dn')
595
-			->with($uid)
596
-			->willReturn($userDn);
597
-		$this->access->expects($this->once())
598
-			->method('groupname2dn')
599
-			->willReturn($groupDn);
600
-		$this->access->expects($this->any())
601
-			->method('readAttribute')
602
-			->willReturn($memberUids);
603
-		$this->access->expects($this->any())
604
-			->method('fetchListOfUsers')
605
-			->willReturn($userRecords);
606
-		$this->access->expects($this->any())
607
-			->method('combineFilterWithOr')
608
-			->willReturn('(|(pseudo=filter)(filter=pseudo))');
609
-
610
-		$this->initBackend();
611
-		$this->assertTrue($this->groupBackend->inGroup($uid, $gid));
612
-	}
613
-
614
-	public function testGetGroupsWithOffset(): void {
615
-		$this->enableGroups();
616
-
617
-		$this->access->expects($this->once())
618
-			->method('nextcloudGroupNames')
619
-			->willReturn(['group1', 'group2']);
620
-
621
-		$this->initBackend();
622
-		$groups = $this->groupBackend->getGroups('', 2, 2);
623
-
624
-		$this->assertSame(2, count($groups));
625
-	}
626
-
627
-	/**
628
-	 * tests that a user listing is complete, if all its members have the group
629
-	 * as their primary.
630
-	 */
631
-	public function testUsersInGroupPrimaryMembersOnly(): void {
632
-		$this->enableGroups();
633
-
634
-		$this->access->connection->expects($this->any())
635
-			->method('getFromCache')
636
-			->willReturn(null);
637
-		$this->access->expects($this->any())
638
-			->method('readAttribute')
639
-			->willReturnCallback(function ($dn, $attr) {
640
-				if ($attr === 'primaryGroupToken') {
641
-					return [1337];
642
-				} elseif ($attr === 'gidNumber') {
643
-					return [4211];
644
-				}
645
-				return [];
646
-			});
647
-		$this->access->expects($this->any())
648
-			->method('groupname2dn')
649
-			->willReturn('cn=foobar,dc=foo,dc=bar');
650
-		$this->access->expects($this->exactly(2))
651
-			->method('nextcloudUserNames')
652
-			->willReturnOnConsecutiveCalls(['lisa', 'bart', 'kira', 'brad'], ['walle', 'dino', 'xenia']);
653
-		$this->access->expects($this->any())
654
-			->method('isDNPartOfBase')
655
-			->willReturn(true);
656
-		$this->access->expects($this->any())
657
-			->method('combineFilterWithAnd')
658
-			->willReturn('pseudo=filter');
659
-
660
-		$this->access->userManager->expects($this->any())
661
-			->method('getAttributes')
662
-			->willReturn(['displayName', 'mail']);
663
-
664
-		$this->initBackend();
665
-		$users = $this->groupBackend->usersInGroup('foobar');
666
-
667
-		$this->assertSame(7, count($users));
668
-	}
669
-
670
-	/**
671
-	 * tests that a user listing is complete, if all its members have the group
672
-	 * as their primary.
673
-	 */
674
-	public function testUsersInGroupPrimaryAndUnixMembers(): void {
675
-		$this->enableGroups();
676
-
677
-		$this->access->connection->expects($this->any())
678
-			->method('getFromCache')
679
-			->willReturn(null);
680
-		$this->access->expects($this->any())
681
-			->method('readAttribute')
682
-			->willReturnCallback(function ($dn, $attr) {
683
-				if ($attr === 'primaryGroupToken') {
684
-					return [1337];
685
-				}
686
-				return [];
687
-			});
688
-		$this->access->expects($this->any())
689
-			->method('groupname2dn')
690
-			->willReturn('cn=foobar,dc=foo,dc=bar');
691
-		$this->access->expects($this->once())
692
-			->method('nextcloudUserNames')
693
-			->willReturn(['lisa', 'bart', 'kira', 'brad']);
694
-		$this->access->expects($this->any())
695
-			->method('isDNPartOfBase')
696
-			->willReturn(true);
697
-		$this->access->expects($this->any())
698
-			->method('combineFilterWithAnd')
699
-			->willReturn('pseudo=filter');
700
-
701
-		$this->access->userManager->expects($this->any())
702
-			->method('getAttributes')
703
-			->willReturn(['displayName', 'mail']);
704
-
705
-		$this->initBackend();
706
-		$users = $this->groupBackend->usersInGroup('foobar');
707
-
708
-		$this->assertSame(4, count($users));
709
-	}
710
-
711
-	/**
712
-	 * tests that a user counting is complete, if all its members have the group
713
-	 * as their primary.
714
-	 */
715
-	public function testCountUsersInGroupPrimaryMembersOnly(): void {
716
-		$this->enableGroups();
717
-
718
-		$this->access->connection->expects($this->any())
719
-			->method('getFromCache')
720
-			->willReturn(null);
721
-
722
-		$this->access->expects($this->any())
723
-			->method('readAttribute')
724
-			->willReturnCallback(function ($dn, $attr) {
725
-				if ($attr === 'primaryGroupToken') {
726
-					return [1337];
727
-				}
728
-				return [];
729
-			});
730
-		$this->access->expects($this->any())
731
-			->method('groupname2dn')
732
-			->willReturn('cn=foobar,dc=foo,dc=bar');
733
-		$this->access->expects($this->once())
734
-			->method('countUsers')
735
-			->willReturn(4);
736
-		$this->access->expects($this->any())
737
-			->method('isDNPartOfBase')
738
-			->willReturn(true);
739
-
740
-		$this->access->userManager->expects($this->any())
741
-			->method('getAttributes')
742
-			->willReturn(['displayName', 'mail']);
743
-
744
-		$this->initBackend();
745
-		$users = $this->groupBackend->countUsersInGroup('foobar');
746
-
747
-		$this->assertSame(4, $users);
748
-	}
749
-
750
-	public function testGetUserGroupsMemberOf(): void {
751
-		$this->enableGroups();
752
-
753
-		$dn = 'cn=userX,dc=foobar';
754
-
755
-		$this->access->connection->hasPrimaryGroups = false;
756
-		$this->access->connection->hasGidNumber = false;
757
-
758
-		$expectedGroups = ['cn=groupA,dc=foobar', 'cn=groupB,dc=foobar'];
759
-
760
-		$this->access->expects($this->any())
761
-			->method('username2dn')
762
-			->willReturn($dn);
763
-		$this->access->expects($this->exactly(5))
764
-			->method('readAttribute')->willReturnOnConsecutiveCalls($expectedGroups, [], [], [], []);
765
-		$this->access->expects($this->any())
766
-			->method('dn2groupname')
767
-			->willReturnArgument(0);
768
-		$this->access->expects($this->any())
769
-			->method('groupname2dn')
770
-			->willReturnArgument(0);
771
-		$this->access->expects($this->any())
772
-			->method('isDNPartOfBase')
773
-			->willReturn(true);
774
-
775
-		$this->config->expects($this->once())
776
-			->method('setUserValue')
777
-			->with('userX', 'user_ldap', 'cached-group-memberships-', \json_encode($expectedGroups));
778
-
779
-		$this->initBackend();
780
-		$groups = $this->groupBackend->getUserGroups('userX');
781
-
782
-		$this->assertSame(2, count($groups));
783
-	}
784
-
785
-	public function testGetUserGroupsMemberOfDisabled(): void {
786
-		$this->access->connection->expects($this->any())
787
-			->method('__get')
788
-			->willReturnCallback(function ($name) {
789
-				if ($name === 'useMemberOfToDetectMembership') {
790
-					return 0;
791
-				} elseif ($name === 'ldapDynamicGroupMemberURL') {
792
-					return '';
793
-				}
794
-				return 1;
795
-			});
796
-
797
-		$dn = 'cn=userX,dc=foobar';
798
-
799
-		$this->access->connection->hasPrimaryGroups = false;
800
-		$this->access->connection->hasGidNumber = false;
801
-
802
-		$this->access->expects($this->once())
803
-			->method('username2dn')
804
-			->willReturn($dn);
805
-		$this->access->expects($this->never())
806
-			->method('readAttribute')
807
-			->with($dn, 'memberOf');
808
-		$this->access->expects($this->once())
809
-			->method('nextcloudGroupNames')
810
-			->willReturn([]);
811
-
812
-		// empty group result should not be oer
813
-		$this->config->expects($this->once())
814
-			->method('setUserValue')
815
-			->with('userX', 'user_ldap', 'cached-group-memberships-', '[]');
816
-
817
-		$ldapUser = $this->createMock(User::class);
818
-
819
-		$this->access->userManager->expects($this->any())
820
-			->method('get')
821
-			->with('userX')
822
-			->willReturn($ldapUser);
823
-
824
-		$userBackend = $this->createMock(User_Proxy::class);
825
-		$userBackend->expects($this->once())
826
-			->method('userExistsOnLDAP')
827
-			->with('userX', true)
828
-			->willReturn(true);
829
-
830
-		$ncUser = $this->createMock(IUser::class);
831
-		$ncUser->expects($this->any())
832
-			->method('getBackend')
833
-			->willReturn($userBackend);
834
-
835
-		$this->ncUserManager->expects($this->once())
836
-			->method('get')
837
-			->with('userX')
838
-			->willReturn($ncUser);
839
-
840
-		$this->initBackend();
841
-		$this->groupBackend->getUserGroups('userX');
842
-	}
843
-
844
-	public function testGetUserGroupsOfflineUser(): void {
845
-		$this->enableGroups();
846
-
847
-		$offlineUser = $this->createMock(OfflineUser::class);
848
-
849
-		$this->config->expects($this->any())
850
-			->method('getUserValue')
851
-			->with('userX', 'user_ldap', 'cached-group-memberships-', $this->anything())
852
-			->willReturn(\json_encode(['groupB', 'groupF']));
853
-
854
-		$this->access->userManager->expects($this->any())
855
-			->method('get')
856
-			->with('userX')
857
-			->willReturn($offlineUser);
858
-
859
-		$this->initBackend();
860
-		$returnedGroups = $this->groupBackend->getUserGroups('userX');
861
-		$this->assertCount(2, $returnedGroups);
862
-		$this->assertContains('groupB', $returnedGroups);
863
-		$this->assertContains('groupF', $returnedGroups);
864
-	}
865
-
866
-	/**
867
-	 * regression tests against a case where a json object was stored instead of expected list
868
-	 * @see https://github.com/nextcloud/server/issues/42374
869
-	 */
870
-	public function testGetUserGroupsOfflineUserUnexpectedJson(): void {
871
-		$this->enableGroups();
872
-
873
-		$offlineUser = $this->createMock(OfflineUser::class);
874
-
875
-		$this->config->expects($this->any())
876
-			->method('getUserValue')
877
-			->with('userX', 'user_ldap', 'cached-group-memberships-', $this->anything())
878
-			// results in a json object: {"0":"groupB","2":"groupF"}
879
-			->willReturn(\json_encode([0 => 'groupB', 2 => 'groupF']));
880
-
881
-		$this->access->userManager->expects($this->any())
882
-			->method('get')
883
-			->with('userX')
884
-			->willReturn($offlineUser);
885
-
886
-		$this->initBackend();
887
-		$returnedGroups = $this->groupBackend->getUserGroups('userX');
888
-		$this->assertCount(2, $returnedGroups);
889
-		$this->assertContains('groupB', $returnedGroups);
890
-		$this->assertContains('groupF', $returnedGroups);
891
-	}
892
-
893
-	public function testGetUserGroupsUnrecognizedOfflineUser(): void {
894
-		$this->enableGroups();
895
-		$dn = 'cn=userX,dc=foobar';
896
-
897
-		$ldapUser = $this->createMock(User::class);
898
-
899
-		$userBackend = $this->createMock(User_Proxy::class);
900
-		$userBackend->expects($this->once())
901
-			->method('userExistsOnLDAP')
902
-			->with('userX', true)
903
-			->willReturn(false);
904
-
905
-		$ncUser = $this->createMock(IUser::class);
906
-		$ncUser->expects($this->any())
907
-			->method('getBackend')
908
-			->willReturn($userBackend);
909
-
910
-		$this->config->expects($this->atLeastOnce())
911
-			->method('getUserValue')
912
-			->with('userX', 'user_ldap', 'cached-group-memberships-', $this->anything())
913
-			->willReturn(\json_encode(['groupB', 'groupF']));
914
-
915
-		$this->access->expects($this->any())
916
-			->method('username2dn')
917
-			->willReturn($dn);
918
-
919
-		$this->access->userManager->expects($this->any())
920
-			->method('get')
921
-			->with('userX')
922
-			->willReturn($ldapUser);
923
-
924
-		$this->ncUserManager->expects($this->once())
925
-			->method('get')
926
-			->with('userX')
927
-			->willReturn($ncUser);
928
-
929
-		$this->initBackend();
930
-		$returnedGroups = $this->groupBackend->getUserGroups('userX');
931
-		$this->assertCount(2, $returnedGroups);
932
-		$this->assertContains('groupB', $returnedGroups);
933
-		$this->assertContains('groupF', $returnedGroups);
934
-	}
935
-
936
-	public static function nestedGroupsProvider(): array {
937
-		return [
938
-			[true],
939
-			[false],
940
-		];
941
-	}
942
-
943
-	#[\PHPUnit\Framework\Attributes\DataProvider('nestedGroupsProvider')]
944
-	public function testGetGroupsByMember(bool $nestedGroups): void {
945
-		$groupFilter = '(&(objectclass=nextcloudGroup)(nextcloudEnabled=TRUE))';
946
-		$this->access->connection->expects($this->any())
947
-			->method('__get')
948
-			->willReturnCallback(function (string $name) use ($nestedGroups, $groupFilter) {
949
-				switch ($name) {
950
-					case 'useMemberOfToDetectMembership':
951
-						return 0;
952
-					case 'ldapDynamicGroupMemberURL':
953
-						return '';
954
-					case 'ldapNestedGroups':
955
-						return (int)$nestedGroups;
956
-					case 'ldapGroupMemberAssocAttr':
957
-						return 'member';
958
-					case 'ldapGroupFilter':
959
-						return $groupFilter;
960
-					case 'ldapBaseGroups':
961
-						return [];
962
-					case 'ldapGroupDisplayName':
963
-						return 'cn';
964
-				}
965
-				return 1;
966
-			});
967
-
968
-		$dn = 'cn=userX,dc=foobar';
969
-
970
-		$this->access->connection->hasPrimaryGroups = false;
971
-		$this->access->connection->hasGidNumber = false;
972
-
973
-		$this->access->expects($this->exactly(2))
974
-			->method('username2dn')
975
-			->willReturn($dn);
976
-		$this->access->expects($this->any())
977
-			->method('readAttribute')
978
-			->willReturn([]);
979
-		$this->access->expects($this->any())
980
-			->method('combineFilterWithAnd')
981
-			->willReturnCallback(function (array $filterParts) {
982
-				// ⚠ returns a pseudo-filter only, not real LDAP Filter syntax
983
-				return implode('&', $filterParts);
984
-			});
985
-
986
-		$group1 = [
987
-			'cn' => 'group1',
988
-			'dn' => ['cn=group1,ou=groups,dc=domain,dc=com'],
989
-			'member' => [$dn],
990
-		];
991
-		$group2 = [
992
-			'cn' => 'group2',
993
-			'dn' => ['cn=group2,ou=groups,dc=domain,dc=com'],
994
-			'member' => [$dn],
995
-		];
996
-		$group3 = [
997
-			'cn' => 'group3',
998
-			'dn' => ['cn=group3,ou=groups,dc=domain,dc=com'],
999
-			'member' => [$group2['dn'][0]],
1000
-		];
1001
-
1002
-		$expectedGroups = ($nestedGroups ? [$group1, $group2, $group3] : [$group1, $group2]);
1003
-		$expectedGroupsNames = ($nestedGroups ? ['group1', 'group2', 'group3'] : ['group1', 'group2']);
1004
-
1005
-		$this->access->expects($this->any())
1006
-			->method('nextcloudGroupNames')
1007
-			->with($expectedGroups)
1008
-			->willReturn($expectedGroupsNames);
1009
-		$this->access->expects($nestedGroups ? $this->atLeastOnce() : $this->once())
1010
-			->method('fetchListOfGroups')
1011
-			->willReturnCallback(function ($filter, $attr, $limit, $offset) use ($nestedGroups, $groupFilter, $group1, $group2, $group3, $dn) {
1012
-				static $firstRun = true;
1013
-				if (!$nestedGroups) {
1014
-					// When nested groups are enabled, groups cannot be filtered early as it would
1015
-					// exclude intermediate groups. But we can, and should, when working with flat groups.
1016
-					$this->assertTrue(str_contains($filter, $groupFilter));
1017
-				}
1018
-				[$memberFilter] = explode('&', $filter);
1019
-				if ($memberFilter === 'member=' . $dn) {
1020
-					return [$group1, $group2];
1021
-					return [];
1022
-				} elseif ($memberFilter === 'member=' . $group2['dn'][0]) {
1023
-					return [$group3];
1024
-				} else {
1025
-					return [];
1026
-				}
1027
-			});
1028
-		$this->access->expects($this->any())
1029
-			->method('dn2groupname')
1030
-			->willReturnCallback(function (string $dn) {
1031
-				return ldap_explode_dn($dn, 1)[0];
1032
-			});
1033
-		$this->access->expects($this->any())
1034
-			->method('groupname2dn')
1035
-			->willReturnCallback(function (string $gid) use ($group1, $group2, $group3) {
1036
-				if ($gid === $group1['cn']) {
1037
-					return $group1['dn'][0];
1038
-				}
1039
-				if ($gid === $group2['cn']) {
1040
-					return $group2['dn'][0];
1041
-				}
1042
-				if ($gid === $group3['cn']) {
1043
-					return $group3['dn'][0];
1044
-				}
1045
-			});
1046
-		$this->access->expects($this->any())
1047
-			->method('isDNPartOfBase')
1048
-			->willReturn(true);
1049
-
1050
-		$this->initBackend();
1051
-		$groups = $this->groupBackend->getUserGroups('userX');
1052
-		$this->assertEquals($expectedGroupsNames, $groups);
1053
-
1054
-		$groupsAgain = $this->groupBackend->getUserGroups('userX');
1055
-		$this->assertEquals($expectedGroupsNames, $groupsAgain);
1056
-	}
1057
-
1058
-	public function testCreateGroupWithPlugin(): void {
1059
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1060
-			->onlyMethods(['implementsActions', 'createGroup'])
1061
-			->getMock();
1062
-
1063
-		$this->pluginManager->expects($this->once())
1064
-			->method('implementsActions')
1065
-			->with(GroupInterface::CREATE_GROUP)
1066
-			->willReturn(true);
1067
-
1068
-		$this->pluginManager->expects($this->once())
1069
-			->method('createGroup')
1070
-			->with('gid')
1071
-			->willReturn('result');
1072
-
1073
-		$this->initBackend();
1074
-		$this->assertTrue($this->groupBackend->createGroup('gid'));
1075
-	}
1076
-
1077
-
1078
-	public function testCreateGroupFailing(): void {
1079
-		$this->expectException(\Exception::class);
1080
-
1081
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1082
-			->onlyMethods(['implementsActions', 'createGroup'])
1083
-			->getMock();
1084
-
1085
-		$this->pluginManager->expects($this->once())
1086
-			->method('implementsActions')
1087
-			->with(GroupInterface::CREATE_GROUP)
1088
-			->willReturn(false);
1089
-
1090
-		$this->initBackend();
1091
-		$this->groupBackend->createGroup('gid');
1092
-	}
1093
-
1094
-	public function testDeleteGroupWithPlugin(): void {
1095
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1096
-			->onlyMethods(['implementsActions', 'deleteGroup'])
1097
-			->getMock();
1098
-
1099
-		$this->pluginManager->expects($this->once())
1100
-			->method('implementsActions')
1101
-			->with(GroupInterface::DELETE_GROUP)
1102
-			->willReturn(true);
1103
-
1104
-		$this->pluginManager->expects($this->once())
1105
-			->method('deleteGroup')
1106
-			->with('gid')
1107
-			->willReturn(true);
1108
-
1109
-		$mapper = $this->getMockBuilder(GroupMapping::class)
1110
-			->onlyMethods(['unmap'])
1111
-			->disableOriginalConstructor()
1112
-			->getMock();
1113
-
1114
-		$this->access->expects($this->any())
1115
-			->method('getGroupMapper')
1116
-			->willReturn($mapper);
1117
-
1118
-		$this->initBackend();
1119
-		$this->assertTrue($this->groupBackend->deleteGroup('gid'));
1120
-	}
1121
-
1122
-
1123
-	public function testDeleteGroupFailing(): void {
1124
-		$this->expectException(\Exception::class);
1125
-
1126
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1127
-			->onlyMethods(['implementsActions', 'deleteGroup'])
1128
-			->getMock();
1129
-
1130
-		$this->pluginManager->expects($this->once())
1131
-			->method('implementsActions')
1132
-			->with(GroupInterface::DELETE_GROUP)
1133
-			->willReturn(false);
1134
-
1135
-		$this->initBackend();
1136
-		$this->groupBackend->deleteGroup('gid');
1137
-	}
1138
-
1139
-	public function testAddToGroupWithPlugin(): void {
1140
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1141
-			->onlyMethods(['implementsActions', 'addToGroup'])
1142
-			->getMock();
1143
-
1144
-		$this->pluginManager->expects($this->once())
1145
-			->method('implementsActions')
1146
-			->with(GroupInterface::ADD_TO_GROUP)
1147
-			->willReturn(true);
1148
-
1149
-		$this->pluginManager->expects($this->once())
1150
-			->method('addToGroup')
1151
-			->with('uid', 'gid')
1152
-			->willReturn('result');
1153
-
1154
-		$this->initBackend();
1155
-		$this->assertEquals('result', $this->groupBackend->addToGroup('uid', 'gid'));
1156
-	}
1157
-
1158
-
1159
-	public function testAddToGroupFailing(): void {
1160
-		$this->expectException(\Exception::class);
1161
-
1162
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1163
-			->onlyMethods(['implementsActions', 'addToGroup'])
1164
-			->getMock();
1165
-
1166
-		$this->pluginManager->expects($this->once())
1167
-			->method('implementsActions')
1168
-			->with(GroupInterface::ADD_TO_GROUP)
1169
-			->willReturn(false);
1170
-
1171
-		$this->initBackend();
1172
-		$this->groupBackend->addToGroup('uid', 'gid');
1173
-	}
1174
-
1175
-	public function testRemoveFromGroupWithPlugin(): void {
1176
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1177
-			->onlyMethods(['implementsActions', 'removeFromGroup'])
1178
-			->getMock();
1179
-
1180
-		$this->pluginManager->expects($this->once())
1181
-			->method('implementsActions')
1182
-			->with(GroupInterface::REMOVE_FROM_GROUP)
1183
-			->willReturn(true);
1184
-
1185
-		$this->pluginManager->expects($this->once())
1186
-			->method('removeFromGroup')
1187
-			->with('uid', 'gid')
1188
-			->willReturn('result');
1189
-
1190
-		$this->initBackend();
1191
-		$this->assertEquals('result', $this->groupBackend->removeFromGroup('uid', 'gid'));
1192
-	}
1193
-
1194
-
1195
-	public function testRemoveFromGroupFailing(): void {
1196
-		$this->expectException(\Exception::class);
1197
-
1198
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1199
-			->onlyMethods(['implementsActions', 'removeFromGroup'])
1200
-			->getMock();
1201
-
1202
-		$this->pluginManager->expects($this->once())
1203
-			->method('implementsActions')
1204
-			->with(GroupInterface::REMOVE_FROM_GROUP)
1205
-			->willReturn(false);
1206
-
1207
-		$this->initBackend();
1208
-		$this->groupBackend->removeFromGroup('uid', 'gid');
1209
-	}
1210
-
1211
-	public function testGetGroupDetailsWithPlugin(): void {
1212
-		/** @var GroupPluginManager|MockObject $pluginManager */
1213
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1214
-			->onlyMethods(['implementsActions', 'getGroupDetails'])
1215
-			->getMock();
1216
-
1217
-		$this->pluginManager->expects($this->once())
1218
-			->method('implementsActions')
1219
-			->with(GroupInterface::GROUP_DETAILS)
1220
-			->willReturn(true);
1221
-
1222
-		$this->pluginManager->expects($this->once())
1223
-			->method('getGroupDetails')
1224
-			->with('gid')
1225
-			->willReturn('result');
1226
-
1227
-		$this->initBackend();
1228
-		$this->assertEquals('result', $this->groupBackend->getGroupDetails('gid'));
1229
-	}
1230
-
1231
-	public function testGetGroupDetailsFailing(): void {
1232
-		$this->expectException(\Exception::class);
1233
-
1234
-		$this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1235
-			->onlyMethods(['implementsActions', 'getGroupDetails'])
1236
-			->getMock();
1237
-
1238
-		$this->pluginManager->expects($this->once())
1239
-			->method('implementsActions')
1240
-			->with(GroupInterface::GROUP_DETAILS)
1241
-			->willReturn(false);
1242
-
1243
-		$this->initBackend();
1244
-		$this->groupBackend->getGroupDetails('gid');
1245
-	}
1246
-
1247
-	public static function groupMemberProvider(): array {
1248
-		$base = 'dc=species,dc=earth';
1249
-
1250
-		$birdsDn = [
1251
-			'uid=3723,' . $base,
1252
-			'uid=8372,' . $base,
1253
-			'uid=8427,' . $base,
1254
-			'uid=2333,' . $base,
1255
-			'uid=4754,' . $base,
1256
-		];
1257
-		$birdsUid = [
1258
-			'3723',
1259
-			'8372',
1260
-			'8427',
1261
-			'2333',
1262
-			'4754',
1263
-		];
1264
-		$animalsDn = [
1265
-			'uid=lion,' . $base,
1266
-			'uid=tiger,' . $base,
1267
-		];
1268
-		$plantsDn = [
1269
-			'uid=flower,' . $base,
1270
-			'uid=tree,' . $base,
1271
-		];
1272
-		$thingsDn = [
1273
-			'uid=thing1,' . $base,
1274
-			'uid=thing2,' . $base,
1275
-		];
1276
-
1277
-		return [
1278
-			[ #0 – test DNs
1279
-				['cn=Birds,' . $base => $birdsDn],
1280
-				['cn=Birds,' . $base => $birdsDn]
1281
-			],
1282
-			[ #1 – test uids
1283
-				['cn=Birds,' . $base => $birdsUid],
1284
-				['cn=Birds,' . $base => $birdsUid]
1285
-			],
1286
-			[ #2 – test simple nested group
1287
-				['cn=Animals,' . $base => array_merge($birdsDn, $animalsDn)],
1288
-				[
1289
-					'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn),
1290
-					'cn=Birds,' . $base => $birdsDn,
1291
-				]
1292
-			],
1293
-			[ #3 – test recursive nested group
1294
-				[
1295
-					'cn=Animals,' . $base => array_merge($birdsDn, $animalsDn),
1296
-					'cn=Birds,' . $base => array_merge($birdsDn, $animalsDn),
1297
-				],
1298
-				[
1299
-					'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base,'cn=Birds,' . $base,'cn=Animals,' . $base], $animalsDn),
1300
-					'cn=Birds,' . $base => array_merge(['cn=Animals,' . $base,'cn=Birds,' . $base], $birdsDn),
1301
-				]
1302
-			],
1303
-			[ #4 – Complicated nested group
1304
-				['cn=Things,' . $base => array_merge($birdsDn, $animalsDn, $thingsDn, $plantsDn)],
1305
-				[
1306
-					'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn),
1307
-					'cn=Birds,' . $base => $birdsDn,
1308
-					'cn=Plants,' . $base => $plantsDn,
1309
-					'cn=Things,' . $base => array_merge(['cn=Animals,' . $base,'cn=Plants,' . $base], $thingsDn),
1310
-				]
1311
-			],
1312
-		];
1313
-	}
1314
-
1315
-	#[\PHPUnit\Framework\Attributes\DataProvider('groupMemberProvider')]
1316
-	public function testGroupMembers(array $expectedResult, array $groupsInfo): void {
1317
-		$this->access->expects($this->any())
1318
-			->method('readAttribute')
1319
-			->willReturnCallback(function ($group) use ($groupsInfo) {
1320
-				if (isset($groupsInfo[$group])) {
1321
-					return $groupsInfo[$group];
1322
-				}
1323
-				return [];
1324
-			});
1325
-
1326
-		$this->access->connection->expects($this->any())
1327
-			->method('__get')
1328
-			->willReturnCallback(function (string $name) {
1329
-				if ($name === 'ldapNestedGroups') {
1330
-					return 1;
1331
-				} elseif ($name === 'ldapGroupMemberAssocAttr') {
1332
-					return 'attr';
1333
-				}
1334
-				return null;
1335
-			});
1336
-
1337
-		$this->initBackend();
1338
-		foreach ($expectedResult as $groupDN => $expectedMembers) {
1339
-			$resultingMembers = $this->invokePrivate($this->groupBackend, '_groupMembers', [$groupDN]);
1340
-
1341
-			sort($expectedMembers);
1342
-			sort($resultingMembers);
1343
-			$this->assertEquals($expectedMembers, $resultingMembers);
1344
-		}
1345
-	}
1346
-
1347
-	public static function displayNameProvider(): array {
1348
-		return [
1349
-			['Graphic Novelists', ['Graphic Novelists']],
1350
-			['', false],
1351
-		];
1352
-	}
1353
-
1354
-	#[\PHPUnit\Framework\Attributes\DataProvider('displayNameProvider')]
1355
-	public function testGetDisplayName(string $expected, bool|array $ldapResult): void {
1356
-		$gid = 'graphic_novelists';
1357
-
1358
-		$this->access->expects($this->atLeastOnce())
1359
-			->method('readAttribute')
1360
-			->willReturn($ldapResult);
1361
-
1362
-		$this->access->connection->expects($this->any())
1363
-			->method('__get')
1364
-			->willReturnCallback(function ($name) {
1365
-				if ($name === 'ldapGroupMemberAssocAttr') {
1366
-					return 'member';
1367
-				} elseif ($name === 'ldapGroupFilter') {
1368
-					return 'objectclass=nextcloudGroup';
1369
-				} elseif ($name === 'ldapGroupDisplayName') {
1370
-					return 'cn';
1371
-				}
1372
-				return null;
1373
-			});
1374
-
1375
-		$this->access->expects($this->any())
1376
-			->method('groupname2dn')
1377
-			->willReturn('fakedn');
1378
-
1379
-		$this->initBackend();
1380
-		$this->assertSame($expected, $this->groupBackend->getDisplayName($gid));
1381
-	}
396
+        $this->initBackend();
397
+        $group = $this->groupBackend->primaryGroupID2Name('3117', $userDN);
398
+
399
+        $this->assertSame(false, $group);
400
+    }
401
+
402
+    public function testGetEntryGroupIDValue(): void {
403
+        //tests getEntryGroupID via getGroupPrimaryGroupID
404
+        //which is basically identical to getUserPrimaryGroupIDs
405
+        $this->enableGroups();
406
+
407
+        $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
408
+        $attr = 'primaryGroupToken';
409
+
410
+        $this->access->expects($this->once())
411
+            ->method('readAttribute')
412
+            ->with($dn, $attr)
413
+            ->willReturn(['3117']);
414
+
415
+        $this->initBackend();
416
+        $gid = $this->groupBackend->getGroupPrimaryGroupID($dn);
417
+
418
+        $this->assertSame('3117', $gid);
419
+    }
420
+
421
+    public function testGetEntryGroupIDNoValue(): void {
422
+        //tests getEntryGroupID via getGroupPrimaryGroupID
423
+        //which is basically identical to getUserPrimaryGroupIDs
424
+        $this->enableGroups();
425
+
426
+        $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
427
+        $attr = 'primaryGroupToken';
428
+
429
+        $this->access->expects($this->once())
430
+            ->method('readAttribute')
431
+            ->with($dn, $attr)
432
+            ->willReturn(false);
433
+
434
+        $this->initBackend();
435
+        $gid = $this->groupBackend->getGroupPrimaryGroupID($dn);
436
+
437
+        $this->assertSame(false, $gid);
438
+    }
439
+
440
+    /**
441
+     * tests whether Group Backend behaves correctly when cache with uid and gid
442
+     * is hit
443
+     */
444
+    public function testInGroupHitsUidGidCache(): void {
445
+        $this->enableGroups();
446
+
447
+        $uid = 'someUser';
448
+        $gid = 'someGroup';
449
+        $cacheKey = 'inGroup' . $uid . ':' . $gid;
450
+
451
+        $this->access->connection->expects($this->once())
452
+            ->method('getFromCache')
453
+            ->with($cacheKey)
454
+            ->willReturn(true);
455
+
456
+        $this->access->expects($this->never())
457
+            ->method('username2dn');
458
+
459
+        $this->initBackend();
460
+        $this->groupBackend->inGroup($uid, $gid);
461
+    }
462
+
463
+    public static function groupWithMembersProvider(): array {
464
+        return [
465
+            [
466
+                'someGroup',
467
+                'cn=someGroup,ou=allTheGroups,ou=someDepartment,dc=someDomain,dc=someTld',
468
+                [
469
+                    'uid=oneUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld',
470
+                    'uid=someUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld',
471
+                    'uid=anotherUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld',
472
+                    'uid=differentUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld',
473
+                ],
474
+            ],
475
+        ];
476
+    }
477
+
478
+    #[\PHPUnit\Framework\Attributes\DataProvider('groupWithMembersProvider')]
479
+    public function testInGroupMember(string $gid, string $groupDn, array $memberDNs): void {
480
+        $uid = 'someUser';
481
+        $userDn = $memberDNs[0];
482
+
483
+        $this->access->connection->expects($this->any())
484
+            ->method('__get')
485
+            ->willReturnCallback(function ($name) {
486
+                switch ($name) {
487
+                    case 'ldapGroupMemberAssocAttr':
488
+                        return 'member';
489
+                    case 'ldapDynamicGroupMemberURL':
490
+                        return '';
491
+                    case 'hasPrimaryGroups':
492
+                    case 'ldapNestedGroups':
493
+                        return 0;
494
+                    default:
495
+                        return 1;
496
+                }
497
+            });
498
+        $this->access->connection->expects($this->any())
499
+            ->method('getFromCache')
500
+            ->willReturn(null);
501
+
502
+        $this->access->expects($this->once())
503
+            ->method('username2dn')
504
+            ->with($uid)
505
+            ->willReturn($userDn);
506
+        $this->access->expects($this->once())
507
+            ->method('groupname2dn')
508
+            ->willReturn($groupDn);
509
+        $this->access->expects($this->any())
510
+            ->method('readAttribute')
511
+            ->willReturn($memberDNs);
512
+
513
+        $this->initBackend();
514
+        $this->assertTrue($this->groupBackend->inGroup($uid, $gid));
515
+    }
516
+
517
+    #[\PHPUnit\Framework\Attributes\DataProvider('groupWithMembersProvider')]
518
+    public function testInGroupMemberNot(string $gid, string $groupDn, array $memberDNs): void {
519
+        $uid = 'unelatedUser';
520
+        $userDn = 'uid=unrelatedUser,ou=unrelatedTeam,ou=unrelatedDepartment,dc=someDomain,dc=someTld';
521
+
522
+        $this->access->connection->expects($this->any())
523
+            ->method('__get')
524
+            ->willReturnCallback(function ($name) {
525
+                switch ($name) {
526
+                    case 'ldapGroupMemberAssocAttr':
527
+                        return 'member';
528
+                    case 'ldapDynamicGroupMemberURL':
529
+                        return '';
530
+                    case 'hasPrimaryGroups':
531
+                    case 'ldapNestedGroups':
532
+                        return 0;
533
+                    default:
534
+                        return 1;
535
+                }
536
+            });
537
+        $this->access->connection->expects($this->any())
538
+            ->method('getFromCache')
539
+            ->willReturn(null);
540
+
541
+        $this->access->expects($this->once())
542
+            ->method('username2dn')
543
+            ->with($uid)
544
+            ->willReturn($userDn);
545
+        $this->access->expects($this->once())
546
+            ->method('groupname2dn')
547
+            ->willReturn($groupDn);
548
+        $this->access->expects($this->any())
549
+            ->method('readAttribute')
550
+            ->willReturn($memberDNs);
551
+
552
+        $this->initBackend();
553
+        $this->assertFalse($this->groupBackend->inGroup($uid, $gid));
554
+    }
555
+
556
+    #[\PHPUnit\Framework\Attributes\DataProvider('groupWithMembersProvider')]
557
+    public function testInGroupMemberUid(string $gid, string $groupDn, array $memberDNs): void {
558
+        $memberUids = [];
559
+        $userRecords = [];
560
+        foreach ($memberDNs as $dn) {
561
+            $memberUids[] = ldap_explode_dn($dn, 0)[0];
562
+            $userRecords[] = ['dn' => [$dn]];
563
+        }
564
+
565
+        $uid = 'someUser';
566
+        $userDn = $memberDNs[0];
567
+
568
+        $this->access->connection->expects($this->any())
569
+            ->method('__get')
570
+            ->willReturnCallback(function ($name) {
571
+                switch ($name) {
572
+                    case 'ldapGroupMemberAssocAttr':
573
+                        return 'memberUid';
574
+                    case 'ldapDynamicGroupMemberURL':
575
+                        return '';
576
+                    case 'ldapLoginFilter':
577
+                        return 'uid=%uid';
578
+                    case 'hasPrimaryGroups':
579
+                    case 'ldapNestedGroups':
580
+                        return 0;
581
+                    default:
582
+                        return 1;
583
+                }
584
+            });
585
+        $this->access->connection->expects($this->any())
586
+            ->method('getFromCache')
587
+            ->willReturn(null);
588
+
589
+        $this->access->userManager->expects($this->any())
590
+            ->method('getAttributes')
591
+            ->willReturn(['uid', 'mail', 'displayname']);
592
+
593
+        $this->access->expects($this->once())
594
+            ->method('username2dn')
595
+            ->with($uid)
596
+            ->willReturn($userDn);
597
+        $this->access->expects($this->once())
598
+            ->method('groupname2dn')
599
+            ->willReturn($groupDn);
600
+        $this->access->expects($this->any())
601
+            ->method('readAttribute')
602
+            ->willReturn($memberUids);
603
+        $this->access->expects($this->any())
604
+            ->method('fetchListOfUsers')
605
+            ->willReturn($userRecords);
606
+        $this->access->expects($this->any())
607
+            ->method('combineFilterWithOr')
608
+            ->willReturn('(|(pseudo=filter)(filter=pseudo))');
609
+
610
+        $this->initBackend();
611
+        $this->assertTrue($this->groupBackend->inGroup($uid, $gid));
612
+    }
613
+
614
+    public function testGetGroupsWithOffset(): void {
615
+        $this->enableGroups();
616
+
617
+        $this->access->expects($this->once())
618
+            ->method('nextcloudGroupNames')
619
+            ->willReturn(['group1', 'group2']);
620
+
621
+        $this->initBackend();
622
+        $groups = $this->groupBackend->getGroups('', 2, 2);
623
+
624
+        $this->assertSame(2, count($groups));
625
+    }
626
+
627
+    /**
628
+     * tests that a user listing is complete, if all its members have the group
629
+     * as their primary.
630
+     */
631
+    public function testUsersInGroupPrimaryMembersOnly(): void {
632
+        $this->enableGroups();
633
+
634
+        $this->access->connection->expects($this->any())
635
+            ->method('getFromCache')
636
+            ->willReturn(null);
637
+        $this->access->expects($this->any())
638
+            ->method('readAttribute')
639
+            ->willReturnCallback(function ($dn, $attr) {
640
+                if ($attr === 'primaryGroupToken') {
641
+                    return [1337];
642
+                } elseif ($attr === 'gidNumber') {
643
+                    return [4211];
644
+                }
645
+                return [];
646
+            });
647
+        $this->access->expects($this->any())
648
+            ->method('groupname2dn')
649
+            ->willReturn('cn=foobar,dc=foo,dc=bar');
650
+        $this->access->expects($this->exactly(2))
651
+            ->method('nextcloudUserNames')
652
+            ->willReturnOnConsecutiveCalls(['lisa', 'bart', 'kira', 'brad'], ['walle', 'dino', 'xenia']);
653
+        $this->access->expects($this->any())
654
+            ->method('isDNPartOfBase')
655
+            ->willReturn(true);
656
+        $this->access->expects($this->any())
657
+            ->method('combineFilterWithAnd')
658
+            ->willReturn('pseudo=filter');
659
+
660
+        $this->access->userManager->expects($this->any())
661
+            ->method('getAttributes')
662
+            ->willReturn(['displayName', 'mail']);
663
+
664
+        $this->initBackend();
665
+        $users = $this->groupBackend->usersInGroup('foobar');
666
+
667
+        $this->assertSame(7, count($users));
668
+    }
669
+
670
+    /**
671
+     * tests that a user listing is complete, if all its members have the group
672
+     * as their primary.
673
+     */
674
+    public function testUsersInGroupPrimaryAndUnixMembers(): void {
675
+        $this->enableGroups();
676
+
677
+        $this->access->connection->expects($this->any())
678
+            ->method('getFromCache')
679
+            ->willReturn(null);
680
+        $this->access->expects($this->any())
681
+            ->method('readAttribute')
682
+            ->willReturnCallback(function ($dn, $attr) {
683
+                if ($attr === 'primaryGroupToken') {
684
+                    return [1337];
685
+                }
686
+                return [];
687
+            });
688
+        $this->access->expects($this->any())
689
+            ->method('groupname2dn')
690
+            ->willReturn('cn=foobar,dc=foo,dc=bar');
691
+        $this->access->expects($this->once())
692
+            ->method('nextcloudUserNames')
693
+            ->willReturn(['lisa', 'bart', 'kira', 'brad']);
694
+        $this->access->expects($this->any())
695
+            ->method('isDNPartOfBase')
696
+            ->willReturn(true);
697
+        $this->access->expects($this->any())
698
+            ->method('combineFilterWithAnd')
699
+            ->willReturn('pseudo=filter');
700
+
701
+        $this->access->userManager->expects($this->any())
702
+            ->method('getAttributes')
703
+            ->willReturn(['displayName', 'mail']);
704
+
705
+        $this->initBackend();
706
+        $users = $this->groupBackend->usersInGroup('foobar');
707
+
708
+        $this->assertSame(4, count($users));
709
+    }
710
+
711
+    /**
712
+     * tests that a user counting is complete, if all its members have the group
713
+     * as their primary.
714
+     */
715
+    public function testCountUsersInGroupPrimaryMembersOnly(): void {
716
+        $this->enableGroups();
717
+
718
+        $this->access->connection->expects($this->any())
719
+            ->method('getFromCache')
720
+            ->willReturn(null);
721
+
722
+        $this->access->expects($this->any())
723
+            ->method('readAttribute')
724
+            ->willReturnCallback(function ($dn, $attr) {
725
+                if ($attr === 'primaryGroupToken') {
726
+                    return [1337];
727
+                }
728
+                return [];
729
+            });
730
+        $this->access->expects($this->any())
731
+            ->method('groupname2dn')
732
+            ->willReturn('cn=foobar,dc=foo,dc=bar');
733
+        $this->access->expects($this->once())
734
+            ->method('countUsers')
735
+            ->willReturn(4);
736
+        $this->access->expects($this->any())
737
+            ->method('isDNPartOfBase')
738
+            ->willReturn(true);
739
+
740
+        $this->access->userManager->expects($this->any())
741
+            ->method('getAttributes')
742
+            ->willReturn(['displayName', 'mail']);
743
+
744
+        $this->initBackend();
745
+        $users = $this->groupBackend->countUsersInGroup('foobar');
746
+
747
+        $this->assertSame(4, $users);
748
+    }
749
+
750
+    public function testGetUserGroupsMemberOf(): void {
751
+        $this->enableGroups();
752
+
753
+        $dn = 'cn=userX,dc=foobar';
754
+
755
+        $this->access->connection->hasPrimaryGroups = false;
756
+        $this->access->connection->hasGidNumber = false;
757
+
758
+        $expectedGroups = ['cn=groupA,dc=foobar', 'cn=groupB,dc=foobar'];
759
+
760
+        $this->access->expects($this->any())
761
+            ->method('username2dn')
762
+            ->willReturn($dn);
763
+        $this->access->expects($this->exactly(5))
764
+            ->method('readAttribute')->willReturnOnConsecutiveCalls($expectedGroups, [], [], [], []);
765
+        $this->access->expects($this->any())
766
+            ->method('dn2groupname')
767
+            ->willReturnArgument(0);
768
+        $this->access->expects($this->any())
769
+            ->method('groupname2dn')
770
+            ->willReturnArgument(0);
771
+        $this->access->expects($this->any())
772
+            ->method('isDNPartOfBase')
773
+            ->willReturn(true);
774
+
775
+        $this->config->expects($this->once())
776
+            ->method('setUserValue')
777
+            ->with('userX', 'user_ldap', 'cached-group-memberships-', \json_encode($expectedGroups));
778
+
779
+        $this->initBackend();
780
+        $groups = $this->groupBackend->getUserGroups('userX');
781
+
782
+        $this->assertSame(2, count($groups));
783
+    }
784
+
785
+    public function testGetUserGroupsMemberOfDisabled(): void {
786
+        $this->access->connection->expects($this->any())
787
+            ->method('__get')
788
+            ->willReturnCallback(function ($name) {
789
+                if ($name === 'useMemberOfToDetectMembership') {
790
+                    return 0;
791
+                } elseif ($name === 'ldapDynamicGroupMemberURL') {
792
+                    return '';
793
+                }
794
+                return 1;
795
+            });
796
+
797
+        $dn = 'cn=userX,dc=foobar';
798
+
799
+        $this->access->connection->hasPrimaryGroups = false;
800
+        $this->access->connection->hasGidNumber = false;
801
+
802
+        $this->access->expects($this->once())
803
+            ->method('username2dn')
804
+            ->willReturn($dn);
805
+        $this->access->expects($this->never())
806
+            ->method('readAttribute')
807
+            ->with($dn, 'memberOf');
808
+        $this->access->expects($this->once())
809
+            ->method('nextcloudGroupNames')
810
+            ->willReturn([]);
811
+
812
+        // empty group result should not be oer
813
+        $this->config->expects($this->once())
814
+            ->method('setUserValue')
815
+            ->with('userX', 'user_ldap', 'cached-group-memberships-', '[]');
816
+
817
+        $ldapUser = $this->createMock(User::class);
818
+
819
+        $this->access->userManager->expects($this->any())
820
+            ->method('get')
821
+            ->with('userX')
822
+            ->willReturn($ldapUser);
823
+
824
+        $userBackend = $this->createMock(User_Proxy::class);
825
+        $userBackend->expects($this->once())
826
+            ->method('userExistsOnLDAP')
827
+            ->with('userX', true)
828
+            ->willReturn(true);
829
+
830
+        $ncUser = $this->createMock(IUser::class);
831
+        $ncUser->expects($this->any())
832
+            ->method('getBackend')
833
+            ->willReturn($userBackend);
834
+
835
+        $this->ncUserManager->expects($this->once())
836
+            ->method('get')
837
+            ->with('userX')
838
+            ->willReturn($ncUser);
839
+
840
+        $this->initBackend();
841
+        $this->groupBackend->getUserGroups('userX');
842
+    }
843
+
844
+    public function testGetUserGroupsOfflineUser(): void {
845
+        $this->enableGroups();
846
+
847
+        $offlineUser = $this->createMock(OfflineUser::class);
848
+
849
+        $this->config->expects($this->any())
850
+            ->method('getUserValue')
851
+            ->with('userX', 'user_ldap', 'cached-group-memberships-', $this->anything())
852
+            ->willReturn(\json_encode(['groupB', 'groupF']));
853
+
854
+        $this->access->userManager->expects($this->any())
855
+            ->method('get')
856
+            ->with('userX')
857
+            ->willReturn($offlineUser);
858
+
859
+        $this->initBackend();
860
+        $returnedGroups = $this->groupBackend->getUserGroups('userX');
861
+        $this->assertCount(2, $returnedGroups);
862
+        $this->assertContains('groupB', $returnedGroups);
863
+        $this->assertContains('groupF', $returnedGroups);
864
+    }
865
+
866
+    /**
867
+     * regression tests against a case where a json object was stored instead of expected list
868
+     * @see https://github.com/nextcloud/server/issues/42374
869
+     */
870
+    public function testGetUserGroupsOfflineUserUnexpectedJson(): void {
871
+        $this->enableGroups();
872
+
873
+        $offlineUser = $this->createMock(OfflineUser::class);
874
+
875
+        $this->config->expects($this->any())
876
+            ->method('getUserValue')
877
+            ->with('userX', 'user_ldap', 'cached-group-memberships-', $this->anything())
878
+            // results in a json object: {"0":"groupB","2":"groupF"}
879
+            ->willReturn(\json_encode([0 => 'groupB', 2 => 'groupF']));
880
+
881
+        $this->access->userManager->expects($this->any())
882
+            ->method('get')
883
+            ->with('userX')
884
+            ->willReturn($offlineUser);
885
+
886
+        $this->initBackend();
887
+        $returnedGroups = $this->groupBackend->getUserGroups('userX');
888
+        $this->assertCount(2, $returnedGroups);
889
+        $this->assertContains('groupB', $returnedGroups);
890
+        $this->assertContains('groupF', $returnedGroups);
891
+    }
892
+
893
+    public function testGetUserGroupsUnrecognizedOfflineUser(): void {
894
+        $this->enableGroups();
895
+        $dn = 'cn=userX,dc=foobar';
896
+
897
+        $ldapUser = $this->createMock(User::class);
898
+
899
+        $userBackend = $this->createMock(User_Proxy::class);
900
+        $userBackend->expects($this->once())
901
+            ->method('userExistsOnLDAP')
902
+            ->with('userX', true)
903
+            ->willReturn(false);
904
+
905
+        $ncUser = $this->createMock(IUser::class);
906
+        $ncUser->expects($this->any())
907
+            ->method('getBackend')
908
+            ->willReturn($userBackend);
909
+
910
+        $this->config->expects($this->atLeastOnce())
911
+            ->method('getUserValue')
912
+            ->with('userX', 'user_ldap', 'cached-group-memberships-', $this->anything())
913
+            ->willReturn(\json_encode(['groupB', 'groupF']));
914
+
915
+        $this->access->expects($this->any())
916
+            ->method('username2dn')
917
+            ->willReturn($dn);
918
+
919
+        $this->access->userManager->expects($this->any())
920
+            ->method('get')
921
+            ->with('userX')
922
+            ->willReturn($ldapUser);
923
+
924
+        $this->ncUserManager->expects($this->once())
925
+            ->method('get')
926
+            ->with('userX')
927
+            ->willReturn($ncUser);
928
+
929
+        $this->initBackend();
930
+        $returnedGroups = $this->groupBackend->getUserGroups('userX');
931
+        $this->assertCount(2, $returnedGroups);
932
+        $this->assertContains('groupB', $returnedGroups);
933
+        $this->assertContains('groupF', $returnedGroups);
934
+    }
935
+
936
+    public static function nestedGroupsProvider(): array {
937
+        return [
938
+            [true],
939
+            [false],
940
+        ];
941
+    }
942
+
943
+    #[\PHPUnit\Framework\Attributes\DataProvider('nestedGroupsProvider')]
944
+    public function testGetGroupsByMember(bool $nestedGroups): void {
945
+        $groupFilter = '(&(objectclass=nextcloudGroup)(nextcloudEnabled=TRUE))';
946
+        $this->access->connection->expects($this->any())
947
+            ->method('__get')
948
+            ->willReturnCallback(function (string $name) use ($nestedGroups, $groupFilter) {
949
+                switch ($name) {
950
+                    case 'useMemberOfToDetectMembership':
951
+                        return 0;
952
+                    case 'ldapDynamicGroupMemberURL':
953
+                        return '';
954
+                    case 'ldapNestedGroups':
955
+                        return (int)$nestedGroups;
956
+                    case 'ldapGroupMemberAssocAttr':
957
+                        return 'member';
958
+                    case 'ldapGroupFilter':
959
+                        return $groupFilter;
960
+                    case 'ldapBaseGroups':
961
+                        return [];
962
+                    case 'ldapGroupDisplayName':
963
+                        return 'cn';
964
+                }
965
+                return 1;
966
+            });
967
+
968
+        $dn = 'cn=userX,dc=foobar';
969
+
970
+        $this->access->connection->hasPrimaryGroups = false;
971
+        $this->access->connection->hasGidNumber = false;
972
+
973
+        $this->access->expects($this->exactly(2))
974
+            ->method('username2dn')
975
+            ->willReturn($dn);
976
+        $this->access->expects($this->any())
977
+            ->method('readAttribute')
978
+            ->willReturn([]);
979
+        $this->access->expects($this->any())
980
+            ->method('combineFilterWithAnd')
981
+            ->willReturnCallback(function (array $filterParts) {
982
+                // ⚠ returns a pseudo-filter only, not real LDAP Filter syntax
983
+                return implode('&', $filterParts);
984
+            });
985
+
986
+        $group1 = [
987
+            'cn' => 'group1',
988
+            'dn' => ['cn=group1,ou=groups,dc=domain,dc=com'],
989
+            'member' => [$dn],
990
+        ];
991
+        $group2 = [
992
+            'cn' => 'group2',
993
+            'dn' => ['cn=group2,ou=groups,dc=domain,dc=com'],
994
+            'member' => [$dn],
995
+        ];
996
+        $group3 = [
997
+            'cn' => 'group3',
998
+            'dn' => ['cn=group3,ou=groups,dc=domain,dc=com'],
999
+            'member' => [$group2['dn'][0]],
1000
+        ];
1001
+
1002
+        $expectedGroups = ($nestedGroups ? [$group1, $group2, $group3] : [$group1, $group2]);
1003
+        $expectedGroupsNames = ($nestedGroups ? ['group1', 'group2', 'group3'] : ['group1', 'group2']);
1004
+
1005
+        $this->access->expects($this->any())
1006
+            ->method('nextcloudGroupNames')
1007
+            ->with($expectedGroups)
1008
+            ->willReturn($expectedGroupsNames);
1009
+        $this->access->expects($nestedGroups ? $this->atLeastOnce() : $this->once())
1010
+            ->method('fetchListOfGroups')
1011
+            ->willReturnCallback(function ($filter, $attr, $limit, $offset) use ($nestedGroups, $groupFilter, $group1, $group2, $group3, $dn) {
1012
+                static $firstRun = true;
1013
+                if (!$nestedGroups) {
1014
+                    // When nested groups are enabled, groups cannot be filtered early as it would
1015
+                    // exclude intermediate groups. But we can, and should, when working with flat groups.
1016
+                    $this->assertTrue(str_contains($filter, $groupFilter));
1017
+                }
1018
+                [$memberFilter] = explode('&', $filter);
1019
+                if ($memberFilter === 'member=' . $dn) {
1020
+                    return [$group1, $group2];
1021
+                    return [];
1022
+                } elseif ($memberFilter === 'member=' . $group2['dn'][0]) {
1023
+                    return [$group3];
1024
+                } else {
1025
+                    return [];
1026
+                }
1027
+            });
1028
+        $this->access->expects($this->any())
1029
+            ->method('dn2groupname')
1030
+            ->willReturnCallback(function (string $dn) {
1031
+                return ldap_explode_dn($dn, 1)[0];
1032
+            });
1033
+        $this->access->expects($this->any())
1034
+            ->method('groupname2dn')
1035
+            ->willReturnCallback(function (string $gid) use ($group1, $group2, $group3) {
1036
+                if ($gid === $group1['cn']) {
1037
+                    return $group1['dn'][0];
1038
+                }
1039
+                if ($gid === $group2['cn']) {
1040
+                    return $group2['dn'][0];
1041
+                }
1042
+                if ($gid === $group3['cn']) {
1043
+                    return $group3['dn'][0];
1044
+                }
1045
+            });
1046
+        $this->access->expects($this->any())
1047
+            ->method('isDNPartOfBase')
1048
+            ->willReturn(true);
1049
+
1050
+        $this->initBackend();
1051
+        $groups = $this->groupBackend->getUserGroups('userX');
1052
+        $this->assertEquals($expectedGroupsNames, $groups);
1053
+
1054
+        $groupsAgain = $this->groupBackend->getUserGroups('userX');
1055
+        $this->assertEquals($expectedGroupsNames, $groupsAgain);
1056
+    }
1057
+
1058
+    public function testCreateGroupWithPlugin(): void {
1059
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1060
+            ->onlyMethods(['implementsActions', 'createGroup'])
1061
+            ->getMock();
1062
+
1063
+        $this->pluginManager->expects($this->once())
1064
+            ->method('implementsActions')
1065
+            ->with(GroupInterface::CREATE_GROUP)
1066
+            ->willReturn(true);
1067
+
1068
+        $this->pluginManager->expects($this->once())
1069
+            ->method('createGroup')
1070
+            ->with('gid')
1071
+            ->willReturn('result');
1072
+
1073
+        $this->initBackend();
1074
+        $this->assertTrue($this->groupBackend->createGroup('gid'));
1075
+    }
1076
+
1077
+
1078
+    public function testCreateGroupFailing(): void {
1079
+        $this->expectException(\Exception::class);
1080
+
1081
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1082
+            ->onlyMethods(['implementsActions', 'createGroup'])
1083
+            ->getMock();
1084
+
1085
+        $this->pluginManager->expects($this->once())
1086
+            ->method('implementsActions')
1087
+            ->with(GroupInterface::CREATE_GROUP)
1088
+            ->willReturn(false);
1089
+
1090
+        $this->initBackend();
1091
+        $this->groupBackend->createGroup('gid');
1092
+    }
1093
+
1094
+    public function testDeleteGroupWithPlugin(): void {
1095
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1096
+            ->onlyMethods(['implementsActions', 'deleteGroup'])
1097
+            ->getMock();
1098
+
1099
+        $this->pluginManager->expects($this->once())
1100
+            ->method('implementsActions')
1101
+            ->with(GroupInterface::DELETE_GROUP)
1102
+            ->willReturn(true);
1103
+
1104
+        $this->pluginManager->expects($this->once())
1105
+            ->method('deleteGroup')
1106
+            ->with('gid')
1107
+            ->willReturn(true);
1108
+
1109
+        $mapper = $this->getMockBuilder(GroupMapping::class)
1110
+            ->onlyMethods(['unmap'])
1111
+            ->disableOriginalConstructor()
1112
+            ->getMock();
1113
+
1114
+        $this->access->expects($this->any())
1115
+            ->method('getGroupMapper')
1116
+            ->willReturn($mapper);
1117
+
1118
+        $this->initBackend();
1119
+        $this->assertTrue($this->groupBackend->deleteGroup('gid'));
1120
+    }
1121
+
1122
+
1123
+    public function testDeleteGroupFailing(): void {
1124
+        $this->expectException(\Exception::class);
1125
+
1126
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1127
+            ->onlyMethods(['implementsActions', 'deleteGroup'])
1128
+            ->getMock();
1129
+
1130
+        $this->pluginManager->expects($this->once())
1131
+            ->method('implementsActions')
1132
+            ->with(GroupInterface::DELETE_GROUP)
1133
+            ->willReturn(false);
1134
+
1135
+        $this->initBackend();
1136
+        $this->groupBackend->deleteGroup('gid');
1137
+    }
1138
+
1139
+    public function testAddToGroupWithPlugin(): void {
1140
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1141
+            ->onlyMethods(['implementsActions', 'addToGroup'])
1142
+            ->getMock();
1143
+
1144
+        $this->pluginManager->expects($this->once())
1145
+            ->method('implementsActions')
1146
+            ->with(GroupInterface::ADD_TO_GROUP)
1147
+            ->willReturn(true);
1148
+
1149
+        $this->pluginManager->expects($this->once())
1150
+            ->method('addToGroup')
1151
+            ->with('uid', 'gid')
1152
+            ->willReturn('result');
1153
+
1154
+        $this->initBackend();
1155
+        $this->assertEquals('result', $this->groupBackend->addToGroup('uid', 'gid'));
1156
+    }
1157
+
1158
+
1159
+    public function testAddToGroupFailing(): void {
1160
+        $this->expectException(\Exception::class);
1161
+
1162
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1163
+            ->onlyMethods(['implementsActions', 'addToGroup'])
1164
+            ->getMock();
1165
+
1166
+        $this->pluginManager->expects($this->once())
1167
+            ->method('implementsActions')
1168
+            ->with(GroupInterface::ADD_TO_GROUP)
1169
+            ->willReturn(false);
1170
+
1171
+        $this->initBackend();
1172
+        $this->groupBackend->addToGroup('uid', 'gid');
1173
+    }
1174
+
1175
+    public function testRemoveFromGroupWithPlugin(): void {
1176
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1177
+            ->onlyMethods(['implementsActions', 'removeFromGroup'])
1178
+            ->getMock();
1179
+
1180
+        $this->pluginManager->expects($this->once())
1181
+            ->method('implementsActions')
1182
+            ->with(GroupInterface::REMOVE_FROM_GROUP)
1183
+            ->willReturn(true);
1184
+
1185
+        $this->pluginManager->expects($this->once())
1186
+            ->method('removeFromGroup')
1187
+            ->with('uid', 'gid')
1188
+            ->willReturn('result');
1189
+
1190
+        $this->initBackend();
1191
+        $this->assertEquals('result', $this->groupBackend->removeFromGroup('uid', 'gid'));
1192
+    }
1193
+
1194
+
1195
+    public function testRemoveFromGroupFailing(): void {
1196
+        $this->expectException(\Exception::class);
1197
+
1198
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1199
+            ->onlyMethods(['implementsActions', 'removeFromGroup'])
1200
+            ->getMock();
1201
+
1202
+        $this->pluginManager->expects($this->once())
1203
+            ->method('implementsActions')
1204
+            ->with(GroupInterface::REMOVE_FROM_GROUP)
1205
+            ->willReturn(false);
1206
+
1207
+        $this->initBackend();
1208
+        $this->groupBackend->removeFromGroup('uid', 'gid');
1209
+    }
1210
+
1211
+    public function testGetGroupDetailsWithPlugin(): void {
1212
+        /** @var GroupPluginManager|MockObject $pluginManager */
1213
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1214
+            ->onlyMethods(['implementsActions', 'getGroupDetails'])
1215
+            ->getMock();
1216
+
1217
+        $this->pluginManager->expects($this->once())
1218
+            ->method('implementsActions')
1219
+            ->with(GroupInterface::GROUP_DETAILS)
1220
+            ->willReturn(true);
1221
+
1222
+        $this->pluginManager->expects($this->once())
1223
+            ->method('getGroupDetails')
1224
+            ->with('gid')
1225
+            ->willReturn('result');
1226
+
1227
+        $this->initBackend();
1228
+        $this->assertEquals('result', $this->groupBackend->getGroupDetails('gid'));
1229
+    }
1230
+
1231
+    public function testGetGroupDetailsFailing(): void {
1232
+        $this->expectException(\Exception::class);
1233
+
1234
+        $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class)
1235
+            ->onlyMethods(['implementsActions', 'getGroupDetails'])
1236
+            ->getMock();
1237
+
1238
+        $this->pluginManager->expects($this->once())
1239
+            ->method('implementsActions')
1240
+            ->with(GroupInterface::GROUP_DETAILS)
1241
+            ->willReturn(false);
1242
+
1243
+        $this->initBackend();
1244
+        $this->groupBackend->getGroupDetails('gid');
1245
+    }
1246
+
1247
+    public static function groupMemberProvider(): array {
1248
+        $base = 'dc=species,dc=earth';
1249
+
1250
+        $birdsDn = [
1251
+            'uid=3723,' . $base,
1252
+            'uid=8372,' . $base,
1253
+            'uid=8427,' . $base,
1254
+            'uid=2333,' . $base,
1255
+            'uid=4754,' . $base,
1256
+        ];
1257
+        $birdsUid = [
1258
+            '3723',
1259
+            '8372',
1260
+            '8427',
1261
+            '2333',
1262
+            '4754',
1263
+        ];
1264
+        $animalsDn = [
1265
+            'uid=lion,' . $base,
1266
+            'uid=tiger,' . $base,
1267
+        ];
1268
+        $plantsDn = [
1269
+            'uid=flower,' . $base,
1270
+            'uid=tree,' . $base,
1271
+        ];
1272
+        $thingsDn = [
1273
+            'uid=thing1,' . $base,
1274
+            'uid=thing2,' . $base,
1275
+        ];
1276
+
1277
+        return [
1278
+            [ #0 – test DNs
1279
+                ['cn=Birds,' . $base => $birdsDn],
1280
+                ['cn=Birds,' . $base => $birdsDn]
1281
+            ],
1282
+            [ #1 – test uids
1283
+                ['cn=Birds,' . $base => $birdsUid],
1284
+                ['cn=Birds,' . $base => $birdsUid]
1285
+            ],
1286
+            [ #2 – test simple nested group
1287
+                ['cn=Animals,' . $base => array_merge($birdsDn, $animalsDn)],
1288
+                [
1289
+                    'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn),
1290
+                    'cn=Birds,' . $base => $birdsDn,
1291
+                ]
1292
+            ],
1293
+            [ #3 – test recursive nested group
1294
+                [
1295
+                    'cn=Animals,' . $base => array_merge($birdsDn, $animalsDn),
1296
+                    'cn=Birds,' . $base => array_merge($birdsDn, $animalsDn),
1297
+                ],
1298
+                [
1299
+                    'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base,'cn=Birds,' . $base,'cn=Animals,' . $base], $animalsDn),
1300
+                    'cn=Birds,' . $base => array_merge(['cn=Animals,' . $base,'cn=Birds,' . $base], $birdsDn),
1301
+                ]
1302
+            ],
1303
+            [ #4 – Complicated nested group
1304
+                ['cn=Things,' . $base => array_merge($birdsDn, $animalsDn, $thingsDn, $plantsDn)],
1305
+                [
1306
+                    'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn),
1307
+                    'cn=Birds,' . $base => $birdsDn,
1308
+                    'cn=Plants,' . $base => $plantsDn,
1309
+                    'cn=Things,' . $base => array_merge(['cn=Animals,' . $base,'cn=Plants,' . $base], $thingsDn),
1310
+                ]
1311
+            ],
1312
+        ];
1313
+    }
1314
+
1315
+    #[\PHPUnit\Framework\Attributes\DataProvider('groupMemberProvider')]
1316
+    public function testGroupMembers(array $expectedResult, array $groupsInfo): void {
1317
+        $this->access->expects($this->any())
1318
+            ->method('readAttribute')
1319
+            ->willReturnCallback(function ($group) use ($groupsInfo) {
1320
+                if (isset($groupsInfo[$group])) {
1321
+                    return $groupsInfo[$group];
1322
+                }
1323
+                return [];
1324
+            });
1325
+
1326
+        $this->access->connection->expects($this->any())
1327
+            ->method('__get')
1328
+            ->willReturnCallback(function (string $name) {
1329
+                if ($name === 'ldapNestedGroups') {
1330
+                    return 1;
1331
+                } elseif ($name === 'ldapGroupMemberAssocAttr') {
1332
+                    return 'attr';
1333
+                }
1334
+                return null;
1335
+            });
1336
+
1337
+        $this->initBackend();
1338
+        foreach ($expectedResult as $groupDN => $expectedMembers) {
1339
+            $resultingMembers = $this->invokePrivate($this->groupBackend, '_groupMembers', [$groupDN]);
1340
+
1341
+            sort($expectedMembers);
1342
+            sort($resultingMembers);
1343
+            $this->assertEquals($expectedMembers, $resultingMembers);
1344
+        }
1345
+    }
1346
+
1347
+    public static function displayNameProvider(): array {
1348
+        return [
1349
+            ['Graphic Novelists', ['Graphic Novelists']],
1350
+            ['', false],
1351
+        ];
1352
+    }
1353
+
1354
+    #[\PHPUnit\Framework\Attributes\DataProvider('displayNameProvider')]
1355
+    public function testGetDisplayName(string $expected, bool|array $ldapResult): void {
1356
+        $gid = 'graphic_novelists';
1357
+
1358
+        $this->access->expects($this->atLeastOnce())
1359
+            ->method('readAttribute')
1360
+            ->willReturn($ldapResult);
1361
+
1362
+        $this->access->connection->expects($this->any())
1363
+            ->method('__get')
1364
+            ->willReturnCallback(function ($name) {
1365
+                if ($name === 'ldapGroupMemberAssocAttr') {
1366
+                    return 'member';
1367
+                } elseif ($name === 'ldapGroupFilter') {
1368
+                    return 'objectclass=nextcloudGroup';
1369
+                } elseif ($name === 'ldapGroupDisplayName') {
1370
+                    return 'cn';
1371
+                }
1372
+                return null;
1373
+            });
1374
+
1375
+        $this->access->expects($this->any())
1376
+            ->method('groupname2dn')
1377
+            ->willReturn('fakedn');
1378
+
1379
+        $this->initBackend();
1380
+        $this->assertSame($expected, $this->groupBackend->getDisplayName($gid));
1381
+    }
1382 1382
 }
Please login to merge, or discard this patch.
Spacing   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
 			->willReturn($groupDN);
65 65
 		$this->access->expects($this->any())
66 66
 			->method('readAttribute')
67
-			->willReturnCallback(function ($dn) use ($groupDN) {
67
+			->willReturnCallback(function($dn) use ($groupDN) {
68 68
 				if ($dn === $groupDN) {
69 69
 					return [
70 70
 						'uid=u11,ou=users,dc=foo,dc=bar',
@@ -112,7 +112,7 @@  discard block
 block discarded – undo
112 112
 	private function enableGroups(): void {
113 113
 		$this->access->connection->expects($this->any())
114 114
 			->method('__get')
115
-			->willReturnCallback(function ($name) {
115
+			->willReturnCallback(function($name) {
116 116
 				if ($name === 'ldapDynamicGroupMemberURL') {
117 117
 					return '';
118 118
 				} elseif ($name === 'ldapBaseGroups') {
@@ -133,7 +133,7 @@  discard block
 block discarded – undo
133 133
 			->willReturn([]);
134 134
 		$this->access->expects($this->any())
135 135
 			->method('readAttribute')
136
-			->willReturnCallback(function ($name) {
136
+			->willReturnCallback(function($name) {
137 137
 				//the search operation will call readAttribute, thus we need
138 138
 				//to analyze the "dn". All other times we just need to return
139 139
 				//something that is neither null or false, but once an array
@@ -146,8 +146,8 @@  discard block
 block discarded – undo
146 146
 			});
147 147
 		$this->access->expects($this->any())
148 148
 			->method('dn2username')
149
-			->willReturnCallback(function () {
150
-				return 'foobar' . Server::get(ISecureRandom::class)->generate(7);
149
+			->willReturnCallback(function() {
150
+				return 'foobar'.Server::get(ISecureRandom::class)->generate(7);
151 151
 			});
152 152
 		$this->access->expects($this->any())
153 153
 			->method('isDNPartOfBase')
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
 		$connection = $this->access->connection;
288 288
 		$connection->expects($this->once())
289 289
 			->method('getFromCache')
290
-			->with('primaryGroupIDtoName_' . $gid)
290
+			->with('primaryGroupIDtoName_'.$gid)
291 291
 			->willReturn('MyGroup');
292 292
 
293 293
 		$this->access->expects($this->never())
@@ -446,7 +446,7 @@  discard block
 block discarded – undo
446 446
 
447 447
 		$uid = 'someUser';
448 448
 		$gid = 'someGroup';
449
-		$cacheKey = 'inGroup' . $uid . ':' . $gid;
449
+		$cacheKey = 'inGroup'.$uid.':'.$gid;
450 450
 
451 451
 		$this->access->connection->expects($this->once())
452 452
 			->method('getFromCache')
@@ -482,7 +482,7 @@  discard block
 block discarded – undo
482 482
 
483 483
 		$this->access->connection->expects($this->any())
484 484
 			->method('__get')
485
-			->willReturnCallback(function ($name) {
485
+			->willReturnCallback(function($name) {
486 486
 				switch ($name) {
487 487
 					case 'ldapGroupMemberAssocAttr':
488 488
 						return 'member';
@@ -521,7 +521,7 @@  discard block
 block discarded – undo
521 521
 
522 522
 		$this->access->connection->expects($this->any())
523 523
 			->method('__get')
524
-			->willReturnCallback(function ($name) {
524
+			->willReturnCallback(function($name) {
525 525
 				switch ($name) {
526 526
 					case 'ldapGroupMemberAssocAttr':
527 527
 						return 'member';
@@ -567,7 +567,7 @@  discard block
 block discarded – undo
567 567
 
568 568
 		$this->access->connection->expects($this->any())
569 569
 			->method('__get')
570
-			->willReturnCallback(function ($name) {
570
+			->willReturnCallback(function($name) {
571 571
 				switch ($name) {
572 572
 					case 'ldapGroupMemberAssocAttr':
573 573
 						return 'memberUid';
@@ -636,7 +636,7 @@  discard block
 block discarded – undo
636 636
 			->willReturn(null);
637 637
 		$this->access->expects($this->any())
638 638
 			->method('readAttribute')
639
-			->willReturnCallback(function ($dn, $attr) {
639
+			->willReturnCallback(function($dn, $attr) {
640 640
 				if ($attr === 'primaryGroupToken') {
641 641
 					return [1337];
642 642
 				} elseif ($attr === 'gidNumber') {
@@ -679,7 +679,7 @@  discard block
 block discarded – undo
679 679
 			->willReturn(null);
680 680
 		$this->access->expects($this->any())
681 681
 			->method('readAttribute')
682
-			->willReturnCallback(function ($dn, $attr) {
682
+			->willReturnCallback(function($dn, $attr) {
683 683
 				if ($attr === 'primaryGroupToken') {
684 684
 					return [1337];
685 685
 				}
@@ -721,7 +721,7 @@  discard block
 block discarded – undo
721 721
 
722 722
 		$this->access->expects($this->any())
723 723
 			->method('readAttribute')
724
-			->willReturnCallback(function ($dn, $attr) {
724
+			->willReturnCallback(function($dn, $attr) {
725 725
 				if ($attr === 'primaryGroupToken') {
726 726
 					return [1337];
727 727
 				}
@@ -785,7 +785,7 @@  discard block
 block discarded – undo
785 785
 	public function testGetUserGroupsMemberOfDisabled(): void {
786 786
 		$this->access->connection->expects($this->any())
787 787
 			->method('__get')
788
-			->willReturnCallback(function ($name) {
788
+			->willReturnCallback(function($name) {
789 789
 				if ($name === 'useMemberOfToDetectMembership') {
790 790
 					return 0;
791 791
 				} elseif ($name === 'ldapDynamicGroupMemberURL') {
@@ -945,14 +945,14 @@  discard block
 block discarded – undo
945 945
 		$groupFilter = '(&(objectclass=nextcloudGroup)(nextcloudEnabled=TRUE))';
946 946
 		$this->access->connection->expects($this->any())
947 947
 			->method('__get')
948
-			->willReturnCallback(function (string $name) use ($nestedGroups, $groupFilter) {
948
+			->willReturnCallback(function(string $name) use ($nestedGroups, $groupFilter) {
949 949
 				switch ($name) {
950 950
 					case 'useMemberOfToDetectMembership':
951 951
 						return 0;
952 952
 					case 'ldapDynamicGroupMemberURL':
953 953
 						return '';
954 954
 					case 'ldapNestedGroups':
955
-						return (int)$nestedGroups;
955
+						return (int) $nestedGroups;
956 956
 					case 'ldapGroupMemberAssocAttr':
957 957
 						return 'member';
958 958
 					case 'ldapGroupFilter':
@@ -978,7 +978,7 @@  discard block
 block discarded – undo
978 978
 			->willReturn([]);
979 979
 		$this->access->expects($this->any())
980 980
 			->method('combineFilterWithAnd')
981
-			->willReturnCallback(function (array $filterParts) {
981
+			->willReturnCallback(function(array $filterParts) {
982 982
 				// ⚠ returns a pseudo-filter only, not real LDAP Filter syntax
983 983
 				return implode('&', $filterParts);
984 984
 			});
@@ -1008,7 +1008,7 @@  discard block
 block discarded – undo
1008 1008
 			->willReturn($expectedGroupsNames);
1009 1009
 		$this->access->expects($nestedGroups ? $this->atLeastOnce() : $this->once())
1010 1010
 			->method('fetchListOfGroups')
1011
-			->willReturnCallback(function ($filter, $attr, $limit, $offset) use ($nestedGroups, $groupFilter, $group1, $group2, $group3, $dn) {
1011
+			->willReturnCallback(function($filter, $attr, $limit, $offset) use ($nestedGroups, $groupFilter, $group1, $group2, $group3, $dn) {
1012 1012
 				static $firstRun = true;
1013 1013
 				if (!$nestedGroups) {
1014 1014
 					// When nested groups are enabled, groups cannot be filtered early as it would
@@ -1016,10 +1016,10 @@  discard block
 block discarded – undo
1016 1016
 					$this->assertTrue(str_contains($filter, $groupFilter));
1017 1017
 				}
1018 1018
 				[$memberFilter] = explode('&', $filter);
1019
-				if ($memberFilter === 'member=' . $dn) {
1019
+				if ($memberFilter === 'member='.$dn) {
1020 1020
 					return [$group1, $group2];
1021 1021
 					return [];
1022
-				} elseif ($memberFilter === 'member=' . $group2['dn'][0]) {
1022
+				} elseif ($memberFilter === 'member='.$group2['dn'][0]) {
1023 1023
 					return [$group3];
1024 1024
 				} else {
1025 1025
 					return [];
@@ -1027,12 +1027,12 @@  discard block
 block discarded – undo
1027 1027
 			});
1028 1028
 		$this->access->expects($this->any())
1029 1029
 			->method('dn2groupname')
1030
-			->willReturnCallback(function (string $dn) {
1030
+			->willReturnCallback(function(string $dn) {
1031 1031
 				return ldap_explode_dn($dn, 1)[0];
1032 1032
 			});
1033 1033
 		$this->access->expects($this->any())
1034 1034
 			->method('groupname2dn')
1035
-			->willReturnCallback(function (string $gid) use ($group1, $group2, $group3) {
1035
+			->willReturnCallback(function(string $gid) use ($group1, $group2, $group3) {
1036 1036
 				if ($gid === $group1['cn']) {
1037 1037
 					return $group1['dn'][0];
1038 1038
 				}
@@ -1248,11 +1248,11 @@  discard block
 block discarded – undo
1248 1248
 		$base = 'dc=species,dc=earth';
1249 1249
 
1250 1250
 		$birdsDn = [
1251
-			'uid=3723,' . $base,
1252
-			'uid=8372,' . $base,
1253
-			'uid=8427,' . $base,
1254
-			'uid=2333,' . $base,
1255
-			'uid=4754,' . $base,
1251
+			'uid=3723,'.$base,
1252
+			'uid=8372,'.$base,
1253
+			'uid=8427,'.$base,
1254
+			'uid=2333,'.$base,
1255
+			'uid=4754,'.$base,
1256 1256
 		];
1257 1257
 		$birdsUid = [
1258 1258
 			'3723',
@@ -1262,51 +1262,51 @@  discard block
 block discarded – undo
1262 1262
 			'4754',
1263 1263
 		];
1264 1264
 		$animalsDn = [
1265
-			'uid=lion,' . $base,
1266
-			'uid=tiger,' . $base,
1265
+			'uid=lion,'.$base,
1266
+			'uid=tiger,'.$base,
1267 1267
 		];
1268 1268
 		$plantsDn = [
1269
-			'uid=flower,' . $base,
1270
-			'uid=tree,' . $base,
1269
+			'uid=flower,'.$base,
1270
+			'uid=tree,'.$base,
1271 1271
 		];
1272 1272
 		$thingsDn = [
1273
-			'uid=thing1,' . $base,
1274
-			'uid=thing2,' . $base,
1273
+			'uid=thing1,'.$base,
1274
+			'uid=thing2,'.$base,
1275 1275
 		];
1276 1276
 
1277 1277
 		return [
1278
-			[ #0 – test DNs
1279
-				['cn=Birds,' . $base => $birdsDn],
1280
-				['cn=Birds,' . $base => $birdsDn]
1278
+			[#0 – test DNs
1279
+				['cn=Birds,'.$base => $birdsDn],
1280
+				['cn=Birds,'.$base => $birdsDn]
1281 1281
 			],
1282
-			[ #1 – test uids
1283
-				['cn=Birds,' . $base => $birdsUid],
1284
-				['cn=Birds,' . $base => $birdsUid]
1282
+			[#1 – test uids
1283
+				['cn=Birds,'.$base => $birdsUid],
1284
+				['cn=Birds,'.$base => $birdsUid]
1285 1285
 			],
1286
-			[ #2 – test simple nested group
1287
-				['cn=Animals,' . $base => array_merge($birdsDn, $animalsDn)],
1286
+			[#2 – test simple nested group
1287
+				['cn=Animals,'.$base => array_merge($birdsDn, $animalsDn)],
1288 1288
 				[
1289
-					'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn),
1290
-					'cn=Birds,' . $base => $birdsDn,
1289
+					'cn=Animals,'.$base => array_merge(['cn=Birds,'.$base], $animalsDn),
1290
+					'cn=Birds,'.$base => $birdsDn,
1291 1291
 				]
1292 1292
 			],
1293
-			[ #3 – test recursive nested group
1293
+			[#3 – test recursive nested group
1294 1294
 				[
1295
-					'cn=Animals,' . $base => array_merge($birdsDn, $animalsDn),
1296
-					'cn=Birds,' . $base => array_merge($birdsDn, $animalsDn),
1295
+					'cn=Animals,'.$base => array_merge($birdsDn, $animalsDn),
1296
+					'cn=Birds,'.$base => array_merge($birdsDn, $animalsDn),
1297 1297
 				],
1298 1298
 				[
1299
-					'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base,'cn=Birds,' . $base,'cn=Animals,' . $base], $animalsDn),
1300
-					'cn=Birds,' . $base => array_merge(['cn=Animals,' . $base,'cn=Birds,' . $base], $birdsDn),
1299
+					'cn=Animals,'.$base => array_merge(['cn=Birds,'.$base, 'cn=Birds,'.$base, 'cn=Animals,'.$base], $animalsDn),
1300
+					'cn=Birds,'.$base => array_merge(['cn=Animals,'.$base, 'cn=Birds,'.$base], $birdsDn),
1301 1301
 				]
1302 1302
 			],
1303
-			[ #4 – Complicated nested group
1304
-				['cn=Things,' . $base => array_merge($birdsDn, $animalsDn, $thingsDn, $plantsDn)],
1303
+			[#4 – Complicated nested group
1304
+				['cn=Things,'.$base => array_merge($birdsDn, $animalsDn, $thingsDn, $plantsDn)],
1305 1305
 				[
1306
-					'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn),
1307
-					'cn=Birds,' . $base => $birdsDn,
1308
-					'cn=Plants,' . $base => $plantsDn,
1309
-					'cn=Things,' . $base => array_merge(['cn=Animals,' . $base,'cn=Plants,' . $base], $thingsDn),
1306
+					'cn=Animals,'.$base => array_merge(['cn=Birds,'.$base], $animalsDn),
1307
+					'cn=Birds,'.$base => $birdsDn,
1308
+					'cn=Plants,'.$base => $plantsDn,
1309
+					'cn=Things,'.$base => array_merge(['cn=Animals,'.$base, 'cn=Plants,'.$base], $thingsDn),
1310 1310
 				]
1311 1311
 			],
1312 1312
 		];
@@ -1316,7 +1316,7 @@  discard block
 block discarded – undo
1316 1316
 	public function testGroupMembers(array $expectedResult, array $groupsInfo): void {
1317 1317
 		$this->access->expects($this->any())
1318 1318
 			->method('readAttribute')
1319
-			->willReturnCallback(function ($group) use ($groupsInfo) {
1319
+			->willReturnCallback(function($group) use ($groupsInfo) {
1320 1320
 				if (isset($groupsInfo[$group])) {
1321 1321
 					return $groupsInfo[$group];
1322 1322
 				}
@@ -1325,7 +1325,7 @@  discard block
 block discarded – undo
1325 1325
 
1326 1326
 		$this->access->connection->expects($this->any())
1327 1327
 			->method('__get')
1328
-			->willReturnCallback(function (string $name) {
1328
+			->willReturnCallback(function(string $name) {
1329 1329
 				if ($name === 'ldapNestedGroups') {
1330 1330
 					return 1;
1331 1331
 				} elseif ($name === 'ldapGroupMemberAssocAttr') {
@@ -1352,7 +1352,7 @@  discard block
 block discarded – undo
1352 1352
 	}
1353 1353
 
1354 1354
 	#[\PHPUnit\Framework\Attributes\DataProvider('displayNameProvider')]
1355
-	public function testGetDisplayName(string $expected, bool|array $ldapResult): void {
1355
+	public function testGetDisplayName(string $expected, bool | array $ldapResult): void {
1356 1356
 		$gid = 'graphic_novelists';
1357 1357
 
1358 1358
 		$this->access->expects($this->atLeastOnce())
@@ -1361,7 +1361,7 @@  discard block
 block discarded – undo
1361 1361
 
1362 1362
 		$this->access->connection->expects($this->any())
1363 1363
 			->method('__get')
1364
-			->willReturnCallback(function ($name) {
1364
+			->willReturnCallback(function($name) {
1365 1365
 				if ($name === 'ldapGroupMemberAssocAttr') {
1366 1366
 					return 'member';
1367 1367
 				} elseif ($name === 'ldapGroupFilter') {
Please login to merge, or discard this patch.