mirror of
https://git.friendi.ca/friendica/friendica-addons.git
synced 2025-07-12 11:28:49 +00:00
Add S3 Storage Backend
This commit is contained in:
parent
95fcf98759
commit
9c4b12f868
63 changed files with 8108 additions and 0 deletions
242
s3_storage/vendor/akeeba/s3/minitest/Test/AbstractTest.php
vendored
Normal file
242
s3_storage/vendor/akeeba/s3/minitest/Test/AbstractTest.php
vendored
Normal file
|
@ -0,0 +1,242 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
use RuntimeException;
|
||||
|
||||
abstract class AbstractTest
|
||||
{
|
||||
const TEN_KB = 10240;
|
||||
|
||||
const HUNDRED_KB = 102400;
|
||||
|
||||
const SIX_HUNDRED_KB = 614400;
|
||||
|
||||
const ONE_MB = 1048576;
|
||||
|
||||
const FIVE_MB = 5242880;
|
||||
|
||||
const SIX_MB = 6291456;
|
||||
|
||||
const TEN_MB = 10485760;
|
||||
|
||||
const ELEVEN_MB = 11534336;
|
||||
|
||||
const BLOCK_SIZE = 1048576;
|
||||
|
||||
const FILE_HASHING_ALGORITHM = 'sha256';
|
||||
|
||||
public static function setup(Connector $s3, array $options): void
|
||||
{
|
||||
// Runs before any test
|
||||
}
|
||||
|
||||
public static function teardown(Connector $s3, array $options): void
|
||||
{
|
||||
// Runs after all tests are finished
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file with random data and returns its file path.
|
||||
*
|
||||
* The random data in the file repeats every $blockSize bytes when $reuseBlock is true.
|
||||
*
|
||||
* @param int $size Size in files
|
||||
*
|
||||
* @param int $blockSize
|
||||
* @param bool $reuseBlock
|
||||
*
|
||||
* @return string The full path to the temporary file.
|
||||
*/
|
||||
protected static function createFile(int $size = AbstractTest::SIX_HUNDRED_KB, int $blockSize = self::BLOCK_SIZE, bool $reuseBlock = true)
|
||||
{
|
||||
$tempFilePath = tempnam(self::getTempFolder(), 'as3');
|
||||
|
||||
if ($tempFilePath === false)
|
||||
{
|
||||
throw new RuntimeException("Cannot create a temporary file.");
|
||||
}
|
||||
|
||||
$fp = @fopen($tempFilePath, 'wb', false);
|
||||
|
||||
if ($fp === false)
|
||||
{
|
||||
throw new RuntimeException("Cannot write to the temporary file.");
|
||||
}
|
||||
|
||||
$blockSize = self::BLOCK_SIZE;
|
||||
$lastBlockSize = $size % $blockSize;
|
||||
$wholeBlocks = (int) (($size - $lastBlockSize) / $blockSize);
|
||||
$blockData = self::getRandomData();
|
||||
|
||||
for ($i = 0; $i < $wholeBlocks; $i++)
|
||||
{
|
||||
fwrite($fp, $blockData);
|
||||
|
||||
if (!$reuseBlock)
|
||||
{
|
||||
$blockData = self::getRandomData($blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
if ($lastBlockSize > 0)
|
||||
{
|
||||
fwrite($fp, $blockData, $lastBlockSize);
|
||||
}
|
||||
|
||||
|
||||
fclose($fp);
|
||||
|
||||
return $tempFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a writeable temporary folder
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getTempFolder(): string
|
||||
{
|
||||
$tempPath = sys_get_temp_dir();
|
||||
|
||||
if (!is_writable($tempPath))
|
||||
{
|
||||
$tempPath = __DIR__ . '/tmp';
|
||||
|
||||
if (!is_dir($tempPath))
|
||||
{
|
||||
@mkdir($tempPath, 0755, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_writable($tempPath))
|
||||
{
|
||||
throw new RuntimeException("Cannot get a writeable temporary path.");
|
||||
}
|
||||
|
||||
return $tempPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that two files are of equal length and contents
|
||||
*
|
||||
* @param string $referenceFilePath The known, reference file
|
||||
* @param string $unknownFilePath The file we want to verify is the same as the reference file
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function areFilesEqual(string $referenceFilePath, string $unknownFilePath): bool
|
||||
{
|
||||
if (!file_exists($referenceFilePath) || !file_exists($unknownFilePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_file($referenceFilePath) || !is_file($unknownFilePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_readable($referenceFilePath) || !is_readable($unknownFilePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (@filesize($referenceFilePath) !== @filesize($unknownFilePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return hash_file(self::FILE_HASHING_ALGORITHM, $referenceFilePath) === hash_file(self::FILE_HASHING_ALGORITHM, $unknownFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that two strings are of equal length and contents
|
||||
*
|
||||
* @param string $referenceString The known, reference file
|
||||
* @param string $unknownString The file we want to verify is the same as the reference file
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function areStringsEqual(string $referenceString, string $unknownString): bool
|
||||
{
|
||||
return $referenceString === $unknownString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns random data of the specific size in bytes
|
||||
*
|
||||
* @param int $length How many bytes of random data to return
|
||||
*
|
||||
* @return string Your random data
|
||||
*/
|
||||
protected static function getRandomData(int $length = self::BLOCK_SIZE): string
|
||||
{
|
||||
$blockData = '';
|
||||
|
||||
if (substr(strtolower(PHP_OS), 0, 7) !== 'windows')
|
||||
{
|
||||
$fpRandom = @fopen('/dev/urandom', 'r');
|
||||
if ($fpRandom !== false)
|
||||
{
|
||||
$blockData = @fread($fpRandom, $length);
|
||||
@fclose($fpRandom);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($blockData) && function_exists('random_bytes'))
|
||||
{
|
||||
try
|
||||
{
|
||||
$blockData = random_bytes($length);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
$blockData = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($blockData) && function_exists('openssl_random_pseudo_bytes'))
|
||||
{
|
||||
$blockData = openssl_random_pseudo_bytes($length);
|
||||
}
|
||||
|
||||
if (empty($blockData) && function_exists('mcrypt_create_iv'))
|
||||
{
|
||||
$blockData = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
|
||||
|
||||
if (empty($blockData))
|
||||
{
|
||||
$blockData = mcrypt_create_iv($length, MCRYPT_RAND);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($blockData))
|
||||
{
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
{
|
||||
$blockData .= ord(mt_rand(0, 255));
|
||||
}
|
||||
}
|
||||
|
||||
return $blockData;
|
||||
}
|
||||
|
||||
protected static function assert(bool $condition, string $message): void
|
||||
{
|
||||
if ($condition)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
throw new RuntimeException($message);
|
||||
}
|
||||
}
|
217
s3_storage/vendor/akeeba/s3/minitest/Test/BigFiles.php
vendored
Normal file
217
s3_storage/vendor/akeeba/s3/minitest/Test/BigFiles.php
vendored
Normal file
|
@ -0,0 +1,217 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Input;
|
||||
|
||||
/**
|
||||
* Upload, download and delete big files (over 1MB), without multipart uploads. Uses string or file sources.
|
||||
*
|
||||
* @package Akeeba\MiniTest\Test
|
||||
*/
|
||||
class BigFiles extends AbstractTest
|
||||
{
|
||||
/**
|
||||
* Should I download the file after uploading it to test for contents consistency?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $downloadAfter = true;
|
||||
|
||||
/**
|
||||
* Should I delete the uploaded file after the test case is done?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $deleteRemote = true;
|
||||
|
||||
/**
|
||||
* Should I use multipart (chunked) uploads?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $multipart = false;
|
||||
|
||||
/**
|
||||
* Chunk size for each multipart upload. Must be at least 5MB or the library overrides us.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $uploadChunkSize = 5242880;
|
||||
|
||||
/**
|
||||
* Number of uploaded chunks.
|
||||
*
|
||||
* This is set by self::upload(). Zero for single part uploads, non-zero for multipart uploads.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $numberOfChunks = 0;
|
||||
|
||||
public static function upload5MBString(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::FIVE_MB, 'bigtest_5mb.dat');
|
||||
}
|
||||
|
||||
public static function upload6MBString(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::SIX_MB, 'bigtest_6mb.dat');
|
||||
}
|
||||
|
||||
public static function upload10MBString(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::TEN_MB, 'bigtest_10mb.dat');
|
||||
}
|
||||
|
||||
public static function upload11MBString(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::ELEVEN_MB, 'bigtest_11mb.dat');
|
||||
}
|
||||
|
||||
public static function upload5MBFile(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::FIVE_MB, 'bigtest_5mb.dat', false);
|
||||
}
|
||||
|
||||
public static function upload6MBFile(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::SIX_MB, 'bigtest_6mb.dat', false);
|
||||
}
|
||||
|
||||
public static function upload10MBFile(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::TEN_MB, 'bigtest_10mb.dat', false);
|
||||
}
|
||||
|
||||
public static function upload11MBFile(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::ELEVEN_MB, 'bigtest_11mb.dat', false);
|
||||
}
|
||||
|
||||
protected static function upload(Connector $s3, array $options, int $size, string $uri, bool $useString = true): bool
|
||||
{
|
||||
// Randomize the name. Required for archive buckets where you cannot overwrite data.
|
||||
$dotPos = strrpos($uri, '.');
|
||||
$uri = substr($uri, 0, $dotPos) . '.' . md5(microtime(false)) . substr($uri, $dotPos);
|
||||
|
||||
self::$numberOfChunks = 0;
|
||||
|
||||
if ($useString)
|
||||
{
|
||||
$sourceData = self::getRandomData($size);
|
||||
$input = Input::createFromData($sourceData);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a file with random data
|
||||
$sourceFile = self::createFile($size);
|
||||
$input = Input::createFromFile($sourceFile);
|
||||
}
|
||||
|
||||
// Upload the file. Throws exception if it fails.
|
||||
$bucket = $options['bucket'];
|
||||
|
||||
if (!self::$multipart)
|
||||
{
|
||||
$s3->putObject($input, $bucket, $uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get an upload session
|
||||
$uploadSession = $s3->startMultipart($input, $bucket, $uri);
|
||||
|
||||
// This array holds the etags of uploaded parts. Used by finalizeMultipart.
|
||||
$eTags = [];
|
||||
$partNumber = 1;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// We need to create a new input for each upload chunk
|
||||
if ($useString)
|
||||
{
|
||||
$input = Input::createFromData($sourceData);
|
||||
}
|
||||
else
|
||||
{
|
||||
$input = Input::createFromFile($sourceFile);
|
||||
}
|
||||
|
||||
$input->setUploadID($uploadSession);
|
||||
$input->setEtags($eTags);
|
||||
$input->setPartNumber($partNumber);
|
||||
|
||||
$etag = $s3->uploadMultipart($input, $bucket, $uri, [], self::$uploadChunkSize);
|
||||
|
||||
// If the result was null we have no more file parts to process.
|
||||
if (is_null($etag))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Append the etag to the etags array
|
||||
$eTags[] = $etag;
|
||||
|
||||
// Set the etags array in the Input object (required by finalizeMultipart)
|
||||
$input->setEtags($eTags);
|
||||
|
||||
$partNumber++;
|
||||
}
|
||||
|
||||
self::$numberOfChunks = count($eTags);
|
||||
|
||||
// Finalize the multipart upload. Tells Amazon to construct the file from the uploaded parts.
|
||||
$s3->finalizeMultipart($input, $bucket, $uri);
|
||||
}
|
||||
|
||||
// Tentatively accept that this method succeeded.
|
||||
$result = true;
|
||||
|
||||
// Should I download the file and compare its contents?
|
||||
if (self::$downloadAfter)
|
||||
{
|
||||
if ($useString)
|
||||
{
|
||||
// Download the data. Throws exception if it fails.
|
||||
$downloadedData = $s3->getObject($bucket, $uri);
|
||||
|
||||
// Compare the file contents.
|
||||
$result = self::areStringsEqual($sourceData, $downloadedData);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Download the data. Throws exception if it fails.
|
||||
$downloadedFile = tempnam(self::getTempFolder(), 'as3');
|
||||
$s3->getObject($bucket, $uri, $downloadedFile);
|
||||
|
||||
// Compare the file contents.
|
||||
$result = self::areFilesEqual($sourceFile, $downloadedFile);
|
||||
|
||||
@unlink($downloadedFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the local files
|
||||
if (!$useString)
|
||||
{
|
||||
@unlink($sourceFile);
|
||||
}
|
||||
|
||||
// Should I delete the remotely stored file?
|
||||
if (self::$deleteRemote)
|
||||
{
|
||||
// Delete the remote file. Throws exception if it fails.
|
||||
$s3->deleteObject($bucket, $uri);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
25
s3_storage/vendor/akeeba/s3/minitest/Test/BucketLocation.php
vendored
Normal file
25
s3_storage/vendor/akeeba/s3/minitest/Test/BucketLocation.php
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
|
||||
class BucketLocation extends AbstractTest
|
||||
{
|
||||
public static function getBucketLocation(Connector $s3, array $options): bool
|
||||
{
|
||||
$location = $s3->getBucketLocation($options['bucket']);
|
||||
|
||||
self::assert($location === $options['region'], "Bucket ‘{$options['bucket']}′ reports being in region ‘{$location}′ instead of expected ‘{$options['region']}′");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
52
s3_storage/vendor/akeeba/s3/minitest/Test/BucketsList.php
vendored
Normal file
52
s3_storage/vendor/akeeba/s3/minitest/Test/BucketsList.php
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
use RuntimeException;
|
||||
|
||||
class BucketsList extends AbstractTest
|
||||
{
|
||||
public static function listBucketsDetailed(Connector $s3, array $options): bool
|
||||
{
|
||||
$buckets = $s3->listBuckets(true);
|
||||
|
||||
self::assert(is_array($buckets), "Detailed buckets list is not an array");
|
||||
self::assert(isset($buckets['owner']), "Detailed buckets list does not list an owner");
|
||||
self::assert(isset($buckets['owner']['id']), "Detailed buckets list does not list an owner's id");
|
||||
self::assert(isset($buckets['owner']['name']), "Detailed buckets list does not list an owner's name");
|
||||
self::assert(isset($buckets['buckets']), "Detailed buckets list does not list any buckets");
|
||||
|
||||
foreach ($buckets['buckets'] as $bucketInfo)
|
||||
{
|
||||
self::assert(isset($bucketInfo['name']), "Bucket information does not list a name");
|
||||
self::assert(isset($bucketInfo['time']), "Bucket information does not list a created times");
|
||||
|
||||
if ($bucketInfo['name'] === $options['bucket'])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Detailed buckets list does not include configured bucket ‘{$options['bucket']}′");
|
||||
}
|
||||
|
||||
public static function listBucketsSimple(Connector $s3, array $options): bool
|
||||
{
|
||||
$buckets = $s3->listBuckets(false);
|
||||
|
||||
self::assert(is_array($buckets), "Simple buckets list is not an array");
|
||||
self::assert(in_array($options['bucket'], $buckets), "Simple buckets list does not include configured bucket ‘{$options['bucket']}′");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
308
s3_storage/vendor/akeeba/s3/minitest/Test/ListFiles.php
vendored
Normal file
308
s3_storage/vendor/akeeba/s3/minitest/Test/ListFiles.php
vendored
Normal file
|
@ -0,0 +1,308 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Exception\CannotPutFile;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Input;
|
||||
|
||||
class ListFiles extends AbstractTest
|
||||
{
|
||||
private static $paths = [
|
||||
'listtest_one.dat',
|
||||
'listtest_two.dat',
|
||||
'listtest_three.dat',
|
||||
'list_deeper/test_one.dat',
|
||||
'list_deeper/test_two.dat',
|
||||
'list_deeper/test_three.dat',
|
||||
'list_deeper/listtest_four.dat',
|
||||
'list_deeper/listtest_five.dat',
|
||||
'list_deeper/listtest_six.dat',
|
||||
'list_deeper/spam.dat',
|
||||
'list_deeper/listtest_deeper/seven.dat',
|
||||
'list_deeper/listtest_deeper/eight.dat',
|
||||
'spam.dat',
|
||||
];
|
||||
|
||||
public static function setup(Connector $s3, array $options): void
|
||||
{
|
||||
$data = self::getRandomData(self::TEN_KB);
|
||||
|
||||
foreach (self::$paths as $uri)
|
||||
{
|
||||
$input = Input::createFromData($data);
|
||||
try
|
||||
{
|
||||
$s3->putObject($input, $options['bucket'], $uri);
|
||||
}
|
||||
catch (CannotPutFile $e)
|
||||
{
|
||||
// Expected for archival buckets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function teardown(Connector $s3, array $options): void
|
||||
{
|
||||
foreach (self::$paths as $uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
$s3->deleteObject($options['bucket'], $uri);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
// No problem if I can't delete the file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function testGetAll(Connector $s3, array $options): bool
|
||||
{
|
||||
$listing = $s3->getBucket($options['bucket'], 'listtest_');
|
||||
|
||||
self::assert(is_array($listing), "The files listing must be an array");
|
||||
self::assert(count($listing) == 3, "I am expecting to see 3 files");
|
||||
|
||||
// Make sure I have the expected files
|
||||
self::assert(array_key_exists('listtest_one.dat', $listing), "File listtest_one.dat not in listing");
|
||||
self::assert(array_key_exists('listtest_two.dat', $listing), "File listtest_two.dat not in listing");
|
||||
self::assert(array_key_exists('listtest_three.dat', $listing), "File listtest_three.dat not in listing");
|
||||
|
||||
// I must not see the files in subdirectories
|
||||
self::assert(!array_key_exists('listtest_four.dat', $listing), "File listtest_four.dat in listing");
|
||||
self::assert(!array_key_exists('listtest_five.dat', $listing), "File listtest_five.dat in listing");
|
||||
self::assert(!array_key_exists('listtest_six.dat', $listing), "File listtest_six.dat in listing");
|
||||
|
||||
// I must not see the files not matching the prefix I gave
|
||||
self::assert(!array_key_exists('spam.dat', $listing), "File spam.dat in listing");
|
||||
self::assert(!array_key_exists('ham.dat', $listing), "File ham.dat in listing");
|
||||
|
||||
foreach ($listing as $fileName => $info)
|
||||
{
|
||||
self::assert(isset($info['name']), "File entries must have a name");
|
||||
self::assert(isset($info['time']), "File entries must have a time");
|
||||
self::assert(isset($info['size']), "File entries must have a size");
|
||||
self::assert(isset($info['hash']), "File entries must have a hash");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function testGetContinue(Connector $s3, array $options): bool
|
||||
{
|
||||
$listing = $s3->getBucket($options['bucket'], 'listtest_', null, 1);
|
||||
|
||||
self::assert(is_array($listing), "The files listing must be an array");
|
||||
self::assert(count($listing) == 1, sprintf("I am expecting to see 1 file, %s seen", count($listing)));
|
||||
|
||||
$files = array_keys($listing);
|
||||
$continued = $s3->getBucket($options['bucket'], 'listtest_', array_shift($files));
|
||||
|
||||
self::assert(is_array($continued), "The continued files listing must be an array");
|
||||
self::assert(count($continued) == 2, sprintf("I am expecting to see 2 files, %s seen", count($continued)));
|
||||
|
||||
$listing = array_merge($listing, $continued);
|
||||
|
||||
// Make sure I have the expected files
|
||||
self::assert(array_key_exists('listtest_one.dat', $listing), "File listtest_one.dat not in listing");
|
||||
self::assert(array_key_exists('listtest_two.dat', $listing), "File listtest_two.dat not in listing");
|
||||
self::assert(array_key_exists('listtest_three.dat', $listing), "File listtest_three.dat not in listing");
|
||||
|
||||
// I must not see the files in subdirectories
|
||||
self::assert(!array_key_exists('listtest_four.dat', $listing), "File listtest_four.dat in listing");
|
||||
self::assert(!array_key_exists('listtest_five.dat', $listing), "File listtest_five.dat in listing");
|
||||
self::assert(!array_key_exists('listtest_six.dat', $listing), "File listtest_six.dat in listing");
|
||||
|
||||
// I must not see the files not matching the prefix I gave
|
||||
self::assert(!array_key_exists('spam.dat', $listing), "File spam.dat in listing");
|
||||
self::assert(!array_key_exists('ham.dat', $listing), "File ham.dat in listing");
|
||||
|
||||
foreach ($listing as $fileName => $info)
|
||||
{
|
||||
self::assert(isset($info['name']), "File entries must have a name");
|
||||
self::assert(isset($info['time']), "File entries must have a time");
|
||||
self::assert(isset($info['size']), "File entries must have a size");
|
||||
self::assert(isset($info['hash']), "File entries must have a hash");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function testGetSubdirectoryFiles(Connector $s3, array $options): bool
|
||||
{
|
||||
$listing = $s3->getBucket($options['bucket'], 'list_deeper/test_');
|
||||
|
||||
self::assert(is_array($listing), "The files listing must be an array");
|
||||
self::assert(count($listing) == 3, "I am expecting to see 3 files");
|
||||
|
||||
// Make sure I have the expected files
|
||||
self::assert(array_key_exists('list_deeper/test_one.dat', $listing), "File test_one.dat not in listing");
|
||||
self::assert(array_key_exists('list_deeper/test_two.dat', $listing), "File test_two.dat not in listing");
|
||||
self::assert(array_key_exists('list_deeper/test_three.dat', $listing), "File test_three.dat not in listing");
|
||||
|
||||
// I must not see the files with different prefix
|
||||
self::assert(!array_key_exists('list_deeper/listtest_four.dat', $listing), "File listtest_four.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/listtest_five.dat', $listing), "File listtest_five.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/listtest_six.dat', $listing), "File listtest_six.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/spam.dat', $listing), "File spam.dat in listing");
|
||||
|
||||
// I must not see the files in subdirectories
|
||||
self::assert(!array_key_exists('list_deeper/listtest_deeper/seven.dat', $listing), "File spam.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/listtest_deeper/eight.dat', $listing), "File spam.dat in listing");
|
||||
|
||||
foreach ($listing as $fileName => $info)
|
||||
{
|
||||
self::assert(isset($info['name']), "File entries must have a name");
|
||||
self::assert(isset($info['time']), "File entries must have a time");
|
||||
self::assert(isset($info['size']), "File entries must have a size");
|
||||
self::assert(isset($info['hash']), "File entries must have a hash");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function testGetSubdirectoryFilesWithContinue(Connector $s3, array $options): bool
|
||||
{
|
||||
$listing = $s3->getBucket($options['bucket'], 'list_deeper/test_', null, 1);
|
||||
|
||||
self::assert(is_array($listing), "The files listing must be an array");
|
||||
self::assert(count($listing) == 1, sprintf("I am expecting to see 1 file, %s seen", count($listing)));
|
||||
|
||||
$files = array_keys($listing);
|
||||
$continued = $s3->getBucket($options['bucket'], 'list_deeper/test_', array_shift($files));
|
||||
|
||||
self::assert(is_array($continued), "The continued files listing must be an array");
|
||||
self::assert(count($continued) == 2, sprintf("I am expecting to see 2 files, %s seen", count($continued)));
|
||||
|
||||
$listing = array_merge($listing, $continued);
|
||||
|
||||
self::assert(is_array($listing), "The files listing must be an array");
|
||||
self::assert(count($listing) == 3, "I am expecting to see 3 files");
|
||||
|
||||
// Make sure I have the expected files
|
||||
self::assert(array_key_exists('list_deeper/test_one.dat', $listing), "File test_one.dat not in listing");
|
||||
self::assert(array_key_exists('list_deeper/test_two.dat', $listing), "File test_two.dat not in listing");
|
||||
self::assert(array_key_exists('list_deeper/test_three.dat', $listing), "File test_three.dat not in listing");
|
||||
|
||||
// I must not see the files with different prefix
|
||||
self::assert(!array_key_exists('list_deeper/listtest_four.dat', $listing), "File listtest_four.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/listtest_five.dat', $listing), "File listtest_five.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/listtest_six.dat', $listing), "File listtest_six.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/spam.dat', $listing), "File spam.dat in listing");
|
||||
|
||||
// I must not see the files in subdirectories
|
||||
self::assert(!array_key_exists('list_deeper/listtest_deeper/seven.dat', $listing), "File spam.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/listtest_deeper/eight.dat', $listing), "File spam.dat in listing");
|
||||
|
||||
foreach ($listing as $fileName => $info)
|
||||
{
|
||||
self::assert(isset($info['name']), "File entries must have a name");
|
||||
self::assert(isset($info['time']), "File entries must have a time");
|
||||
self::assert(isset($info['size']), "File entries must have a size");
|
||||
self::assert(isset($info['hash']), "File entries must have a hash");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function testListWithPrefixSharedWithFolder(Connector $s3, array $options): bool
|
||||
{
|
||||
/**
|
||||
* The prefix list_deeper/listtest_ matches BOTH keys (files) and common prefixes (folders).
|
||||
*
|
||||
* Common prefixes have priority so the first request would return zero files. The Connector catches that
|
||||
* internally and performs more requests until it has at least as many files as we requeted.
|
||||
*/
|
||||
$listing = $s3->getBucket($options['bucket'], 'list_deeper/listtest_', null, 1);
|
||||
|
||||
self::assert(is_array($listing), "The files listing must be an array");
|
||||
self::assert(count($listing) == 1, sprintf("I am expecting to see 1 files, %s seen", count($listing)));
|
||||
|
||||
$files = array_keys($listing);
|
||||
$continued = $s3->getBucket($options['bucket'], 'list_deeper/listtest_', array_shift($files));
|
||||
|
||||
self::assert(is_array($continued), "The continued files listing must be an array");
|
||||
self::assert(count($continued) == 2, sprintf("I am expecting to see 2 files, %s seen", count($continued)));
|
||||
|
||||
$listing = array_merge($listing, $continued);
|
||||
|
||||
self::assert(is_array($listing), "The files listing must be an array");
|
||||
self::assert(count($listing) == 3, "I am expecting to see 3 files");
|
||||
|
||||
// Make sure I have the expected files
|
||||
self::assert(array_key_exists('list_deeper/listtest_four.dat', $listing), "File listtest_four.dat not in listing");
|
||||
self::assert(array_key_exists('list_deeper/listtest_five.dat', $listing), "File listtest_five.dat not in listing");
|
||||
self::assert(array_key_exists('list_deeper/listtest_six.dat', $listing), "File listtest_six.dat not in listing");
|
||||
|
||||
|
||||
// I must not see the files with different prefix
|
||||
self::assert(!array_key_exists('list_deeper/test_one.dat', $listing), "File test_one.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/test_two.dat', $listing), "File test_two.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/test_three.dat', $listing), "File test_three.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/spam.dat', $listing), "File spam.dat in listing");
|
||||
|
||||
// I must not see the files in subdirectories
|
||||
self::assert(!array_key_exists('list_deeper/listtest_deeper/seven.dat', $listing), "File spam.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/listtest_deeper/eight.dat', $listing), "File spam.dat in listing");
|
||||
|
||||
foreach ($listing as $fileName => $info)
|
||||
{
|
||||
self::assert(isset($info['name']), "File entries must have a name");
|
||||
self::assert(isset($info['time']), "File entries must have a time");
|
||||
self::assert(isset($info['size']), "File entries must have a size");
|
||||
self::assert(isset($info['hash']), "File entries must have a hash");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function testCommonPrefixes(Connector $s3, array $options): bool
|
||||
{
|
||||
$listing = $s3->getBucket($options['bucket'], 'list_deeper/listtest_', null, null, '/', true);
|
||||
|
||||
self::assert(is_array($listing), "The files listing must be an array");
|
||||
self::assert(count($listing) == 4, sprintf("I am expecting to see 4 entries, %s entries seen.", count($listing)));
|
||||
|
||||
// Make sure I have the expected files
|
||||
self::assert(array_key_exists('list_deeper/listtest_four.dat', $listing), "File listtest_four.dat not in listing");
|
||||
self::assert(array_key_exists('list_deeper/listtest_five.dat', $listing), "File listtest_five.dat not in listing");
|
||||
self::assert(array_key_exists('list_deeper/listtest_six.dat', $listing), "File listtest_six.dat not in listing");
|
||||
self::assert(array_key_exists('list_deeper/listtest_deeper/', $listing), "Folder listtest_deeper not in listing");
|
||||
|
||||
// I must not see the files in subdirectories
|
||||
self::assert(!array_key_exists('list_deeper/listtest_deeper/seven.dat', $listing), "File seven.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/listtest_deeper/eight.dat', $listing), "File eight.dat in listing");
|
||||
|
||||
// I must not see the files with different prefix
|
||||
self::assert(!array_key_exists('list_deeper/spam.dat', $listing), "File spam.dat in listing");
|
||||
self::assert(!array_key_exists('list_deeper/test_one.dat', $listing), "File test_one.dat not in listing");
|
||||
self::assert(!array_key_exists('list_deeper/test_two.dat', $listing), "File test_two.dat not in listing");
|
||||
self::assert(!array_key_exists('list_deeper/test_three.dat', $listing), "File test_three.dat not in listing");
|
||||
|
||||
foreach ($listing as $fileName => $info)
|
||||
{
|
||||
if (substr($fileName, -1) !== '/')
|
||||
{
|
||||
self::assert(isset($info['name']), "File entries must have a name");
|
||||
self::assert(isset($info['time']), "File entries must have a time");
|
||||
self::assert(isset($info['size']), "File entries must have a size");
|
||||
self::assert(isset($info['hash']), "File entries must have a hash");
|
||||
}
|
||||
else
|
||||
{
|
||||
self::assert(isset($info['prefix']), "Folder entries must return a prefix");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
97
s3_storage/vendor/akeeba/s3/minitest/Test/Multipart.php
vendored
Normal file
97
s3_storage/vendor/akeeba/s3/minitest/Test/Multipart.php
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
|
||||
class Multipart extends BigFiles
|
||||
{
|
||||
public static function setup(Connector $s3, array $options): void
|
||||
{
|
||||
self::$multipart = true;
|
||||
|
||||
parent::setup($s3, $options);
|
||||
}
|
||||
|
||||
public static function upload5MBString(Connector $s3, array $options): bool
|
||||
{
|
||||
$result = parent::upload5MBString($s3, $options);
|
||||
|
||||
$expectedChunks = 1;
|
||||
self::assert(self::$numberOfChunks === $expectedChunks, sprintf("Expected %s chunks, upload complete in %s chunks", $expectedChunks, self::$numberOfChunks));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function upload6MBString(Connector $s3, array $options): bool
|
||||
{
|
||||
$result = parent::upload6MBString($s3, $options);
|
||||
|
||||
$expectedChunks = 2;
|
||||
self::assert(self::$numberOfChunks === $expectedChunks, sprintf("Expected %s chunks, upload complete in %s chunks", $expectedChunks, self::$numberOfChunks));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function upload10MBString(Connector $s3, array $options): bool
|
||||
{
|
||||
$result = parent::upload10MBString($s3, $options);
|
||||
|
||||
$expectedChunks = 2;
|
||||
self::assert(self::$numberOfChunks === $expectedChunks, sprintf("Expected %s chunks, upload complete in %s chunks", $expectedChunks, self::$numberOfChunks));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function upload11MBString(Connector $s3, array $options): bool
|
||||
{
|
||||
$result = parent::upload11MBString($s3, $options);
|
||||
|
||||
$expectedChunks = 3;
|
||||
self::assert(self::$numberOfChunks === $expectedChunks, sprintf("Expected %s chunks, upload complete in %s chunks", $expectedChunks, self::$numberOfChunks));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function upload5MBFile(Connector $s3, array $options): bool
|
||||
{
|
||||
$result = parent::upload5MBFile($s3, $options);
|
||||
|
||||
$expectedChunks = 1;
|
||||
self::assert(self::$numberOfChunks === $expectedChunks, sprintf("Expected %s chunks, upload complete in %s chunks", $expectedChunks, self::$numberOfChunks));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function upload6MBFile(Connector $s3, array $options): bool
|
||||
{
|
||||
$result = parent::upload6MBFile($s3, $options);
|
||||
|
||||
$expectedChunks = 2;
|
||||
self::assert(self::$numberOfChunks === $expectedChunks, sprintf("Expected %s chunks, upload complete in %s chunks", $expectedChunks, self::$numberOfChunks));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function upload10MBFile(Connector $s3, array $options): bool
|
||||
{
|
||||
$result = parent::upload10MBFile($s3, $options);
|
||||
|
||||
$expectedChunks = 2;
|
||||
self::assert(self::$numberOfChunks === $expectedChunks, sprintf("Expected %s chunks, upload complete in %s chunks", $expectedChunks, self::$numberOfChunks));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function upload11MBFile(Connector $s3, array $options): bool
|
||||
{
|
||||
$result = parent::upload11MBFile($s3, $options);
|
||||
|
||||
$expectedChunks = 3;
|
||||
self::assert(self::$numberOfChunks === $expectedChunks, sprintf("Expected %s chunks, upload complete in %s chunks", $expectedChunks, self::$numberOfChunks));
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
59
s3_storage/vendor/akeeba/s3/minitest/Test/SignedURLs.php
vendored
Normal file
59
s3_storage/vendor/akeeba/s3/minitest/Test/SignedURLs.php
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Acl;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Input;
|
||||
use RuntimeException;
|
||||
|
||||
class SignedURLs extends AbstractTest
|
||||
{
|
||||
public static function signedURLPublicObject(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::signedURL($s3, $options, Acl::ACL_PUBLIC_READ);
|
||||
}
|
||||
|
||||
public static function signedURLPrivateObject(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::signedURL($s3, $options, Acl::ACL_PRIVATE);
|
||||
}
|
||||
|
||||
private static function signedURL(Connector $s3, array $options, string $aclPrivilege): bool
|
||||
{
|
||||
$tempData = self::getRandomData(AbstractTest::TEN_KB);
|
||||
$input = Input::createFromData($tempData);
|
||||
$uri = 'test.' . md5(microtime(false)) . '.dat';
|
||||
|
||||
$s3->putObject($input, $options['bucket'], $uri, $aclPrivilege);
|
||||
|
||||
$downloadURL = $s3->getAuthenticatedURL($options['bucket'], $uri, null, $options['ssl']);
|
||||
$downloadedData = @file_get_contents($downloadURL);
|
||||
|
||||
try
|
||||
{
|
||||
$s3->deleteObject($options['bucket'], $uri);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
// Ignore deletion errors
|
||||
}
|
||||
|
||||
if ($downloadedData === false)
|
||||
{
|
||||
throw new RuntimeException("Failed to download from signed URL ‘{$downloadURL}′");
|
||||
}
|
||||
|
||||
self::assert(self::areStringsEqual($tempData, $downloadedData), "Wrong data received from signed URL ‘{$downloadURL}′");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
109
s3_storage/vendor/akeeba/s3/minitest/Test/SmallFiles.php
vendored
Normal file
109
s3_storage/vendor/akeeba/s3/minitest/Test/SmallFiles.php
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Input;
|
||||
|
||||
/**
|
||||
* Upload, download and delete small files (under 1MB) using a file source
|
||||
*
|
||||
* @package Akeeba\MiniTest\Test
|
||||
*/
|
||||
class SmallFiles extends AbstractTest
|
||||
{
|
||||
/**
|
||||
* Should I download the file after uploading it to test for contents consistency?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $downloadAfter = true;
|
||||
|
||||
/**
|
||||
* Should I delete the uploaded file after the test case is done?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $deleteRemote = true;
|
||||
|
||||
public static function upload10KbRoot(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, AbstractTest::TEN_KB, 'root_10kb.dat');
|
||||
}
|
||||
|
||||
public static function upload10KbRootGreek(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, AbstractTest::TEN_KB, 'δοκιμή_10kb.dat');
|
||||
}
|
||||
|
||||
public static function upload10KbFolderGreek(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, AbstractTest::TEN_KB, 'ο_φάκελός_μου/δοκιμή_10kb.dat');
|
||||
}
|
||||
|
||||
public static function upload600KbRoot(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, AbstractTest::SIX_HUNDRED_KB, 'root_600kb.dat');
|
||||
}
|
||||
|
||||
public static function upload10KbFolder(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, AbstractTest::TEN_KB, 'my_folder/10kb.dat');
|
||||
}
|
||||
|
||||
public static function upload600KbFolder(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, AbstractTest::SIX_HUNDRED_KB, 'my_folder/600kb.dat');
|
||||
}
|
||||
|
||||
protected static function upload(Connector $s3, array $options, int $size, string $uri): bool
|
||||
{
|
||||
// Randomize the name. Required for archive buckets where you cannot overwrite data.
|
||||
$dotPos = strrpos($uri, '.');
|
||||
$uri = substr($uri, 0, $dotPos) . '.' . md5(microtime(false)) . substr($uri, $dotPos);
|
||||
|
||||
// Create a file with random data
|
||||
$sourceFile = self::createFile($size);
|
||||
|
||||
// Upload the file. Throws exception if it fails.
|
||||
$bucket = $options['bucket'];
|
||||
$input = Input::createFromFile($sourceFile);
|
||||
|
||||
$s3->putObject($input, $bucket, $uri);
|
||||
|
||||
// Tentatively accept that this method succeeded.
|
||||
$result = true;
|
||||
|
||||
// Should I download the file and compare its contents?
|
||||
if (self::$downloadAfter)
|
||||
{
|
||||
// Donwload the data. Throws exception if it fails.
|
||||
$downloadedFile = tempnam(self::getTempFolder(), 'as3');
|
||||
$s3->getObject($bucket, $uri, $downloadedFile);
|
||||
|
||||
// Compare the file contents.
|
||||
$result = self::areFilesEqual($sourceFile, $downloadedFile);
|
||||
}
|
||||
|
||||
// Remove the local files
|
||||
@unlink($sourceFile);
|
||||
@unlink($downloadedFile);
|
||||
|
||||
// Should I delete the remotely stored file?
|
||||
if (self::$deleteRemote)
|
||||
{
|
||||
// Delete the remote file. Throws exception if it fails.
|
||||
$s3->deleteObject($bucket, $uri);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
28
s3_storage/vendor/akeeba/s3/minitest/Test/SmallFilesNoDelete.php
vendored
Normal file
28
s3_storage/vendor/akeeba/s3/minitest/Test/SmallFilesNoDelete.php
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
|
||||
/**
|
||||
* Upload and download small files (under 1MB) using a file source
|
||||
*
|
||||
* @package Akeeba\MiniTest\Test
|
||||
*/
|
||||
class SmallFilesNoDelete extends SmallFiles
|
||||
{
|
||||
public static function setup(Connector $s3, array $options): void
|
||||
{
|
||||
self::$deleteRemote = false;
|
||||
|
||||
parent::setup($s3, $options);
|
||||
}
|
||||
}
|
31
s3_storage/vendor/akeeba/s3/minitest/Test/SmallFilesOnlyUpload.php
vendored
Normal file
31
s3_storage/vendor/akeeba/s3/minitest/Test/SmallFilesOnlyUpload.php
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
|
||||
/**
|
||||
* Upload small files (under 1MB) using a file source
|
||||
*
|
||||
* @package Akeeba\MiniTest\Test
|
||||
*/
|
||||
class SmallFilesOnlyUpload extends SmallFiles
|
||||
{
|
||||
public static function setup(Connector $s3, array $options): void
|
||||
{
|
||||
self::$deleteRemote = false;
|
||||
self::$downloadAfter = false;
|
||||
|
||||
parent::setup($s3, $options);
|
||||
}
|
||||
|
||||
|
||||
}
|
58
s3_storage/vendor/akeeba/s3/minitest/Test/SmallInlineFiles.php
vendored
Normal file
58
s3_storage/vendor/akeeba/s3/minitest/Test/SmallInlineFiles.php
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Input;
|
||||
|
||||
/**
|
||||
* Upload, download and delete small files (under 1MB) using a string source
|
||||
*
|
||||
* @package Akeeba\MiniTest\Test
|
||||
*/
|
||||
class SmallInlineFiles extends SmallFiles
|
||||
{
|
||||
protected static function upload(Connector $s3, array $options, int $size, string $uri): bool
|
||||
{
|
||||
// Randomize the name. Required for archive buckets where you cannot overwrite data.
|
||||
$dotPos = strrpos($uri, '.');
|
||||
$uri = substr($uri, 0, $dotPos) . '.' . md5(microtime(false)) . substr($uri, $dotPos);
|
||||
|
||||
// Create some random data to upload
|
||||
$sourceData = self::getRandomData($size);
|
||||
|
||||
// Upload the data. Throws exception if it fails.
|
||||
$bucket = $options['bucket'];
|
||||
$input = Input::createFromData($sourceData);
|
||||
|
||||
$s3->putObject($input, $bucket, $uri);
|
||||
|
||||
// Tentatively accept that this method succeeded.
|
||||
$result = true;
|
||||
|
||||
// Should I download the file and compare its contents with my random data?
|
||||
if (self::$downloadAfter)
|
||||
{
|
||||
$downloadedData = $s3->getObject($bucket, $uri);
|
||||
|
||||
$result = self::areStringsEqual($sourceData, $downloadedData);
|
||||
}
|
||||
|
||||
// Should I delete the remotely stored file?
|
||||
if (self::$deleteRemote)
|
||||
{
|
||||
// Delete the remote file. Throws exception if it fails.
|
||||
$s3->deleteObject($bucket, $uri);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
28
s3_storage/vendor/akeeba/s3/minitest/Test/SmallInlineFilesNoDelete.php
vendored
Normal file
28
s3_storage/vendor/akeeba/s3/minitest/Test/SmallInlineFilesNoDelete.php
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
|
||||
/**
|
||||
* Upload and download small files (under 1MB) using a string source
|
||||
*
|
||||
* @package Akeeba\MiniTest\Test
|
||||
*/
|
||||
class SmallInlineFilesNoDelete extends SmallInlineFiles
|
||||
{
|
||||
public static function setup(Connector $s3, array $options): void
|
||||
{
|
||||
self:: $deleteRemote = false;
|
||||
|
||||
parent::setup($s3, $options);
|
||||
}
|
||||
}
|
30
s3_storage/vendor/akeeba/s3/minitest/Test/SmallInlineFilesOnlyUpload.php
vendored
Normal file
30
s3_storage/vendor/akeeba/s3/minitest/Test/SmallInlineFilesOnlyUpload.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
|
||||
/**
|
||||
* Upload small files (under 1MB) using a string source
|
||||
*
|
||||
* @package Akeeba\MiniTest\Test
|
||||
*/
|
||||
class SmallInlineFilesOnlyUpload extends SmallInlineFiles
|
||||
{
|
||||
public static function setup(Connector $s3, array $options): void
|
||||
{
|
||||
self::$deleteRemote = false;
|
||||
self::$downloadAfter = false;
|
||||
|
||||
parent::setup($s3, $options);
|
||||
}
|
||||
|
||||
}
|
74
s3_storage/vendor/akeeba/s3/minitest/Test/StorageClasses.php
vendored
Normal file
74
s3_storage/vendor/akeeba/s3/minitest/Test/StorageClasses.php
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
namespace Akeeba\MiniTest\Test;
|
||||
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Acl;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Input;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\StorageClass;
|
||||
|
||||
class StorageClasses extends AbstractTest
|
||||
{
|
||||
protected static $downloadAfter = true;
|
||||
|
||||
protected static $deleteRemote = true;
|
||||
|
||||
public static function uploadRRS(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::TEN_KB, 'rrs_test_10kb.dat', StorageClass::REDUCED_REDUNDANCY);
|
||||
}
|
||||
|
||||
public static function uploadIntelligentTiering(Connector $s3, array $options): bool
|
||||
{
|
||||
return self::upload($s3, $options, self::TEN_KB, 'rrs_test_10kb.dat', StorageClass::INTELLIGENT_TIERING);
|
||||
}
|
||||
|
||||
protected static function upload(Connector $s3, array $options, int $size, string $uri, string $storageClass = null)
|
||||
{
|
||||
// Randomize the name. Required for archive buckets where you cannot overwrite data.
|
||||
$dotPos = strrpos($uri, '.');
|
||||
$uri = substr($uri, 0, $dotPos) . '.' . md5(microtime(false)) . substr($uri, $dotPos);
|
||||
|
||||
// Create some random data to upload
|
||||
$sourceData = self::getRandomData($size);
|
||||
|
||||
// Upload the data. Throws exception if it fails.
|
||||
$bucket = $options['bucket'];
|
||||
$input = Input::createFromData($sourceData);
|
||||
|
||||
// Get the headers
|
||||
$headers = [];
|
||||
StorageClass::setStorageClass($headers, $storageClass);
|
||||
|
||||
$s3->putObject($input, $bucket, $uri, Acl::ACL_PRIVATE, $headers);
|
||||
|
||||
// Tentatively accept that this method succeeded.
|
||||
$result = true;
|
||||
|
||||
// Should I download the file and compare its contents with my random data?
|
||||
if (self::$downloadAfter)
|
||||
{
|
||||
$downloadedData = $s3->getObject($bucket, $uri);
|
||||
|
||||
$result = self::areStringsEqual($sourceData, $downloadedData);
|
||||
}
|
||||
|
||||
// Should I delete the remotely stored file?
|
||||
if (self::$deleteRemote)
|
||||
{
|
||||
// Delete the remote file. Throws exception if it fails.
|
||||
$s3->deleteObject($bucket, $uri);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
169
s3_storage/vendor/akeeba/s3/minitest/config.dist.php
vendored
Normal file
169
s3_storage/vendor/akeeba/s3/minitest/config.dist.php
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
// Default Amazon S3 Access Key
|
||||
define('DEFAULT_ACCESS_KEY', 'your s3 access key');
|
||||
// Default Amazon S3 Secret Key
|
||||
define('DEFAULT_SECRET_KEY', 'your secret key');
|
||||
// Default region for the bucket
|
||||
define('DEFAULT_REGION', 'us-east-1');
|
||||
// Default bucket name
|
||||
define('DEFAULT_BUCKET', 'example');
|
||||
// Default signature method (v4 or v2)
|
||||
define('DEFAULT_SIGNATURE', 'v4');
|
||||
// Use Dualstack unless otherwise specified?
|
||||
define('DEFAULT_DUALSTACK', false);
|
||||
// Use legacy path access by default?
|
||||
define('DEFAULT_PATH_ACCESS', false);
|
||||
// Should I use SSL by default?
|
||||
define('DEFAULT_SSL', true);
|
||||
|
||||
/**
|
||||
* Tests for standard key pairs allowing us to read, write and delete
|
||||
*
|
||||
* This is the main test suite
|
||||
*/
|
||||
$standardTests = [
|
||||
'BucketsList',
|
||||
'BucketLocation',
|
||||
'SmallFiles',
|
||||
'SmallInlineFiles',
|
||||
'SignedURLs',
|
||||
'StorageClasses',
|
||||
'ListFiles',
|
||||
'BigFiles',
|
||||
'Multipart',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests for key pairs or buckets which do NOT allow us to delete, but DO allow us to write and read data
|
||||
*
|
||||
* Example: archival buckets
|
||||
*/
|
||||
$noDeleteTests = [
|
||||
'SmallFilesNoDelete',
|
||||
'SmallInlineFilesNoDelete',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests for key pairs which do NOT allow us to read, but DO allow us to write/delete
|
||||
*
|
||||
* Example: write-only key pairs per my documentation information from 2011 :)
|
||||
*/
|
||||
$writeOnlyTests = [
|
||||
'SmallFilesOnlyUpload',
|
||||
'SmallInlineFilesOnlyUpload',
|
||||
];
|
||||
|
||||
/**
|
||||
* These are the individual test configurations.
|
||||
*
|
||||
* Each configuration consists of two keys:
|
||||
*
|
||||
* * **configuration** Overrides to the default configuration.
|
||||
* * **tests** The names of the test classes to execute. Use the format ['classname', 'method'] to execute
|
||||
* specific test methods only.
|
||||
*/
|
||||
$testConfigurations = [
|
||||
// Format of each
|
||||
// 'Description of this configuration' => array(
|
||||
// 'configuration' => array(
|
||||
// // You can skip one or more keys. The defaults will be used.
|
||||
// 'access' => 'a different access key',
|
||||
// 'secret' => 'a different secret key',
|
||||
// 'region' => 'eu-west-1',
|
||||
// 'bucket' => 'different_example',
|
||||
// 'signature' => 'v2',
|
||||
// 'dualstack' => true,
|
||||
// 'path_access' => true,
|
||||
// 'ssl' => true,
|
||||
// // Only if you want to use a custom, non-Amazon endpoint
|
||||
// 'endpoint' => null,
|
||||
// ),
|
||||
// 'tests' => array(
|
||||
// // Use a start to run all tests
|
||||
// '*',
|
||||
// // Alternatively you can define single test classes:
|
||||
// 'SmallFiles',
|
||||
// // ..or specific tests:
|
||||
// array('SmallFiles', 'upload10KbRoot'),
|
||||
// )
|
||||
// ),
|
||||
/**/
|
||||
|
||||
/**
|
||||
* These are the standard tests we run for each region and key pair.
|
||||
*
|
||||
* For all available regions please consult https://docs.aws.amazon.com/general/latest/gr/s3.html
|
||||
*
|
||||
* It is recommended to run against the following regions:
|
||||
* - eu-east-1 The original Amazon S3 region, it often has special meaning in APIs.
|
||||
* - eu-west-1 Ireland. The original EU region for S3, as a test for the non-default region.
|
||||
* - eu-central-1 Frankfurt. This region –like all newer regions– only allows v4 signatures!
|
||||
* - cn-north-1 Beijing, China. Requires running it from inside China.
|
||||
* - NON-AMAZON A custom endpoint for a third party, S3-compatible API. Ideally one for v2 and one for v4.
|
||||
*
|
||||
* Further to that test the following:
|
||||
* - Write-only, bucket-restricted keys
|
||||
* - Read/write, bucket-restricted keys
|
||||
* - Buckets with dots
|
||||
* - Buckets with uppercase letters
|
||||
* - Buckets with international letters
|
||||
* - Access from within EC2
|
||||
*/
|
||||
'Global key, v4, DNS, single stack' => [
|
||||
'configuration' => [
|
||||
'signature' => 'v4',
|
||||
'dualstack' => false,
|
||||
'path_access' => false,
|
||||
],
|
||||
'tests' => $standardTests,
|
||||
],
|
||||
'Global key, v4, DNS, dual stack' => [
|
||||
'configuration' => [
|
||||
'signature' => 'v4',
|
||||
'dualstack' => true,
|
||||
'path_access' => false,
|
||||
],
|
||||
'tests' => $standardTests,
|
||||
],
|
||||
'Global key, v4, path, single stack' => [
|
||||
'configuration' => [
|
||||
'signature' => 'v4',
|
||||
'dualstack' => false,
|
||||
'path_access' => true,
|
||||
],
|
||||
'tests' => $standardTests,
|
||||
],
|
||||
'Global key, v4, path, dual stack' => [
|
||||
'configuration' => [
|
||||
'signature' => 'v4',
|
||||
'dualstack' => true,
|
||||
'path_access' => true,
|
||||
],
|
||||
'tests' => $standardTests,
|
||||
],
|
||||
|
||||
'Global key, v2, DNS, single stack' => [
|
||||
'configuration' => [
|
||||
'signature' => 'v2',
|
||||
'dualstack' => false,
|
||||
'path_access' => false,
|
||||
],
|
||||
'tests' => $standardTests,
|
||||
],
|
||||
'Global key, v2, DNS, dual stack' => [
|
||||
'configuration' => [
|
||||
'signature' => 'v2',
|
||||
'dualstack' => true,
|
||||
'path_access' => false,
|
||||
],
|
||||
'tests' => $standardTests,
|
||||
],
|
||||
];
|
396
s3_storage/vendor/akeeba/s3/minitest/minitest.php
vendored
Normal file
396
s3_storage/vendor/akeeba/s3/minitest/minitest.php
vendored
Normal file
|
@ -0,0 +1,396 @@
|
|||
<?php
|
||||
/**
|
||||
* Akeeba Engine
|
||||
*
|
||||
* @package akeebaengine
|
||||
* @copyright Copyright (c)2006-2020 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 3, or later
|
||||
*/
|
||||
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Configuration;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
|
||||
use Akeeba\Engine\Postproc\Connector\S3v4\Input;
|
||||
|
||||
// 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;
|
||||
|
||||
// Extract the configuration options
|
||||
if (!isset($setup['configuration']))
|
||||
{
|
||||
$setup['configuration'] = [];
|
||||
}
|
||||
|
||||
$configOptions = array_merge([
|
||||
'access' => DEFAULT_ACCESS_KEY,
|
||||
'secret' => DEFAULT_SECRET_KEY,
|
||||
'region' => DEFAULT_REGION,
|
||||
'bucket' => DEFAULT_BUCKET,
|
||||
'signature' => DEFAULT_SIGNATURE,
|
||||
'dualstack' => DEFAULT_DUALSTACK,
|
||||
'path_access' => DEFAULT_PATH_ACCESS,
|
||||
'ssl' => DEFAULT_SSL,
|
||||
'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->setUseDualstackUrl($configOptions['dualstack']);
|
||||
$s3Configuration->setUseLegacyPathStyle($configOptions['path_access']);
|
||||
$s3Configuration->setSSL($configOptions['ssl']);
|
||||
|
||||
if (!is_null($configOptions['endpoint']))
|
||||
{
|
||||
$s3Configuration->setEndpoint($configOptions['endpoint']);
|
||||
}
|
||||
|
||||
// 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 Teared 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;
|
Loading…
Add table
Add a link
Reference in a new issue