diff --git a/tests/acceptance/TestHelpers/EmailHelper.php b/tests/acceptance/TestHelpers/EmailHelper.php index 28e9df4465..6071bdba1d 100644 --- a/tests/acceptance/TestHelpers/EmailHelper.php +++ b/tests/acceptance/TestHelpers/EmailHelper.php @@ -127,13 +127,10 @@ class EmailHelper { } /** - * Returns the body of the last received email for the provided receiver according to the provided email address and the serial number - * For email number, 1 means the latest one + * Returns the body of the last received email for the provided receiver * * @param string $emailAddress - * @param string|null $xRequestId - * @param int|null $emailNumber For email number, 1 means the latest one - * @param int|null $waitTimeSec Time to wait for the email if the email has been delivered + * @param string $xRequestId * * @return string * @throws GuzzleException @@ -142,48 +139,40 @@ class EmailHelper { public static function getBodyOfLastEmail( string $emailAddress, string $xRequestId, - ?int $emailNumber = 1, - ?int $waitTimeSec = EMAIL_WAIT_TIMEOUT_SEC ): string { - $currentTime = \time(); - $endTime = $currentTime + $waitTimeSec; $mailBox = self::getMailBoxFromEmail($emailAddress); - while ($currentTime <= $endTime) { - $mailboxResponse = self::getMailboxInformation($mailBox, $xRequestId); - if (!empty($mailboxResponse) && \sizeof($mailboxResponse) >= $emailNumber) { - $mailboxId = $mailboxResponse[\sizeof($mailboxResponse) - $emailNumber]->id; - $response = self::getBodyOfAnEmailById($mailBox, $mailboxId, $xRequestId); - $body = \str_replace( - "\r\n", - "\n", - \quoted_printable_decode($response->body->text . "\n" . $response->body->html) - ); - return $body; - } - \usleep(STANDARD_SLEEP_TIME_MICROSEC * 50); - $currentTime = \time(); + $emails = self::getMailboxInformation($mailBox, $xRequestId); + if (!empty($emails)) { + $emailId = \array_pop($emails)->id; + $response = self::getBodyOfAnEmailById($mailBox, $emailId, $xRequestId); + $body = \str_replace( + "\r\n", + "\n", + \quoted_printable_decode($response->body->text . "\n" . $response->body->html) + ); + return $body; } - throw new Exception("Could not find the email to the address: " . $emailAddress); + return ""; } /** * Deletes all the emails for the provided mailbox * - * @param string $localInbucketUrl - * @param string|null $xRequestId + * @param string $url * @param string $mailBox + * @param string $xRequestId * * @return ResponseInterface * @throws GuzzleException */ - public static function deleteAllEmailsForAMailbox( - string $localInbucketUrl, - ?string $xRequestId, - string $mailBox + public static function deleteAllEmails( + string $url, + string $mailBox, + string $xRequestId, ): ResponseInterface { return HttpRequestHelper::delete( - $localInbucketUrl . "/api/v1/mailbox/" . $mailBox, - $xRequestId + $url . "/api/v1/mailbox/" . $mailBox, + $xRequestId, ); } } diff --git a/tests/acceptance/TestHelpers/HttpRequestHelper.php b/tests/acceptance/TestHelpers/HttpRequestHelper.php index 5decf10599..f81859fb53 100644 --- a/tests/acceptance/TestHelpers/HttpRequestHelper.php +++ b/tests/acceptance/TestHelpers/HttpRequestHelper.php @@ -57,7 +57,7 @@ class HttpRequestHelper { public static function numRetriesOnHttpTooEarly(): int { // Currently reva and OpenCloud may return HTTP_TOO_EARLY // So try up to 10 times before giving up. - return 10; + return STANDARD_RETRY_COUNT; } /** @@ -732,7 +732,7 @@ class HttpRequestHelper { */ public static function getRequestTimeout(): int { $timeout = \getenv("REQUEST_TIMEOUT"); - return (int)$timeout ?: 60; + return (int)$timeout ?: HTTP_REQUEST_TIMEOUT; } /** diff --git a/tests/acceptance/bootstrap/NotificationContext.php b/tests/acceptance/bootstrap/NotificationContext.php index 55f2409a91..184b48bf5d 100644 --- a/tests/acceptance/bootstrap/NotificationContext.php +++ b/tests/acceptance/bootstrap/NotificationContext.php @@ -589,36 +589,68 @@ class NotificationContext implements Context { ): void { $address = $this->featureContext->getEmailAddressForUser($user); $this->featureContext->pushEmailRecipientAsMailBox($address); - $actualEmailBodyContent = EmailHelper::getBodyOfLastEmail($address, $this->featureContext->getStepLineRef()); - if ($ignoreWhiteSpace) { - $expectedEmailBodyContent = preg_replace('/\s+/', '', $expectedEmailBodyContent); - $actualEmailBodyContent = preg_replace('/\s+/', '', $actualEmailBodyContent); - } + + // assert with retries as email delivery might be delayed + $retried = 0; + do { + $actualEmailBodyContent = EmailHelper::getBodyOfLastEmail( + $address, + $this->featureContext->getStepLineRef() + ); + if ($ignoreWhiteSpace) { + $expectedEmailBodyContent = preg_replace('/\s+/', '', $expectedEmailBodyContent); + $actualEmailBodyContent = preg_replace('/\s+/', '', $actualEmailBodyContent); + } + $tryAgain = !\str_contains($actualEmailBodyContent, $expectedEmailBodyContent) + && $retried <= STANDARD_RETRY_COUNT; + $retried++; + if ($tryAgain) { + $mailBox = EmailHelper::getMailBoxFromEmail($address); + echo "[INFO] Checking last email content for '$mailBox'. (Retry $retried)\n"; + // wait for 1 second before trying again + sleep(1); + } + } while ($tryAgain); Assert::assertStringContainsString( $expectedEmailBodyContent, $actualEmailBodyContent, "The email address '$address' should have received an" - . "email with the body containing $expectedEmailBodyContent - but the received email is $actualEmailBodyContent" + . " email with the body containing '$expectedEmailBodyContent'" + . " but the received email is '$actualEmailBodyContent'" ); } /** - * Delete all the inbucket emails + * Delete all emails from the mailboxes * * @AfterScenario @email * * @return void */ - public function clearInbucketMessages(): void { + public function clearMailboxes(): void { + $users = \array_keys($this->featureContext->getCreatedUsers()); try { - if (!empty($this->featureContext->emailRecipients)) { - foreach ($this->featureContext->emailRecipients as $emailRecipient) { - EmailHelper::deleteAllEmailsForAMailbox( - EmailHelper::getLocalEmailUrl(), - $this->featureContext->getStepLineRef(), - $emailRecipient - ); + if (!empty($users)) { + foreach ($users as $emailRecipient) { + $retried = 0; + do { + $res = EmailHelper::deleteAllEmails( + EmailHelper::getLocalEmailUrl(), + $emailRecipient, + $this->featureContext->getStepLineRef(), + ); + $deleteStatus = $res->getStatusCode(); + $mailBox = EmailHelper::getMailboxInformation($emailRecipient); + $tryAgain = ($deleteStatus !== 200 || !empty($mailBox)) && $retried <= STANDARD_RETRY_COUNT; + $retried++; + if ($tryAgain) { + echo "[INFO] Clearing mailbox '$emailRecipient'." + . " Status: $deleteStatus. Emails: " . \count($mailBox) . "." + . " (Retry $retried)\n"; + // wait for 1 second before trying again + sleep(1); + } + } while ($tryAgain); } } } catch (Exception $e) { diff --git a/tests/acceptance/bootstrap/bootstrap.php b/tests/acceptance/bootstrap/bootstrap.php index 13ef6320bc..507311ffea 100644 --- a/tests/acceptance/bootstrap/bootstrap.php +++ b/tests/acceptance/bootstrap/bootstrap.php @@ -27,51 +27,20 @@ $classLoader->addPsr4("TestHelpers\\", __DIR__ . "/../TestHelpers", true); $classLoader->register(); -// Sleep for 10 milliseconds -if (!\defined('STANDARD_SLEEP_TIME_MILLISEC')) { - \define('STANDARD_SLEEP_TIME_MILLISEC', 10); -} - -if (!\defined('STANDARD_SLEEP_TIME_MICROSEC')) { - \define('STANDARD_SLEEP_TIME_MICROSEC', STANDARD_SLEEP_TIME_MILLISEC * 1000); -} - -// Long timeout for use in code that needs to wait for known slow UI -if (!\defined('LONG_UI_WAIT_TIMEOUT_MILLISEC')) { - \define('LONG_UI_WAIT_TIMEOUT_MILLISEC', 60000); -} - -// Default timeout for use in code that needs to wait for the UI -if (!\defined('STANDARD_UI_WAIT_TIMEOUT_MILLISEC')) { - \define('STANDARD_UI_WAIT_TIMEOUT_MILLISEC', 10000); -} - -// Minimum timeout for use in code that needs to wait for the UI -if (!\defined('MINIMUM_UI_WAIT_TIMEOUT_MILLISEC')) { - \define('MINIMUM_UI_WAIT_TIMEOUT_MILLISEC', 500); -} - -if (!\defined('MINIMUM_UI_WAIT_TIMEOUT_MICROSEC')) { - \define('MINIMUM_UI_WAIT_TIMEOUT_MICROSEC', MINIMUM_UI_WAIT_TIMEOUT_MILLISEC * 1000); -} - -// Minimum timeout for emails -if (!\defined('EMAIL_WAIT_TIMEOUT_SEC')) { - \define('EMAIL_WAIT_TIMEOUT_SEC', 10); -} -if (!\defined('EMAIL_WAIT_TIMEOUT_MILLISEC')) { - \define('EMAIL_WAIT_TIMEOUT_MILLISEC', EMAIL_WAIT_TIMEOUT_SEC * 1000); -} - // Default number of times to retry where retries are useful if (!\defined('STANDARD_RETRY_COUNT')) { - \define('STANDARD_RETRY_COUNT', 5); + \define('STANDARD_RETRY_COUNT', 10); } // Minimum number of times to retry where retries are useful if (!\defined('MINIMUM_RETRY_COUNT')) { \define('MINIMUM_RETRY_COUNT', 2); } +// Minimum number of times to retry where retries are useful +if (!\defined('HTTP_REQUEST_TIMEOUT')) { + \define('HTTP_REQUEST_TIMEOUT', 60); +} + // The remote server-under-test might or might not happen to have this directory. // If it does not exist, then the tests may end up creating it. if (!\defined('ACCEPTANCE_TEST_DIR_ON_REMOTE_SERVER')) {