New Library

This commit is contained in:
EoleDev 2016-03-09 15:36:02 +01:00
parent 5c6f6c97b7
commit c479658f0b
83 changed files with 5788 additions and 0 deletions

View file

@ -0,0 +1,20 @@
<?php
namespace OpenCloud\integration;
use Psr\Log\AbstractLogger;
class DefaultLogger extends AbstractLogger
{
public function log($level, $message, array $context = [])
{
echo $this->format($level, $message, $context);
}
private function format($level, $message, $context)
{
$msg = strtr($message, $context);
return sprintf("%s: %s\n", strtoupper($level), $msg);
}
}

View file

@ -0,0 +1,112 @@
<?php
namespace OpenCloud\integration;
class Runner
{
private $basePath;
private $logger;
private $services = [];
public function __construct($basePath)
{
$this->basePath = $basePath;
$this->logger = new DefaultLogger();
$this->assembleServicesFromSamples();
}
private function traverse($path)
{
return new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS);
}
private function assembleServicesFromSamples()
{
foreach ($this->traverse($this->basePath) as $servicePath) {
if ($servicePath->isDir()) {
foreach ($this->traverse($servicePath) as $versionPath) {
$this->services[$servicePath->getBasename()][] = $versionPath->getBasename();
}
}
}
}
private function getOpts()
{
$opts = getopt('s:v:t:', ['service:', 'version:', 'test::', 'debug::', 'help::']);
$getOpt = function (array $keys, $default) use ($opts) {
foreach ($keys as $key) {
if (isset($opts[$key])) {
return $opts[$key];
}
}
return $default;
};
return [
$getOpt(['s', 'service'], 'all'),
$getOpt(['n', 'version'], 'all'),
$getOpt(['t', 'test'], ''),
isset($opts['debug']) ? (int) $opts['debug'] : 0,
];
}
private function getRunnableServices($service, $version)
{
$services = $this->services;
if ($service != 'all') {
if (!isset($this->services[$service])) {
throw new \InvalidArgumentException(sprintf("%s service does not exist", $service));
}
$versions = ($version == 'all') ? $this->services[$service] : [$version];
$services = [$service => $versions];
}
return $services;
}
/**
* @return TestInterface
*/
private function getTest($serviceName, $version, $verbosity)
{
$namespace = (new \ReflectionClass($this))->getNamespaceName();
$className = sprintf("%s\\%s\\%sTest", $namespace, Utils::toCamelCase($serviceName), ucfirst($version));
if (!class_exists($className)) {
throw new \RuntimeException(sprintf("%s does not exist", $className));
}
$basePath = $this->basePath . DIRECTORY_SEPARATOR . $serviceName . DIRECTORY_SEPARATOR . $version;
$smClass = sprintf("%s\\SampleManager", $namespace);
$class = new $className($this->logger, new $smClass($basePath, $verbosity));
if (!($class instanceof TestInterface)) {
throw new \RuntimeException(sprintf("%s does not implement TestInterface", $className));
}
return $class;
}
public function runServices()
{
list($serviceOpt, $versionOpt, $testMethodOpt, $verbosityOpt) = $this->getOpts();
foreach ($this->getRunnableServices($serviceOpt, $versionOpt) as $serviceName => $versions) {
foreach ($versions as $version) {
$testRunner = $this->getTest($serviceName, $version, $verbosityOpt);
if ($testMethodOpt) {
$testRunner->runOneTest($testMethodOpt);
} else {
$testRunner->runTests();
}
$testRunner->teardown();
}
}
}
}

View file

