2022-08-26 21:21:08 +12:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Appwrite\Tests;
|
|
|
|
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
|
|
|
|
/**
|
2022-08-30 23:10:15 +12:00
|
|
|
* Allows test methods annotated with {@see Retry} to be retried.
|
2022-08-26 21:21:08 +12:00
|
|
|
*/
|
|
|
|
trait Retryable
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Custom runBare, hides and defers to PHPUnit {@see TestCase} runBare function,
|
2022-08-30 23:10:15 +12:00
|
|
|
* accounting for any retries configured by the {@see Retry} annotation.
|
2022-08-26 21:21:08 +12:00
|
|
|
*
|
|
|
|
* @return void
|
2023-08-24 05:12:43 +12:00
|
|
|
*
|
2022-08-26 21:21:08 +12:00
|
|
|
* @throws \ReflectionException
|
|
|
|
* @throws \Throwable
|
|
|
|
*/
|
|
|
|
public function runBare(): void
|
|
|
|
{
|
|
|
|
$retries = $this->getNumberOfRetries();
|
|
|
|
$ex = null;
|
2023-08-24 05:12:43 +12:00
|
|
|
for ($i = 0; $i <= $retries; $i++) {
|
2022-08-26 21:21:08 +12:00
|
|
|
try {
|
|
|
|
parent::runBare();
|
2023-08-24 05:12:43 +12:00
|
|
|
|
2022-08-26 21:21:08 +12:00
|
|
|
return;
|
2023-08-24 05:12:43 +12:00
|
|
|
} catch (\Throwable|\Exception $ex) {
|
2022-08-26 21:21:08 +12:00
|
|
|
// Swallow the exception until we have exhausted our retries.
|
|
|
|
if ($i !== $retries) {
|
2023-08-24 05:12:43 +12:00
|
|
|
echo 'Flaky test failed, retrying...'.PHP_EOL;
|
2022-08-26 21:21:08 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($ex) {
|
|
|
|
throw $ex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return int
|
2023-08-24 05:12:43 +12:00
|
|
|
*
|
2022-08-26 21:21:08 +12:00
|
|
|
* @throws \ReflectionException
|
|
|
|
*/
|
|
|
|
private function getNumberOfRetries(): int
|
|
|
|
{
|
|
|
|
$root = new \ReflectionClass($this);
|
|
|
|
$case = $this->getTestCaseRoot($root);
|
|
|
|
$name = $case->getProperty('name');
|
|
|
|
$name->setAccessible(true);
|
|
|
|
$name = $name->getValue($this);
|
|
|
|
$method = $root->getMethod($name);
|
2022-08-30 23:10:15 +12:00
|
|
|
$attributes = $method->getAttributes(Retry::class);
|
2022-08-26 21:21:08 +12:00
|
|
|
$attribute = $attributes[0] ?? null;
|
|
|
|
$args = $attribute?->getArguments();
|
2022-08-30 23:12:58 +12:00
|
|
|
$retries = $args['count'] ?? 0;
|
2023-08-24 05:12:43 +12:00
|
|
|
|
2022-08-26 21:21:08 +12:00
|
|
|
return \max(0, $retries);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-08-24 05:12:43 +12:00
|
|
|
* @param \ReflectionClass $reflection
|
2022-08-26 21:21:08 +12:00
|
|
|
* @return \ReflectionClass
|
|
|
|
*/
|
|
|
|
private function getTestCaseRoot(\ReflectionClass $reflection): \ReflectionClass
|
|
|
|
{
|
|
|
|
if ($reflection->getName() === TestCase::class) {
|
|
|
|
return $reflection;
|
|
|
|
}
|
2023-08-24 05:12:43 +12:00
|
|
|
|
2022-08-26 21:21:08 +12:00
|
|
|
return $this->getTestCaseRoot($reflection->getParentClass());
|
|
|
|
}
|
|
|
|
}
|