From dbbacb488d054280c35dc5cdfa167d319b094ce9 Mon Sep 17 00:00:00 2001 From: Daniel Kesselberg Date: Tue, 10 Jun 2025 14:26:49 +0200 Subject: [PATCH] test(dav): add integration test for principal property search Signed-off-by: Daniel Kesselberg --- .../composer/composer/autoload_classmap.php | 1 + .../composer/composer/autoload_static.php | 1 + apps/testing/lib/AppInfo/Application.php | 5 + apps/testing/lib/HiddenGroupBackend.php | 47 ++++++ build/integration/config/behat.yml | 2 + .../principal-property-search.feature | 13 ++ .../PrincipalPropertySearchContext.php | 141 ++++++++++++++++++ .../features/provisioning-v1.feature | 1 + 8 files changed, 211 insertions(+) create mode 100644 apps/testing/lib/HiddenGroupBackend.php create mode 100644 build/integration/dav_features/principal-property-search.feature create mode 100644 build/integration/features/bootstrap/PrincipalPropertySearchContext.php diff --git a/apps/testing/composer/composer/autoload_classmap.php b/apps/testing/composer/composer/autoload_classmap.php index 83d1fc771fc..ea03446b5ae 100644 --- a/apps/testing/composer/composer/autoload_classmap.php +++ b/apps/testing/composer/composer/autoload_classmap.php @@ -12,6 +12,7 @@ return array( 'OCA\\Testing\\Controller\\ConfigController' => $baseDir . '/../lib/Controller/ConfigController.php', 'OCA\\Testing\\Controller\\LockingController' => $baseDir . '/../lib/Controller/LockingController.php', 'OCA\\Testing\\Controller\\RateLimitTestController' => $baseDir . '/../lib/Controller/RateLimitTestController.php', + 'OCA\\Testing\\HiddenGroupBackend' => $baseDir . '/../lib/HiddenGroupBackend.php', 'OCA\\Testing\\Listener\\GetDeclarativeSettingsValueListener' => $baseDir . '/../lib/Listener/GetDeclarativeSettingsValueListener.php', 'OCA\\Testing\\Listener\\RegisterDeclarativeSettingsListener' => $baseDir . '/../lib/Listener/RegisterDeclarativeSettingsListener.php', 'OCA\\Testing\\Listener\\SetDeclarativeSettingsValueListener' => $baseDir . '/../lib/Listener/SetDeclarativeSettingsValueListener.php', diff --git a/apps/testing/composer/composer/autoload_static.php b/apps/testing/composer/composer/autoload_static.php index 3dc4bfe2fd6..afe4b146fc5 100644 --- a/apps/testing/composer/composer/autoload_static.php +++ b/apps/testing/composer/composer/autoload_static.php @@ -27,6 +27,7 @@ class ComposerStaticInitTesting 'OCA\\Testing\\Controller\\ConfigController' => __DIR__ . '/..' . '/../lib/Controller/ConfigController.php', 'OCA\\Testing\\Controller\\LockingController' => __DIR__ . '/..' . '/../lib/Controller/LockingController.php', 'OCA\\Testing\\Controller\\RateLimitTestController' => __DIR__ . '/..' . '/../lib/Controller/RateLimitTestController.php', + 'OCA\\Testing\\HiddenGroupBackend' => __DIR__ . '/..' . '/../lib/HiddenGroupBackend.php', 'OCA\\Testing\\Listener\\GetDeclarativeSettingsValueListener' => __DIR__ . '/..' . '/../lib/Listener/GetDeclarativeSettingsValueListener.php', 'OCA\\Testing\\Listener\\RegisterDeclarativeSettingsListener' => __DIR__ . '/..' . '/../lib/Listener/RegisterDeclarativeSettingsListener.php', 'OCA\\Testing\\Listener\\SetDeclarativeSettingsValueListener' => __DIR__ . '/..' . '/../lib/Listener/SetDeclarativeSettingsValueListener.php', diff --git a/apps/testing/lib/AppInfo/Application.php b/apps/testing/lib/AppInfo/Application.php index 6cd45b85b65..1441822866b 100644 --- a/apps/testing/lib/AppInfo/Application.php +++ b/apps/testing/lib/AppInfo/Application.php @@ -8,6 +8,7 @@ namespace OCA\Testing\AppInfo; use OCA\Testing\AlternativeHomeUserBackend; +use OCA\Testing\HiddenGroupBackend; use OCA\Testing\Listener\GetDeclarativeSettingsValueListener; use OCA\Testing\Listener\RegisterDeclarativeSettingsListener; use OCA\Testing\Listener\SetDeclarativeSettingsValueListener; @@ -26,6 +27,7 @@ use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\IGroupManager; use OCP\Settings\Events\DeclarativeSettingsGetValueEvent; use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent; use OCP\Settings\Events\DeclarativeSettingsSetValueEvent; @@ -66,5 +68,8 @@ class Application extends App implements IBootstrap { $userManager->clearBackends(); $userManager->registerBackend($context->getAppContainer()->get(AlternativeHomeUserBackend::class)); } + + $groupManager = $server->get(IGroupManager::class); + $groupManager->addBackend($server->get(HiddenGroupBackend::class)); } } diff --git a/apps/testing/lib/HiddenGroupBackend.php b/apps/testing/lib/HiddenGroupBackend.php new file mode 100644 index 00000000000..4f7004aae0a --- /dev/null +++ b/apps/testing/lib/HiddenGroupBackend.php @@ -0,0 +1,47 @@ +groupName = $groupName; + } + + public function inGroup($uid, $gid): bool { + return false; + } + + public function getUserGroups($uid): array { + return []; + } + + public function getGroups($search = '', $limit = -1, $offset = 0): array { + return $offset === 0 ? [$this->groupName] : []; + } + + public function groupExists($gid): bool { + return $gid === $this->groupName; + } + + public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0): array { + return []; + } + + public function hideGroup(string $groupId): bool { + return true; + } +} diff --git a/build/integration/config/behat.yml b/build/integration/config/behat.yml index 4185378211b..192dc973045 100644 --- a/build/integration/config/behat.yml +++ b/build/integration/config/behat.yml @@ -80,6 +80,8 @@ default: - CommandLineContext: baseUrl: http://localhost:8080 ocPath: ../../ + - PrincipalPropertySearchContext: + baseUrl: http://localhost:8080 federation: paths: - "%paths.base%/../federation_features" diff --git a/build/integration/dav_features/principal-property-search.feature b/build/integration/dav_features/principal-property-search.feature new file mode 100644 index 00000000000..b2195489263 --- /dev/null +++ b/build/integration/dav_features/principal-property-search.feature @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later + +Feature: principal-property-search + Background: + Given user "user0" exists + Given As an "admin" + Given invoking occ with "app:enable --force testing" + + Scenario: Find a principal by a given displayname + When searching for a principal matching "user0" + Then The search HTTP status code should be "207" + And The search response should contain "/remote.php/dav/principals/users/user0/" diff --git a/build/integration/features/bootstrap/PrincipalPropertySearchContext.php b/build/integration/features/bootstrap/PrincipalPropertySearchContext.php new file mode 100644 index 00000000000..064ff79dbd3 --- /dev/null +++ b/build/integration/features/bootstrap/PrincipalPropertySearchContext.php @@ -0,0 +1,141 @@ +baseUrl = $baseUrl; + + // in case of ci deployment we take the server url from the environment + $testServerUrl = getenv('TEST_SERVER_URL'); + if ($testServerUrl !== false) { + $this->baseUrl = substr($testServerUrl, 0, -5); + } + } + + /** @BeforeScenario */ + public function setUpScenario(): void { + $this->client = $this->createGuzzleInstance(); + } + + /** + * Create a Guzzle client with a higher truncateAt value to read full error responses. + */ + private function createGuzzleInstance(): Client { + $bodySummarizer = new BodySummarizer(2048); + + $stack = new HandlerStack(Utils::chooseHandler()); + $stack->push(Middleware::httpErrors($bodySummarizer), 'http_errors'); + $stack->push(Middleware::redirect(), 'allow_redirects'); + $stack->push(Middleware::cookies(), 'cookies'); + $stack->push(Middleware::prepareBody(), 'prepare_body'); + + return new Client(['handler' => $stack]); + } + + /** + * @When searching for a principal matching :match + * @param string $match + * @throws \Exception + */ + public function principalPropertySearch(string $match) { + $davUrl = $this->baseUrl . '/remote.php/dav/'; + $user = 'admin'; + $password = 'admin'; + + $this->response = $this->client->request( + 'REPORT', + $davUrl, + [ + 'body' => ' + + + + + + ' . $match . ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +', + 'auth' => [ + $user, + $password, + ], + 'headers' => [ + 'Content-Type' => 'application/xml; charset=UTF-8', + 'Depth' => '0', + ], + ] + ); + } + + /** + * @Then The search HTTP status code should be :code + * @param string $code + * @throws \Exception + */ + public function theHttpStatusCodeShouldBe(string $code): void { + if ((int) $code !== $this->response->getStatusCode()) { + throw new \Exception('Expected ' . (int) $code . ' got ' . $this->response->getStatusCode()); + } + } + + /** + * @Then The search response should contain :needle + * @param string $needle + * @throws \Exception + */ + public function theResponseShouldContain(string $needle): void { + $body = $this->response->getBody()->getContents(); + + if (str_contains($body, $needle) === false) { + throw new \Exception('Response does not contain "' . $needle . '"'); + } + } +} diff --git a/build/integration/features/provisioning-v1.feature b/build/integration/features/provisioning-v1.feature index 61a2eeca18c..b2307694257 100644 --- a/build/integration/features/provisioning-v1.feature +++ b/build/integration/features/provisioning-v1.feature @@ -450,6 +450,7 @@ Feature: provisioning Then groups returned are | EspaƱa | | admin | + | hidden_group | | new-group | Scenario: create a subadmin