diff --git a/tests/acceptance/bootstrap/SearchContext.php b/tests/acceptance/bootstrap/SearchContext.php index 7d2c5ff2c6..acaa0f5d6b 100644 --- a/tests/acceptance/bootstrap/SearchContext.php +++ b/tests/acceptance/bootstrap/SearchContext.php @@ -25,6 +25,7 @@ use GuzzleHttp\Exception\GuzzleException; use PHPUnit\Framework\Assert; use Psr\Http\Message\ResponseInterface; use TestHelpers\WebDavHelper; +use TestHelpers\WaitHelper; use TestHelpers\HttpRequestHelper; use TestHelpers\BehatHelper; use Behat\Step\Then; @@ -37,6 +38,7 @@ require_once 'bootstrap.php'; */ class SearchContext implements Context { private FeatureContext $featureContext; + private array $lastSearchQuery = []; /** * @param string $user @@ -149,6 +151,13 @@ class SearchContext implements Context { // NOTE: because indexing of newly uploaded files or directories with OpenCloud is decoupled and occurs asynchronously // short wait is necessary before searching sleep(10); + // remember the query so "should eventually contain" steps can re-search + $this->lastSearchQuery = [ + "user" => $user, + "pattern" => $pattern, + "limit" => $limit, + "properties" => $properties, + ]; $response = $this->searchFiles($user, $pattern, $limit, null, null, null, $properties); $this->featureContext->setResponse($response); } @@ -279,4 +288,83 @@ class SearchContext implements Context { $response = $this-> searchFiles($user, $pattern, null, $scopeType, $scope, $spaceName); $this->featureContext->setResponse($response); } + + /** + * re-run the last WebDAV search until the assertion passes or the WaitHelper + * timeout elapses, leaving the last response set for a final assertion by the + * caller. Indexing of newly uploaded resources is asynchronous, so a wanted + * file can be missing from an early search; OpenSearch never returns a partial + * document, so once the expected entries are present the result is complete. + * + * @param callable $assert + * + * @return void + */ + private function retrySearchUntilSatisfied(callable $assert): void { + Assert::assertNotEmpty( + $this->lastSearchQuery, + 'No search to retry. Use a "searches for ... using the WebDAV API" step first.' + ); + $query = $this->lastSearchQuery; + $response = WaitHelper::waitUntil( + fn () => $this->searchFiles( + $query["user"], + $query["pattern"], + $query["limit"], + null, + null, + null, + $query["properties"] + ), + function ($response) use ($assert) { + $this->featureContext->setResponse($response); + try { + $assert(); + return true; + } catch (\Throwable $e) { + return false; + } + } + ); + $this->featureContext->setResponse($response); + } + + /** + * @param string $user + * @param TableNode $expectedFiles + * + * @return void + */ + #[Then('/^the search result of user "([^"]*)" should eventually contain only these (?:files|entries):$/')] + public function theSearchResultShouldEventuallyContainOnlyEntries(string $user, TableNode $expectedFiles): void { + $assert = fn () => $this->featureContext->thePropfindResultShouldContainOnlyEntries($user, $expectedFiles); + $this->retrySearchUntilSatisfied($assert); + $assert(); + } + + /** + * @param string $user + * @param TableNode $expectedFiles + * + * @return void + */ + #[Then('/^the search result of user "([^"]*)" should eventually contain these (?:files|entries):$/')] + public function theSearchResultShouldEventuallyContainEntries(string $user, TableNode $expectedFiles): void { + $assert = fn () => $this->featureContext->thePropfindResultShouldContainEntries($user, '', $expectedFiles); + $this->retrySearchUntilSatisfied($assert); + $assert(); + } + + /** + * @param TableNode $expectedFiles + * @param string $expectedContent + * + * @return void + */ + #[Then('/^the search result should eventually contain these (?:files|entries) with highlight on keyword "([^"]*)"$/')] + public function theSearchResultShouldEventuallyContainEntriesWithHighlight(TableNode $expectedFiles, string $expectedContent): void { + $assert = fn () => $this->theSearchResultShouldContainEntriesWithHighlight($expectedFiles, $expectedContent); + $this->retrySearchUntilSatisfied($assert); + $assert(); + } } diff --git a/tests/acceptance/features/apiSearchContent/contentSearch.feature b/tests/acceptance/features/apiSearchContent/contentSearch.feature index b7189c4dcd..de808ca2da 100644 --- a/tests/acceptance/features/apiSearchContent/contentSearch.feature +++ b/tests/acceptance/features/apiSearchContent/contentSearch.feature @@ -16,7 +16,7 @@ Feature: content search And user "Alice" has uploaded file with content "namaste from nepal" to "hello.txt" When user "Alice" searches for "Content:hello" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | keywordAtStart.txt | | keywordAtMiddle.txt | | keywordAtLast.txt | @@ -34,15 +34,15 @@ Feature: content search And user "Alice" has uploaded file with content "alan@example.org want to say hello" to "findByEmail.docs" When user "Alice" searches for "Content:k6" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | wordWithNumber.md | When user "Alice" searches for "Content:https://opencloud.eu/" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | findByWebSite.txt | When user "Alice" searches for "Content:alan@" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | findByEmail.docs | Examples: | dav-path-version | @@ -71,11 +71,11 @@ Feature: content search And user "Alice" has uploaded file with content "He has expirience, we must to have, I have to find ...." to "fileWithStopWords.txt" When user "Alice" searches for 'Content:"he has"' using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | fileWithStopWords.txt | When user "Alice" searches for 'Content:"I have"' using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | fileWithStopWords.txt | Examples: | dav-path-version | @@ -101,7 +101,7 @@ Feature: content search And user "Brian" has a share "uploadFolder" synced When user "Brian" searches for "Content:hello" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Brian" should contain only these files: + And the search result of user "Brian" should eventually contain only these files: | keywordAtStart.txt | | keywordAtMiddle.txt | | keywordAtLast.txt | @@ -121,7 +121,7 @@ Feature: content search And user "Alice" has deleted file "keywordAtLast.txt" When user "Alice" searches for "Content:hello" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | keywordAtStart.txt | | keywordAtMiddle.txt | Examples: @@ -139,7 +139,7 @@ Feature: content search And user "Alice" has restored the file with original path "keywordAtStart.txt" When user "Alice" searches for "Content:hello" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | keywordAtStart.txt | Examples: | dav-path-version | @@ -154,7 +154,7 @@ Feature: content search And user "Alice" has restored version index "1" of file "test.txt" When user "Alice" searches for "Content:hello" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | test.txt | Examples: | dav-path-version | @@ -175,7 +175,7 @@ Feature: content search And using DAV path When user "Alice" searches for "Content:hello" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | keywordAtStart.txt | | keywordAtMiddle.txt | | keywordAtLast.txt | @@ -204,7 +204,7 @@ Feature: content search And using DAV path When user "Brian" searches for "Content:hello" using the WebDAV API Then the HTTP status code should be "207" - And the search result of user "Alice" should contain only these files: + And the search result of user "Alice" should eventually contain only these files: | keywordAtStart.txt | | keywordAtMiddle.txt | | keywordAtLast.txt | @@ -224,10 +224,10 @@ Feature: content search | technical task.txt | test | When user "Alice" searches for '' using the WebDAV API Then the HTTP status code should be "207" - And the search result should contain "" entries - And the search result of user "Alice" should contain these entries: + And the search result of user "Alice" should eventually contain these entries: | | | | + And the search result should contain "" entries Examples: | pattern | result-count | search-result-1 | search-result-2 | | Content:hello | 1 | technical task.txt | | @@ -251,7 +251,7 @@ Feature: content search And user "Alice" has uploaded a file inside space "project-space" with content "this is a simple odt file" to "test-odt-file.odt" When user "Alice" searches for "Content:simple" using the WebDAV API Then the HTTP status code should be "207" - And the search result should contain these entries with highlight on keyword "simple" + And the search result should eventually contain these entries with highlight on keyword "simple" | test-text-file.txt | | test-pdf-file.pdf | | test-cpp-file.cpp |