friendica-addons/s3_storage/vendor/akeeba/s3/minitest/minitest.php

441 lines
10 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Akeeba Engine
*
* @package akeebaengine
* @copyright Copyright (c)2006-2024 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
use Akeeba\S3\Configuration;
use Akeeba\S3\Connector;
/**
* The Miniature Test Framework For The Akeeba S3 Library
*
* This is a self-contained test-suite runner. Running minitest.php will execute all the tests against all
* configurations set up in the config.php file. When it's decked out with all real world examples this can take many
* hours to complete (it's not as "mini" as its name would like you to believe).
*
* Please read NOTES.md before proceeding and do keep in mind that some tests may fail for reasons outside the control
* of the library such as network conditions, whether PHP has a configured Certification Authority cache etc.
*
* As to why we didn't use Unit Tests: Elementary, dear Watson. Unit Tests are great when testing your code against a
* specification. In this case, the specification would be the Amazon S3 API documentation. Sounds great in theory, but
* not even Amazon itself works according to its own documentation, let alone the third party "S3-compatible" services
* which each one implements its own interpretation of that documentation. Therefore, slow-as-heck integration testing
* is the only way to do any kind of meaningful testing.
*/
// Necessary for including the library
define('AKEEBAENGINE', 1);
if (!file_exists(__DIR__ . '/../vendor/autoload.php'))
{
die ('Please run composer install before running the mini test suite.');
}
// Use Composer's autoloader to load the library
/** @var \Composer\Autoload\ClassLoader $autoloader */
$autoloader = require_once(__DIR__ . '/../vendor/autoload.php');
// Add the minitest PSR-4 path map to Composer's autoloader
$autoloader->addPsr4('Akeeba\\MiniTest\\', __DIR__);
function getAllTestClasses(): array
{
static $testClasses = [];
if (!empty($testClasses))
{
return $testClasses;
}
$folder = __DIR__ . '/Test';
$di = new DirectoryIterator($folder);
foreach ($di as $entry)
{
if ($entry->isDot() || !$entry->isFile())
{
continue;
}
$baseName = $entry->getBasename('.php');
$className = '\\Akeeba\\MiniTest\\Test\\' . $baseName;
if (!class_exists($className))
{
continue;
}
$reflectedClass = new ReflectionClass($className);
if ($reflectedClass->isAbstract())
{
continue;
}
$testClasses[] = $className;
}
return $testClasses;
}
function getTestMethods(string $className): array
{
static $classMethodMap = [];
if (isset($classMethodMap[$className]))
{
return $classMethodMap[$className];
}
$classMethodMap[$className] = [];
if (!class_exists($className))
{
return $classMethodMap[$className];
}
$reflectedClass = new ReflectionClass($className);
$methods = $reflectedClass->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_STATIC);
$classMethodMap[$className] = array_map(function (ReflectionMethod $refMethod) {
if ($refMethod->isPrivate() || $refMethod->isProtected() || $refMethod->isAbstract())
{
return null;
}
if (!$refMethod->isStatic())
{
return null;
}
return $refMethod->getName();
}, $methods);
$classMethodMap[$className] = array_filter($classMethodMap[$className], function ($method) {
if (is_null($method))
{
return false;
}
if (in_array($method, ['setup', 'teardown']))
{
return false;
}
return true;
});
return $classMethodMap[$className];
}
function simplifyClassName(?string $className): string
{
if (empty($className))
{
return '';
}
$namespace = __NAMESPACE__ . '\\Test\\';
if (strpos($className, $namespace) === 0)
{
return substr($className, strlen($namespace));
}
return $className;
}
if (!file_exists(__DIR__ . '/config.php'))
{
die ('Please rename config.dist.php to config.php and customise it before running the mini test suite.');
}
require __DIR__ . '/config.php';
global $testConfigurations;
$total = 0;
$broken = 0;
$failed = 0;
$successful = 0;
foreach ($testConfigurations as $description => $setup)
{
echo "" . $description . PHP_EOL;
echo str_repeat('〰', 80) . PHP_EOL . PHP_EOL;
if ($setup['skip'] ?? false)
{
echo "\t🤡 Skipping\n\n";
continue;
}
// Extract the configuration options
if (!isset($setup['configuration']))
{
$setup['configuration'] = [];
}
$configOptions = array_merge([
'access' => defined('DEFAULT_ACCESS_KEY') ? DEFAULT_ACCESS_KEY : null,
'secret' => defined('DEFAULT_SECRET_KEY') ? DEFAULT_SECRET_KEY : null,
'region' => defined('DEFAULT_REGION') ? DEFAULT_REGION : null,
'bucket' => defined('DEFAULT_BUCKET') ? DEFAULT_BUCKET : null,
'signature' => defined('DEFAULT_SIGNATURE') ? DEFAULT_SIGNATURE : null,
'dualstack' => defined('DEFAULT_DUALSTACK') ? DEFAULT_DUALSTACK : null,
'path_access' => defined('DEFAULT_PATH_ACCESS') ? DEFAULT_PATH_ACCESS : null,
'ssl' => defined('DEFAULT_SSL') ? DEFAULT_SSL : null,
'endpoint' => defined('DEFAULT_ENDPOINT') ? constant('DEFAULT_ENDPOINT') : null,
], $setup['configuration']);
// Extract the test classes/methods to run
if (!isset($setup['tests']))
{
$setup['tests'] = getAllTestClasses();
}
$tests = $setup['tests'];
if (!is_array($tests) || (is_array($tests) && in_array('*', $tests)))
{
$tests = getAllTestClasses();
}
// Create the S3 configuration object
$s3Configuration = new Configuration($configOptions['access'], $configOptions['secret'], $configOptions['signature'], $configOptions['region']);
$s3Configuration->setRegion($configOptions['region']);
$s3Configuration->setSignatureMethod($configOptions['signature']);
if (!is_null($configOptions['endpoint']))
{
$s3Configuration->setEndpoint($configOptions['endpoint']);
// We need to redo this because setting the endpoint may reset these options
$s3Configuration->setRegion($configOptions['region']);
$s3Configuration->setSignatureMethod($configOptions['signature']);
}
$s3Configuration->setUseDualstackUrl($configOptions['dualstack']);
$s3Configuration->setUseLegacyPathStyle($configOptions['path_access']);
$s3Configuration->setSSL($configOptions['ssl']);
// Feature flags
if (isset($configOptions['alternateDateHeaderFormat']))
{
$s3Configuration->setAlternateDateHeaderFormat((bool) $configOptions['alternateDateHeaderFormat']);
}
if (isset($configOptions['useHTTPDateHeader']))
{
$s3Configuration->setUseHTTPDateHeader((bool) $configOptions['useHTTPDateHeader']);
}
if (isset($configOptions['preSignedBucketInURL']))
{
$s3Configuration->setPreSignedBucketInURL((bool) $configOptions['preSignedBucketInURL']);
}
// Create the connector object
$s3Connector = new Connector($s3Configuration);
// Run the tests
foreach ($tests as $testInfo)
{
if (!is_array($testInfo))
{
$className = $testInfo;
if (!class_exists($className))
{
$className = '\\Akeeba\\MiniTest\\Test\\' . $className;
}
if (!class_exists($className))
{
$total++;
$broken++;
echo " ⁉️ Test class {$className} not found." . PHP_EOL;
continue;
}
$testInfo = array_map(function ($method) use ($className) {
return [$className, $method];
}, getTestMethods($className));
}
else
{
[$className, $method] = $testInfo;
if (!class_exists($className))
{
$className = '\\Akeeba\\MiniTest\\Test\\' . $className;
}
if (!class_exists($className))
{
$total++;
$broken++;
echo " ⁉️ Test class {$className} not found." . PHP_EOL;
continue;
}
$testInfo = [
[$className, $method],
];
}
$firstOne = false;
$className = null;
$callableSetup = null;
$callableTeardown = null;
$simplifiedClassname = simplifyClassName($className);
if (!empty($testInfo))
{
$firstOne = array_shift($testInfo);
array_unshift($testInfo, $firstOne);
}
if ($firstOne)
{
[$className,] = $firstOne;
if ($className)
{
$callableSetup = [$className, 'setup'];
$callableTeardown = [$className, 'teardown'];
}
}
if (is_callable($callableSetup))
{
[$classNameSetup, $method] = $callableSetup;
$simplifiedClassname = simplifyClassName($classNameSetup);
echo " ⏱ Preparing {$simplifiedClassname}:{$method}";
call_user_func($callableSetup, $s3Connector, $configOptions);
echo "\r Prepared {$simplifiedClassname} " . PHP_EOL;
}
foreach ($testInfo as $callable)
{
$total++;
[$className, $method] = $callable;
if (!class_exists($className))
{
$broken++;
echo " ⁉️ Test class {$className} not found." . PHP_EOL;
continue;
}
if (!method_exists($className, $method))
{
$broken++;
echo " ⁉️ Method {$method} not found in test class {$className}." . PHP_EOL;
continue;
}
echo "{$simplifiedClassname}:{$method}";
$errorException = null;
try
{
$result = call_user_func([$className, $method], $s3Connector, $configOptions);
}
catch (Exception $e)
{
$result = false;
$errorException = $e;
}
echo "\r " . ($result ? '✔' : '🚨') . " {$simplifiedClassname}:{$method} " . PHP_EOL;
if ($result)
{
$successful++;
continue;
}
$failed++;
if (is_null($errorException))
{
echo " Returned false" . PHP_EOL;
continue;
}
echo " {$errorException->getCode()} {$errorException->getMessage()}" . PHP_EOL;
echo " {$errorException->getFile()}({$errorException->getLine()})" . PHP_EOL . PHP_EOL;
$errorLines = explode("\n", $errorException->getTraceAsString());
foreach ($errorLines as $line)
{
echo " $line" . PHP_EOL;
}
}
if (is_callable($callableTeardown))
{
[$className, $method] = $callableSetup;
echo " ⏱ Tearing down {$className}:{$method}";
call_user_func($callableTeardown, $s3Connector, $configOptions);
echo "\r Tore down {$className} " . PHP_EOL;
}
}
echo PHP_EOL;
}
echo PHP_EOL;
echo str_repeat('⎺', 80) . PHP_EOL;
echo PHP_EOL;
echo "Summary:" . PHP_EOL;
if ($broken)
{
echo " Broken : $broken" . PHP_EOL;
}
if ($failed)
{
echo " Failed : $failed" . PHP_EOL;
}
if ($successful)
{
echo " Successful : $successful" . PHP_EOL;
}
echo " Total : $total" . PHP_EOL . PHP_EOL;
echo "Conclusion: " . PHP_EOL . " ";
if ($failed > 0)
{
echo "❌ FAILED 😭😭😭" . PHP_EOL;
exit(1);
}
if ($successful === 0)
{
echo "🔥 No tests executed! 🤪" . PHP_EOL;
exit (3);
}
if ($broken > 0)
{
echo "⁉️ SUCCESS but some tests are broken 🤦" . PHP_EOL;
exit (2);
}
echo "✅ PASSED" . PHP_EOL;