@ -0,0 +1,104 @@
<?php
namespace OpenCloud\integration;
class SampleManager implements SampleManagerInterface
{
protected $basePath;
protected $paths = [];
protected $verbosity;
public function __construct($basePath, $verbosity)
{
$this->basePath = $basePath;
$this->verbosity = $verbosity;
}
public function deletePaths()
{
if (!empty($this->paths)) {
foreach ($this->paths as $path) {
unlink($path);
}
}
}
protected function getGlobalReplacements()
{
return [
'{userId}' => getenv('OS_USER_ID'),
'{username}' => getenv('OS_USERNAME'),
'{password}' => getenv('OS_PASSWORD'),
'{domainId}' => getenv('OS_DOMAIN_ID'),
'{authUrl}' => getenv('OS_AUTH_URL'),
'{tenantId}' => getenv('OS_TENANT_ID'),
'{region}' => getenv('OS_REGION'),
'{projectId}' => getenv('OS_PROJECT_ID'),
'{projectName}' => getenv('OS_PROJECT_NAME'),
];
}
protected function getConnectionTemplate()
{
if ($this->verbosity === 1) {
$subst = <<<'EOL'
use OpenCloud\Integration\DefaultLogger;
use OpenCloud\Integration\Utils;
use GuzzleHttp\MessageFormatter;
$options = [
'debugLog' => true,
'logger' => new DefaultLogger(),
'messageFormatter' => new MessageFormatter(),
];
$openstack = new OpenCloud\OpenCloud(Utils::getAuthOpts($options));
EOL;
} elseif ($this->verbosity === 2) {
$subst = <<<'EOL'
use OpenCloud\Integration\DefaultLogger;
use OpenCloud\Integration\Utils;
use GuzzleHttp\MessageFormatter;
$options = [
'debugLog' => true,
'logger' => new DefaultLogger(),
'messageFormatter' => new MessageFormatter(MessageFormatter::DEBUG),
];
$openstack = new OpenCloud\OpenCloud(Utils::getAuthOpts($options));
EOL;
} else {
$subst = <<<'EOL'
use OpenCloud\Integration\Utils;
$openstack = new OpenCloud\OpenCloud(Utils::getAuthOpts());
EOL;
}
return $subst;
}
public function write($path, array $replacements)
{
$replacements = array_merge($this->getGlobalReplacements(), $replacements);
$sampleFile = rtrim($this->basePath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $path;
if (!file_exists($sampleFile) || !is_readable($sampleFile)) {
throw new \RuntimeException(sprintf("%s either does not exist or is not readable", $sampleFile));
}
$content = strtr(file_get_contents($sampleFile), $replacements);
$content = str_replace("'vendor/'", "'" . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . "vendor'", $content);
$subst = $this->getConnectionTemplate();
$content = preg_replace('/\([^)]+\)/', '', $content, 1);
$content = str_replace('$openstack = new OpenCloud\OpenCloud;', $subst, $content);
$tmp = tempnam(sys_get_temp_dir(), 'openstack');
file_put_contents($tmp, $content);
$this->paths[] = $tmp;
return $tmp;
}
}

View file

@ -0,0 +1,10 @@
<?php
namespace OpenCloud\integration;
interface SampleManagerInterface
{
public function write($path, array $replacements);
public function deletePaths();
}

View file

@ -0,0 +1,115 @@
<?php
namespace OpenCloud\integration;
use Psr\Log\LoggerInterface;
abstract class TestCase extends \PHPUnit_Framework_TestCase implements TestInterface
{
private $logger;
private $startPoint;
private $lastPoint;
private $sampleManager;
public function __construct(LoggerInterface $logger, SampleManagerInterface $sampleManager)
{
$this->logger = $logger;
$this->sampleManager = $sampleManager;
}
public function teardown()
{
$this->sampleManager->deletePaths();
}
public function runOneTest($name)
{
if (!method_exists($this, $name)) {
throw new \InvalidArgumentException(sprintf("%s method does not exist", $name));
}
$this->startTimer();
$this->$name();
$this->outputTimeTaken();
}
protected function startTimer()
{
$this->startPoint = $this->lastPoint = microtime(true);
}
private function wrapColor($message, $colorPrefix)
{
return sprintf("%s%s", $colorPrefix, $message) . "\033[0m\033[1;0m";
}
protected function logStep($message, array $context = [])
{
$duration = microtime(true) - $this->lastPoint;
$stepTimeTaken = sprintf('(%s)', $this->formatSecDifference($duration));
if ($duration >= 10) {
$color = "\033[0m\033[1;31m"; // red
} elseif ($duration >= 2) {
$color = "\033[0m\033[1;33m"; // yellow
} else {
$color = "\033[0m\033[1;32m"; // green
}
$message = '{timeTaken} ' . $message;
$context['{timeTaken}'] = $this->wrapColor($stepTimeTaken, $color);
$this->logger->info($message, $context);
$this->lastPoint = microtime(true);
}
protected function randomStr($length = 5)
{
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charsLen = strlen($chars);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $chars[rand(0, $charsLen - 1)];
}
return 'phptest_' . $randomString;
}
private function formatMinDifference($duration)
{
$output = '';
if (($minutes = floor($duration / 60)) > 0) {
$output .= $minutes . 'min' . (($minutes > 1) ? 's' : '');
}
if (($seconds = number_format(fmod($duration, 60), 2)) > 0) {
if ($minutes > 0) {
$output .= ' ';
}
$output .= $seconds . 's';
}
return $output;
}
private function formatSecDifference($duration)
{
return number_format($duration, 2) . 's';
}
protected function outputTimeTaken()
{
$output = $this->formatMinDifference(microtime(true) - $this->startPoint);
$this->logger->info('Finished all tests! Time taken: {output}.', ['{output}' => $output]);
}
protected function sampleFile(array $replacements, $path)
{
return $this->sampleManager->write($path, $replacements);
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace OpenCloud\integration;
use Psr\Log\LoggerInterface;
interface TestInterface
{
public function __construct(LoggerInterface $logger, SampleManagerInterface $sampleManager);
public function runTests();
public function runOneTest($name);
public function teardown();
}

View file

@ -0,0 +1,59 @@
<?php
namespace OpenCloud\integration;
use GuzzleHttp\Client;
use OpenCloud\Identity\v2\Api;
use OpenCloud\Identity\v2\Service;
use OpenCloud\Common\Transport\HandlerStack;
use OpenCloud\Common\Transport\Utils as CommonUtils;
class Utils
{
public static function getAuthOptsV3()
{
return [
'authUrl' => getenv('OS_AUTH_URL'),
'region' => getenv('OS_REGION_NAME'),
'user' => [
'id' => getenv('OS_USER_ID'),
'password' => getenv('OS_PASSWORD'),
],
'scope' => [
'project' => [
'id' => getenv('OS_PROJECT_ID'),
]
]
];
}
public static function getAuthOptsV2()
{
$httpClient = new Client([
'base_uri' => CommonUtils::normalizeUrl(getenv('OS_AUTH_URL')),
'handler' => HandlerStack::create(),
]);
return [
'authUrl' => getenv('OS_AUTH_URL'),
'region' => getenv('OS_REGION_NAME'),
'username' => getenv('OS_USERNAME'),
'password' => getenv('OS_PASSWORD'),
'tenantName' => getenv('OS_TENANT_NAME'),
'identityService' => new Service($httpClient, new Api),
];
}
public static function getAuthOpts(array $options = [])
{
$authOptions = getenv('OS_IDENTITY_API_VERSION') == '2.0'
? self::getAuthOptsV2()
: self::getAuthOptsV3();
return array_merge($authOptions, $options);
}
public static function toCamelCase($word, $separator = '_')
{
return str_replace($separator, '', ucwords($word, $separator));
}
}

View file

@ -0,0 +1,10 @@
<?php
$rootDir = dirname(dirname(__DIR__));
require_once $rootDir . '/vendor/autoload.php';
$basePath = $rootDir . '/samples';
$runner = new \OpenCloud\Integration\Runner($basePath);
$runner->runServices();

View file

@ -0,0 +1,3 @@
#!/bin/bash
php tests/integration/Runner.php -s compute -v v2

View file

@ -0,0 +1,3 @@
#!/bin/bash
php tests/integration/Runner.php -s identity -v v3

View file

@ -0,0 +1,3 @@
#!/bin/bash
php tests/integration/Runner.php -s networking -v v2

View file

@ -0,0 +1,3 @@
#!/bin/bash
php tests/integration/Runner.php -s objectstore -v v2