Partially implements blueprint psr-2

Change-Id: Ifd8b7237f650f0f18fa58ab0e870eb2774c776fc
This commit is contained in:
Sam Choi 2014-04-16 22:58:32 -07:00
parent 948eb89ba8
commit e5c695f72a
44 changed files with 8957 additions and 8700 deletions

View File

@ -1,7 +1,6 @@
<?php
require_once __DIR__ . '/../src/OpenStack/Autoloader.php';
use \OpenStack\Bootstrap;
use \OpenStack\Autoloader;
use \OpenStack\Services\IdentityService;
use \OpenStack\Storage\ObjectStorage;
@ -38,6 +37,3 @@ printf("Name: %s \n", $object->name());
printf("Size: %d \n", $object->contentLength());
printf("Type: %s \n", $object->contentType());
print $object->content() . PHP_EOL;

View File

@ -8,10 +8,10 @@ Bootstrap::useStreamWrappers();
$ini = parse_ini_file(getenv('HOME') . '/.OpenStack.ini');
$settings = array(
'account' => $ini['account'],
'key' => $ini['secret'],
'tenantid' => $ini['tenantId'],
'endpoint' => $ini['url'],
'account' => $ini['account'],
'key' => $ini['secret'],
'tenantid' => $ini['tenantId'],
'endpoint' => $ini['url'],
);
Bootstrap::setConfiguration($settings);
@ -22,7 +22,7 @@ fclose($newfile);
// Check for an object:
if (file_exists('swift://Example/my_file.txt')) {
print "Found my_file.txt." . PHP_EOL;
print "Found my_file.txt." . PHP_EOL;
}
// Get an entire object at once:
@ -30,13 +30,12 @@ $file = file_get_contents('swift://Example/my_file.txt');
print 'File: ' . $file . PHP_EOL;
$cxt = stream_context_create(array(
'swift' => array(
'account' => $ini['account'],
'key' => $ini['secret'],
'tenantid' => $ini['tenantId'],
'endpoint' => $ini['url'],
),
'swift' => array(
'account' => $ini['account'],
'key' => $ini['secret'],
'tenantid' => $ini['tenantId'],
'endpoint' => $ini['url'],
),
));
print file_get_contents('swift://Example/my_file.txt', FALSE, $cxt);

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* An Autoloader to use for the case Composer isn't available.
@ -44,74 +44,77 @@ namespace OpenStack;
*/
Class Autoloader {
/**
* @var string The directory where OpenStack is located.
*/
public static $basedir = __DIR__;
/**
* @var string The directory where OpenStack is located.
*/
public static $basedir = __DIR__;
/**
* Add the autoloader to PHP's autoloader list.
*
* This will add the internal special-purpose
* autoloader to the list of autoloaders that PHP will
* leverage to resolve class paths.
*
* Because OpenStack is PSR-4 compliant, any
* full PSR-4 classloader should be capable of loading
* these classes witout issue. You may prefer to use
* a standard PSR-4 loader instead of this one.
*
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4.md
*/
public static function useAutoloader() {
spl_autoload_register(__NAMESPACE__ . '\Autoloader::autoload');
}
/**
* OpenStack autoloader.
*
* An implementation of a PHP autoload function. Use
* OpenStack::useAutoloader() if you want PHP to automatically
* load classes using this autoloader.
*
* // Enable the autoloader.
* Autoloader::useAutoloader();
*
* This is a special-purpose autoloader for loading
* only the OpenStack classes. It will not attempt to
* autoload anything outside of the OpenStack namespace.
*
* Because this is a special-purpose autoloader, it
* should be safe to use with other special-purpose
* autoloaders (and also projects that don't
* rely upon autoloaders).
*
* @param string $klass The fully qualified name of the class to be autoloaded.
*/
public static function autoload($klass) {
$components = explode('\\', $klass);
if (empty($components[0])) {
array_shift($components);
/**
* Add the autoloader to PHP's autoloader list.
*
* This will add the internal special-purpose
* autoloader to the list of autoloaders that PHP will
* leverage to resolve class paths.
*
* Because OpenStack is PSR-4 compliant, any
* full PSR-4 classloader should be capable of loading
* these classes witout issue. You may prefer to use
* a standard PSR-4 loader instead of this one.
*
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4.md
*/
public static function useAutoloader()
{
spl_autoload_register(__NAMESPACE__ . '\Autoloader::autoload');
}
// This class loader ONLY loads
// our classes. A general purpose
// classloader should be used for
// more sophisticated needs.
if ($components[0] != 'OpenStack') {
return;
/**
* OpenStack autoloader.
*
* An implementation of a PHP autoload function. Use
* OpenStack::useAutoloader() if you want PHP to automatically
* load classes using this autoloader.
*
* // Enable the autoloader.
* Autoloader::useAutoloader();
*
* This is a special-purpose autoloader for loading
* only the OpenStack classes. It will not attempt to
* autoload anything outside of the OpenStack namespace.
*
* Because this is a special-purpose autoloader, it
* should be safe to use with other special-purpose
* autoloaders (and also projects that don't
* rely upon autoloaders).
*
* @param string $klass The fully qualified name of the class to be autoloaded.
*/
public static function autoload($klass)
{
$components = explode('\\', $klass);
if (empty($components[0])) {
array_shift($components);
}
// This class loader ONLY loads
// our classes. A general purpose
// classloader should be used for
// more sophisticated needs.
if ($components[0] != 'OpenStack') {
return;
}
// We need the path up to, but not including, the root OpenStack dir:
$loc = DIRECTORY_SEPARATOR . 'OpenStack';
$local_path = substr(self::$basedir, 0, strrpos(self::$basedir, $loc));
array_unshift($components, $local_path);
$path = implode(DIRECTORY_SEPARATOR, $components) . '.php';
if (file_exists($path)) {
require $path;
return;
}
}
// We need the path up to, but not including, the root OpenStack dir:
$loc = DIRECTORY_SEPARATOR . 'OpenStack';
$local_path = substr(self::$basedir, 0, strrpos(self::$basedir, $loc));
array_unshift($components, $local_path);
$path = implode(DIRECTORY_SEPARATOR, $components) . '.php';
if (file_exists($path)) {
require $path;
return;
}
}
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* OpenStack SDK for PHP configuration.
@ -23,7 +23,6 @@
namespace OpenStack;
use OpenStack\Services\IdentityService;
use OpenStack\Exception;
/**
* Bootstrapping services.
@ -80,204 +79,207 @@ use OpenStack\Exception;
*
* It's awesome. Trust me.
*/
class Bootstrap {
public static $config = array(
// The transport implementation. By default, we use the Guzzle Client
'transport' => '\OpenStack\Transport\GuzzleClient',
);
/**
* @var \OpenStack\Services\IdentityService An identity services object
* created from the global settings.
*/
public static $identity = NULL;
/**
* @var \OpenStack\Transport\ClientInterface A transport client for requests.
*/
public static $transport = NULL;
/**
* Register stream wrappers for OpenStack.
*
* This registers the ObjectStorage stream wrappers, which allow you to access
* ObjectStorage through standard file access mechanisms.
*
* // Enable stream wrapper.
* Bootstrap::useStreamWrappers();
*
* // Create a context resource.
* $cxt = stream_context_create(array(
* 'tenantid' => '12de21',
* 'username' => 'foobar',
* 'password' => 'f78saf7hhlll',
* 'endpoint' => 'https://identity.hpcloud.com' // <-- not real URL!
* ));
*
* // Get the contents of a Swift object.
* $content = file_get_contents('swift://public/notes.txt', 'r', FALSE, $cxt);
*/
public static function useStreamWrappers() {
$swift = stream_wrapper_register(
\OpenStack\Storage\ObjectStorage\StreamWrapper::DEFAULT_SCHEME,
'\OpenStack\Storage\ObjectStorage\StreamWrapper'
class Bootstrap
{
public static $config = array(
// The transport implementation. By default, we use the Guzzle Client
'transport' => '\OpenStack\Transport\GuzzleClient',
);
$swiftfs = stream_wrapper_register(
\OpenStack\Storage\ObjectStorage\StreamWrapperFS::DEFAULT_SCHEME,
'\OpenStack\Storage\ObjectStorage\StreamWrapperFS'
);
/**
* @var \OpenStack\Services\IdentityService An identity services object
* created from the global settings.
*/
public static $identity = NULL;
return ($swift && $swiftfs);
}
/**
* @var \OpenStack\Transport\ClientInterface A transport client for requests.
*/
public static $transport = NULL;
/**
* Set configuration directives for OpenStack.
*
* This merges the provided associative array into the existing
* configuration parameters (Bootstrap::$config).
*
* All of the OpenStack classes share the same configuration. This
* ensures that a stable runtime environment is maintained.
*
* Common configuration directives:
*
* - 'transport': The namespaced classname for the transport that
* should be used. Example: @code \OpenStack\Transport\CURLTransport @endcode
* - 'transport.debug': The integer 1 for enabling debug, 0 for
* disabling. Enabling will turn on verbose debugging output
* for any transport that supports it.
* - 'transport.timeout': An integer value indicating how long
* the transport layer should wait for an HTTP request. A
* transport MAY ignore this parameter, but the ones included
* with the library honor it.
* - 'transport.ssl_verify': Set this to FALSE to turn off SSL certificate
* verification. This is NOT recommended, but is sometimes necessary for
* certain proxy configurations.
* - 'transport.proxy': Set the proxy as a string.
* - 'username' and 'password'
* - 'tenantid'
* - 'endpoint': The full URL to identity services. This is used by stream
* wrappers.
*
* @param array $array An associative array of configuration directives.
*/
public static function setConfiguration($array) {
self::$config = $array + self::$config;
}
/**
* Register stream wrappers for OpenStack.
*
* This registers the ObjectStorage stream wrappers, which allow you to access
* ObjectStorage through standard file access mechanisms.
*
* // Enable stream wrapper.
* Bootstrap::useStreamWrappers();
*
* // Create a context resource.
* $cxt = stream_context_create(array(
* 'tenantid' => '12de21',
* 'username' => 'foobar',
* 'password' => 'f78saf7hhlll',
* 'endpoint' => 'https://identity.hpcloud.com' // <-- not real URL!
* ));
*
* // Get the contents of a Swift object.
* $content = file_get_contents('swift://public/notes.txt', 'r', FALSE, $cxt);
*/
public static function useStreamWrappers()
{
$swift = stream_wrapper_register(
\OpenStack\Storage\ObjectStorage\StreamWrapper::DEFAULT_SCHEME,
'\OpenStack\Storage\ObjectStorage\StreamWrapper'
);
/**
* Get a configuration option.
*
* Get a configuration option by name, with an optional default.
*
* @param string $name The name of the configuration option to get.
* @param mixed $default The default value to return if the name is not found.
*
* @return mixed The value, if found; or the default, if set; or NULL.
*/
public static function config($name = NULL, $default = NULL) {
$swiftfs = stream_wrapper_register(
\OpenStack\Storage\ObjectStorage\StreamWrapperFS::DEFAULT_SCHEME,
'\OpenStack\Storage\ObjectStorage\StreamWrapperFS'
);
// If no name is specified, return the entire config array.
if (empty($name)) {
return self::$config;
return ($swift && $swiftfs);
}
// If the config value exists, return that.
if (isset(self::$config[$name])) {
return self::$config[$name];
/**
* Set configuration directives for OpenStack.
*
* This merges the provided associative array into the existing
* configuration parameters (Bootstrap::$config).
*
* All of the OpenStack classes share the same configuration. This
* ensures that a stable runtime environment is maintained.
*
* Common configuration directives:
*
* - 'transport': The namespaced classname for the transport that
* should be used. Example: @code \OpenStack\Transport\CURLTransport @endcode
* - 'transport.debug': The integer 1 for enabling debug, 0 for
* disabling. Enabling will turn on verbose debugging output
* for any transport that supports it.
* - 'transport.timeout': An integer value indicating how long
* the transport layer should wait for an HTTP request. A
* transport MAY ignore this parameter, but the ones included
* with the library honor it.
* - 'transport.ssl_verify': Set this to FALSE to turn off SSL certificate
* verification. This is NOT recommended, but is sometimes necessary for
* certain proxy configurations.
* - 'transport.proxy': Set the proxy as a string.
* - 'username' and 'password'
* - 'tenantid'
* - 'endpoint': The full URL to identity services. This is used by stream
* wrappers.
*
* @param array $array An associative array of configuration directives.
*/
public static function setConfiguration($array)
{
self::$config = $array + self::$config;
}
// Otherwise, just return the default value.
return $default;
}
/**
* Get a configuration option.
*
* Get a configuration option by name, with an optional default.
*
* @param string $name The name of the configuration option to get.
* @param mixed $default The default value to return if the name is not found.
*
* @return mixed The value, if found; or the default, if set; or NULL.
*/
public static function config($name = NULL, $default = NULL)
{
// If no name is specified, return the entire config array.
if (empty($name)) {
return self::$config;
}
/**
* Check whether the given configuration option is set.
*
* if (Bootstrap::hasConfig('transport')) {
* syslog(LOG_INFO, 'An alternate transport is supplied.');
* }
*
* @param string $name The name of the item to check for.
*
* @return boolean TRUE if the named option is set, FALSE otherwise. Note that
* the value may be falsey (FALSE, 0, etc.), but if the value is NULL, this
* will return false.
*/
public static function hasConfig($name) {
return isset(self::$config[$name]);
}
// If the config value exists, return that.
if (isset(self::$config[$name])) {
return self::$config[$name];
}
/**
* Get a \OpenStack\Services\IdentityService object from the bootstrap config.
*
* A factory helper function that uses the bootstrap configuration to create
* a ready to use \OpenStack\Services\IdentityService object.
*
* @param bool $force Whether to force the generation of a new object even if
* one is already cached.
*
* @return \OpenStack\Services\IdentityService An authenticated ready to use
* \OpenStack\Services\IdentityService object.
* @throws \OpenStack\Exception When the needed configuration to authenticate
* is not available.
*/
public static function identity($force = FALSE) {
$transport = self::transport();
// If we already have an identity make sure the token is not expired.
if ($force || is_null(self::$identity) || self::$identity->isExpired()) {
// Make sure we have an endpoint to use
if (!self::hasConfig('endpoint')) {
throw new Exception('Unable to authenticate. No endpoint supplied.');
}
// User cannot be an empty string, so we need
// to do more checking than self::hasConfig(), which returns TRUE
// if an item exists and is an empty string.
$user = self::config('username', NULL);
// Check if we have a username/password
if (!empty($user) && self::hasConfig('password')) {
$is = new IdentityService(self::config('endpoint'), $transport);
$is->authenticateAsUser($user, self::config('password'), self::config('tenantid', NULL), self::config('tenantname', NULL));
self::$identity = $is;
}
else {
throw new Exception('Unable to authenticate. No user credentials supplied.');
}
// Otherwise, just return the default value.
return $default;
}
return self::$identity;
}
/**
* Get a transport client.
*
* @param boolean $reset Whether to recreate the transport client if one already exists.
* @return \OpenStack\Transport\ClientInterface A transport client.
*/
public static function transport($reset = FALSE) {
if (is_null(self::$transport) || $reset == TRUE) {
$options = [
'ssl_verify' => self::config('ssl_verify', TRUE),
'timeout' => self::config('timeout', 0), // 0 is no timeout.
'debug' => self::config('debug', 0),
];
$proxy = self::config('proxy', FALSE);
if ($proxy) {
$options['proxy'] = $proxy;
}
$klass = self::config('transport');
self::$transport = new $klass($options);
/**
* Check whether the given configuration option is set.
*
* if (Bootstrap::hasConfig('transport')) {
* syslog(LOG_INFO, 'An alternate transport is supplied.');
* }
*
* @param string $name The name of the item to check for.
*
* @return boolean TRUE if the named option is set, FALSE otherwise. Note that
* the value may be falsey (FALSE, 0, etc.), but if the value is NULL, this
* will return false.
*/
public static function hasConfig($name)
{
return isset(self::$config[$name]);
}
return self::$transport;
}
/**
* Get a \OpenStack\Services\IdentityService object from the bootstrap config.
*
* A factory helper function that uses the bootstrap configuration to create
* a ready to use \OpenStack\Services\IdentityService object.
*
* @param bool $force Whether to force the generation of a new object even if
* one is already cached.
*
* @return \OpenStack\Services\IdentityService An authenticated ready to use
* \OpenStack\Services\IdentityService object.
* @throws \OpenStack\Exception When the needed configuration to authenticate
* is not available.
*/
public static function identity($force = FALSE)
{
$transport = self::transport();
// If we already have an identity make sure the token is not expired.
if ($force || is_null(self::$identity) || self::$identity->isExpired()) {
// Make sure we have an endpoint to use
if (!self::hasConfig('endpoint')) {
throw new Exception('Unable to authenticate. No endpoint supplied.');
}
// User cannot be an empty string, so we need
// to do more checking than self::hasConfig(), which returns TRUE
// if an item exists and is an empty string.
$user = self::config('username', NULL);
// Check if we have a username/password
if (!empty($user) && self::hasConfig('password')) {
$is = new IdentityService(self::config('endpoint'), $transport);
$is->authenticateAsUser($user, self::config('password'), self::config('tenantid', NULL), self::config('tenantname', NULL));
self::$identity = $is;
} else {
throw new Exception('Unable to authenticate. No user credentials supplied.');
}
}
return self::$identity;
}
/**
* Get a transport client.
*
* @param boolean $reset Whether to recreate the transport client if one already exists.
*
* @return \OpenStack\Transport\ClientInterface A transport client.
*/
public static function transport($reset = FALSE)
{
if (is_null(self::$transport) || $reset == TRUE) {
$options = [
'ssl_verify' => self::config('ssl_verify', TRUE),
'timeout' => self::config('timeout', 0), // 0 is no timeout.
'debug' => self::config('debug', 0),
];
$proxy = self::config('proxy', FALSE);
if ($proxy) {
$options['proxy'] = $proxy;
}
$klass = self::config('transport');
self::$transport = new $klass($options);
}
return self::$transport;
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* The parent exception class for OpenStack.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Contains the class for manipulating ObjectStorage ACL strings.
@ -98,459 +98,471 @@ namespace OpenStack\Storage\ObjectStorage;
* For a detailed description of the rules for ACL creation,
* @see http://swift.openstack.org/misc.html#acls
*/
class ACL {
class ACL
{
/**
* Read flag.
*
* This is for an ACL of the READ type.
*/
const READ = 1;
/**
* Write flag.
*
* This is for an ACL of the WRITE type.
*/
const WRITE = 2;
/**
* Flag for READ and WRITE.
*
* This is equivalent to `ACL::READ | ACL::WRITE`
*/
const READ_WRITE = 3; // self::READ | self::WRITE;
/**
* Read flag.
*
* This is for an ACL of the READ type.
*/
const READ = 1;
/**
* Write flag.
*
* This is for an ACL of the WRITE type.
*/
const WRITE = 2;
/**
* Flag for READ and WRITE.
*
* This is equivalent to `ACL::READ | ACL::WRITE`
*/
const READ_WRITE = 3; // self::READ | self::WRITE;
/**
* Header string for a read flag.
*/
const HEADER_READ = 'X-Container-Read';
/**
* Header string for a write flag.
*/
const HEADER_WRITE = 'X-Container-Write';
/**
* Header string for a read flag.
*/
const HEADER_READ = 'X-Container-Read';
/**
* Header string for a write flag.
*/
const HEADER_WRITE = 'X-Container-Write';
protected $rules = array();
protected $rules = array();
/**
* Allow READ access to the public.
*
* This grants the following:
*
* - READ to any host, with container listings.
*
* @return \OpenStack\Storage\ObjectStorage\ACL an ACL object with the
* appopriate permissions set.
*/
public static function makePublic()
{
$acl = new ACL();
$acl->addReferrer(self::READ, '*');
$acl->allowListings();
/**
* Allow READ access to the public.
*
* This grants the following:
*
* - READ to any host, with container listings.
*
* @return \OpenStack\Storage\ObjectStorage\ACL an ACL object with the
* appopriate permissions set.
*/
public static function makePublic() {
$acl = new ACL();
$acl->addReferrer(self::READ, '*');
$acl->allowListings();
return $acl;
}
return $acl;
}
/**
* Disallow all public access.
*
* Non-public is the same as private. Private, however, is a reserved
* word in PHP.
*
* This does not grant any permissions. OpenStack interprets an object
* with no permissions as a private object.
*
* @return \OpenStack\Storage\ObjectStorage\ACL an ACL object with the
* appopriate permissions set.
*/
public static function makeNonPublic()
{
// Default ACL is private.
return new ACL();
}
/**
* Disallow all public access.
*
* Non-public is the same as private. Private, however, is a reserved
* word in PHP.
*
* This does not grant any permissions. OpenStack interprets an object
* with no permissions as a private object.
*
* @return \OpenStack\Storage\ObjectStorage\ACL an ACL object with the
* appopriate permissions set.
*/
public static function makeNonPublic() {
// Default ACL is private.
return new ACL();
}
/**
* Alias of ACL::makeNonPublic().
*/
public static function makePrivate()
{
return self::makeNonPublic();
}
/**
* Alias of ACL::makeNonPublic().
*/
public static function makePrivate() {
return self::makeNonPublic();
}
/**
* Given a list of headers, get the ACL info.
*
* This is a utility for processing headers and discovering any ACLs embedded
* inside the headers.
*
* @param array $headers An associative array of headers.
*
* @return \OpenStack\Storage\ObjectStorage\ACL A new ACL.
*/
public static function newFromHeaders($headers)
{
$acl = new ACL();
/**
* Given a list of headers, get the ACL info.
*
* This is a utility for processing headers and discovering any ACLs embedded
* inside the headers.
*
* @param array $headers An associative array of headers.
*
* @return \OpenStack\Storage\ObjectStorage\ACL A new ACL.
*/
public static function newFromHeaders($headers) {
$acl = new ACL();
// READ rules.
$rules = array();
if (!empty($headers[self::HEADER_READ])) {
$read = $headers[self::HEADER_READ];
$rules = explode(',', $read);
foreach ($rules as $rule) {
$ruleArray = self::parseRule(self::READ, $rule);
if (!empty($ruleArray)) {
$acl->rules[] = $ruleArray;
// READ rules.
$rules = array();
if (!empty($headers[self::HEADER_READ])) {
$read = $headers[self::HEADER_READ];
$rules = explode(',', $read);
foreach ($rules as $rule) {
$ruleArray = self::parseRule(self::READ, $rule);
if (!empty($ruleArray)) {
$acl->rules[] = $ruleArray;
}
}
}
}
}
// WRITE rules.
$rules = array();
if (!empty($headers[self::HEADER_WRITE])) {
$write = $headers[self::HEADER_WRITE];
$rules = explode(',', $write);
foreach ($rules as $rule) {
$ruleArray = self::parseRule(self::WRITE, $rule);
if (!empty($ruleArray)) {
$acl->rules[] = $ruleArray;
// WRITE rules.
$rules = array();
if (!empty($headers[self::HEADER_WRITE])) {
$write = $headers[self::HEADER_WRITE];
$rules = explode(',', $write);
foreach ($rules as $rule) {
$ruleArray = self::parseRule(self::WRITE, $rule);
if (!empty($ruleArray)) {
$acl->rules[] = $ruleArray;
}
}
}
}
//throw new \Exception(print_r($acl->rules(), TRUE));
return $acl;
}
//throw new \Exception(print_r($acl->rules(), TRUE));
/**
* Parse a rule.
*
* This attempts to parse an ACL rule. It is not particularly
* fault-tolerant.
*
* @param int $perm The permission (ACL::READ, ACL::WRITE).
* @param string $rule The string rule to parse.
*
* @return array The rule as an array.
*/
public static function parseRule($perm, $rule)
{
// This regular expression generates the following:
//
// array(
// 0 => ENTIRE RULE
// 1 => WHOLE EXPRESSION, no whitespace
// 2 => domain compontent
// 3 => 'rlistings', set if .rincludes is the directive
// 4 => account name
// 5 => :username
// 6 => username
// );
$exp = '/^\s*(.r:([a-zA-Z0-9\*\-\.]+)|\.(rlistings)|([a-zA-Z0-9]+)(\:([a-zA-Z0-9]+))?)\s*$/';
return $acl;
}
$matches = array();
preg_match($exp, $rule, $matches);
/**
* Parse a rule.
*
* This attempts to parse an ACL rule. It is not particularly
* fault-tolerant.
*
* @param int $perm The permission (ACL::READ, ACL::WRITE).
* @param string $rule The string rule to parse.
*
* @return array The rule as an array.
*/
public static function parseRule($perm, $rule) {
// This regular expression generates the following:
//
// array(
// 0 => ENTIRE RULE
// 1 => WHOLE EXPRESSION, no whitespace
// 2 => domain compontent
// 3 => 'rlistings', set if .rincludes is the directive
// 4 => account name
// 5 => :username
// 6 => username
// );
$exp = '/^\s*(.r:([a-zA-Z0-9\*\-\.]+)|\.(rlistings)|([a-zA-Z0-9]+)(\:([a-zA-Z0-9]+))?)\s*$/';
$matches = array();
preg_match($exp, $rule, $matches);
$entry = array('mask' => $perm);
if (!empty($matches[2])) {
$entry['host'] = $matches[2];
}
elseif (!empty($matches[3])) {
$entry['rlistings'] = TRUE;
}
elseif (!empty($matches[4])) {
$entry['account'] = $matches[4];
if (!empty($matches[6])) {
$entry['user'] = $matches[6];
}
}
return $entry;
}
/**
* Create a new ACL.
*
* This creates an empty ACL with no permissions granted. When no
* permissions are granted, the file is effectively private
* (nonPublic()).
*
* Use add* methods to add permissions.
*/
public function __construct() {}
/**
* Grant ACL access to an account.
*
* Optionally, a user may be given to further limit access.
*
* This is used to restrict access to a particular account and, if so
* specified, a specific user on that account.
*
* If just an account is given, any user on that account will be
* automatically granted access.
*
* If an account and a user is given, only that user of the account is
* granted access.
*
* If $user is an array, every user in the array will be granted
* access under the provided account. That is, for each user in the
* array, an entry of the form `account:user` will be generated in the
* final ACL.
*
* At this time there does not seem to be a way to grant global write
* access to an object.
*
* @param int $perm ACL::READ, ACL::WRITE or ACL::READ_WRITE (which is the
* same as ACL::READ|ACL::WRITE).
* @param string $account The name of the account.
* @param mixed $user The name of the user, or optionally an indexed array of
* user names.
*
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
* the method can be used in chaining.
*/
public function addAccount($perm, $account, $user = NULL) {
$rule = array('account' => $account);
if (!empty($user)) {
$rule['user'] = $user;
}
$this->addRule($perm, $rule);
return $this;
}
/**
* Allow (or deny) a hostname or host pattern.
*
* In current Swift implementations, only READ rules can have host
* patterns. WRITE permissions cannot be granted to hostnames.
*
* Formats:
* - Allow any host: '*'
* - Allow exact host: 'www.example.com'
* - Allow hosts in domain: '.example.com'
* - Disallow exact host: '-www.example.com'
* - Disallow hosts in domain: '-.example.com'
*
* Note that a simple minus sign ('-') is illegal, though it seems it
* should be "disallow all hosts."
*
* @param string $perm The permission being granted. One of ACL:READ,
* ACL::WRITE, or ACL::READ_WRITE.
* @param string $host A host specification string as described above.
*
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
* the method can be used in chaining.
*/
public function addReferrer($perm, $host = '*') {
$this->addRule($perm, array('host' => $host));
return $this;
}
/**
* Add a rule to the appropriate stack of rules.
*
* @param int $perm One of the predefined permission constants.
* @param array $rule A rule array.
*
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
* the method can be used in chaining.
*/
protected function addRule($perm, $rule) {
$rule['mask'] = $perm;
$this->rules[] = $rule;
return $this;
}
/**
* Allow hosts with READ permissions to list a container's content.
*
* By default, granting READ permission on a container does not grant
* permission to list the contents of a container. Setting the
* ACL::allowListings() permission will allow matching hosts to also list
* the contents of a container.
*
* In the current Swift implementation, there is no mechanism for
* allowing some hosts to get listings, while denying others.
*
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
* the method can be used in chaining.
*/
public function allowListings() {
$this->rules[] = array(
'mask' => self::READ,
'rlistings' => TRUE,
);
return $this;
}
/**
* Get the rules array for this ACL.
*
* @return array An array of associative arrays of rules.
*/
public function rules() {
return $this->rules;
}
/**
* Generate HTTP headers for this ACL.
*
* If this is called on an empty object, an empty set of headers is
* returned.
*
* @return array Array of headers
*/
public function headers() {
$headers = array();
$readers = array();
$writers = array();
// Create the rule strings. We need two copies, one for READ and
// one for WRITE.
foreach ($this->rules as $rule) {
// We generate read and write rules separately so that the
// generation logic has a chance to respond to the differences
// allowances for READ and WRITE ACLs.
if (self::READ & $rule['mask']) {
$ruleStr = $this->ruleToString(self::READ, $rule);
if (!empty($ruleStr)) {
$readers[] = $ruleStr;
$entry = array('mask' => $perm);
if (!empty($matches[2])) {
$entry['host'] = $matches[2];
} elseif (!empty($matches[3])) {
$entry['rlistings'] = TRUE;
} elseif (!empty($matches[4])) {
$entry['account'] = $matches[4];
if (!empty($matches[6])) {
$entry['user'] = $matches[6];
}
}
}
if (self::WRITE & $rule['mask']) {
$ruleStr = $this->ruleToString(self::WRITE, $rule);
if (!empty($ruleStr)) {
$writers[] = $ruleStr;
return $entry;
}
/**
* Create a new ACL.
*
* This creates an empty ACL with no permissions granted. When no
* permissions are granted, the file is effectively private
* (nonPublic()).
*
* Use add* methods to add permissions.
*/
public function __construct() {}
/**
* Grant ACL access to an account.
*
* Optionally, a user may be given to further limit access.
*
* This is used to restrict access to a particular account and, if so
* specified, a specific user on that account.
*
* If just an account is given, any user on that account will be
* automatically granted access.
*
* If an account and a user is given, only that user of the account is
* granted access.
*
* If $user is an array, every user in the array will be granted
* access under the provided account. That is, for each user in the
* array, an entry of the form `account:user` will be generated in the
* final ACL.
*
* At this time there does not seem to be a way to grant global write
* access to an object.
*
* @param int $perm ACL::READ, ACL::WRITE or ACL::READ_WRITE (which is the
* same as ACL::READ|ACL::WRITE).
* @param string $account The name of the account.
* @param mixed $user The name of the user, or optionally an indexed array of
* user names.
*
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
* the method can be used in chaining.
*/
public function addAccount($perm, $account, $user = NULL)
{
$rule = array('account' => $account);
if (!empty($user)) {
$rule['user'] = $user;
}
}
$this->addRule($perm, $rule);
return $this;
}
// Create the HTTP headers.
if (!empty($readers)) {
$headers[self::HEADER_READ] = implode(',', $readers);
}
if (!empty($writers)) {
$headers[self::HEADER_WRITE] = implode(',', $writers);
/**
* Allow (or deny) a hostname or host pattern.
*
* In current Swift implementations, only READ rules can have host
* patterns. WRITE permissions cannot be granted to hostnames.
*
* Formats:
* - Allow any host: '*'
* - Allow exact host: 'www.example.com'
* - Allow hosts in domain: '.example.com'
* - Disallow exact host: '-www.example.com'
* - Disallow hosts in domain: '-.example.com'
*
* Note that a simple minus sign ('-') is illegal, though it seems it
* should be "disallow all hosts."
*
* @param string $perm The permission being granted. One of ACL:READ,
* ACL::WRITE, or ACL::READ_WRITE.
* @param string $host A host specification string as described above.
*
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
* the method can be used in chaining.
*/
public function addReferrer($perm, $host = '*')
{
$this->addRule($perm, array('host' => $host));
return $this;
}
return $headers;
}
/**
* Add a rule to the appropriate stack of rules.
*
* @param int $perm One of the predefined permission constants.
* @param array $rule A rule array.
*
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
* the method can be used in chaining.
*/
protected function addRule($perm, $rule)
{
$rule['mask'] = $perm;
/**
* Convert a rule to a string.
*
* @param int $perm The permission for which to generate the rule.
* @param array $rule A rule array.
*/
protected function ruleToString($perm, $rule) {
$this->rules[] = $rule;
// Some rules only apply to READ.
if (self::READ & $perm) {
// Host rule.
if (!empty($rule['host'])) {
return '.r:' . $rule['host'];
}
// Listing rule.
if (!empty($rule['rlistings'])) {
return '.rlistings';
}
return $this;
}
// READ and WRITE both allow account/user rules.
if (!empty($rule['account'])) {
/**
* Allow hosts with READ permissions to list a container's content.
*
* By default, granting READ permission on a container does not grant
* permission to list the contents of a container. Setting the
* ACL::allowListings() permission will allow matching hosts to also list
* the contents of a container.
*
* In the current Swift implementation, there is no mechanism for
* allowing some hosts to get listings, while denying others.
*
* @return \OpenStack\Storage\ObjectStorage\ACL $this for current object so
* the method can be used in chaining.
*/
public function allowListings()
{
$this->rules[] = array(
'mask' => self::READ,
'rlistings' => TRUE,
);
// Just an account name.
if (empty($rule['user'])) {
return $rule['account'];
}
return $this;
}
/**
* Get the rules array for this ACL.
*
* @return array An array of associative arrays of rules.
*/
public function rules()
{
return $this->rules;
}
/**
* Generate HTTP headers for this ACL.
*
* If this is called on an empty object, an empty set of headers is
* returned.
*
* @return array Array of headers
*/
public function headers()
{
$headers = array();
$readers = array();
$writers = array();
// Create the rule strings. We need two copies, one for READ and
// one for WRITE.
foreach ($this->rules as $rule) {
// We generate read and write rules separately so that the
// generation logic has a chance to respond to the differences
// allowances for READ and WRITE ACLs.
if (self::READ & $rule['mask']) {
$ruleStr = $this->ruleToString(self::READ, $rule);
if (!empty($ruleStr)) {
$readers[] = $ruleStr;
}
}
if (self::WRITE & $rule['mask']) {
$ruleStr = $this->ruleToString(self::WRITE, $rule);
if (!empty($ruleStr)) {
$writers[] = $ruleStr;
}
}
}
// Create the HTTP headers.
if (!empty($readers)) {
$headers[self::HEADER_READ] = implode(',', $readers);
}
if (!empty($writers)) {
$headers[self::HEADER_WRITE] = implode(',', $writers);
}
return $headers;
}
/**
* Convert a rule to a string.
*
* @param int $perm The permission for which to generate the rule.
* @param array $rule A rule array.
*/
protected function ruleToString($perm, $rule)
{
// Some rules only apply to READ.
if (self::READ & $perm) {
// Host rule.
if (!empty($rule['host'])) {
return '.r:' . $rule['host'];
}
// Listing rule.
if (!empty($rule['rlistings'])) {
return '.rlistings';
}
}
// READ and WRITE both allow account/user rules.
if (!empty($rule['account'])) {
// Just an account name.
if (empty($rule['user'])) {
return $rule['account'];
}
// Account + multiple users.
elseif (is_array($rule['user'])) {
$buffer = array();
foreach ($rule['user'] as $user) {
$buffer[] = $rule['account'] . ':' . $user;
}
return implode(',', $buffer);
}
// Account + one user.
else {
return $rule['account'] . ':' . $rule['user'];
}
}
}
/**
* Check if the ACL marks this private.
*
* This returns TRUE only if this ACL does not grant any permissions
* at all.
*
* @return boolean TRUE if this is private (non-public), FALSE if any
* permissions are granted via this ACL.
*/
public function isNonPublic()
{
return empty($this->rules);
}
/**
* Alias of isNonPublic().
*/
public function isPrivate()
{
return $this->isNonPublic();
}
/**
* Check whether this object allows public reading.
*
* This will return TRUE the ACL allows (a) any host to access
* the item, and (b) it allows container listings.
*
* This checks whether the object allows public reading,
* not whether it is ONLY allowing public reads.
*
* @see ACL::makePublic().
*
* @return boolean Whether or not the object allows public reading.
*/
public function isPublic()
{
$allowsAllHosts = FALSE;
$allowsRListings = FALSE;
foreach ($this->rules as $rule) {
if (self::READ & $rule['mask']) {
if (!empty($rule['rlistings'])) {
$allowsRListings = TRUE;
} elseif (!empty($rule['host']) && trim($rule['host']) == '*') {
$allowsAllHosts = TRUE;
}
}
}
return $allowsAllHosts && $allowsRListings;
}
/**
* Implements the magic `__toString()` PHP function.
*
* This allows you to `print $acl` and get back
* a pretty string.
*
* @return string The ACL represented as a string.
*/
public function __toString()
{
$headers = $this->headers();
// Account + multiple users.
elseif (is_array($rule['user'])) {
$buffer = array();
foreach ($rule['user'] as $user) {
$buffer[] = $rule['account'] . ':' . $user;
foreach ($headers as $k => $v) {
$buffer[] = $k . ': ' . $v;
}
return implode(',', $buffer);
}
// Account + one user.
else {
return $rule['account'] . ':' . $rule['user'];
}
}
}
/**
* Check if the ACL marks this private.
*
* This returns TRUE only if this ACL does not grant any permissions
* at all.
*
* @return boolean TRUE if this is private (non-public), FALSE if any
* permissions are granted via this ACL.
*/
public function isNonPublic() {
return empty($this->rules);
}
/**
* Alias of isNonPublic().
*/
public function isPrivate() {
return $this->isNonPublic();
}
/**
* Check whether this object allows public reading.
*
* This will return TRUE the ACL allows (a) any host to access
* the item, and (b) it allows container listings.
*
* This checks whether the object allows public reading,
* not whether it is ONLY allowing public reads.
*
* @see ACL::makePublic().
*
* @return boolean Whether or not the object allows public reading.
*/
public function isPublic() {
$allowsAllHosts = FALSE;
$allowsRListings = FALSE;
foreach ($this->rules as $rule) {
if (self::READ & $rule['mask']) {
if (!empty($rule['rlistings'])) {
$allowsRListings = TRUE;
}
elseif(!empty($rule['host']) && trim($rule['host']) == '*') {
$allowsAllHosts = TRUE;
}
}
}
return $allowsAllHosts && $allowsRListings;
}
/**
* Implements the magic `__toString()` PHP function.
*
* This allows you to `print $acl` and get back
* a pretty string.
*
* @return string The ACL represented as a string.
*/
public function __toString() {
$headers = $this->headers();
$buffer = array();
foreach ($headers as $k => $v) {
$buffer[] = $k . ': ' . $v;
return implode("\t", $buffer);
}
return implode("\t", $buffer);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Contains exception class for ContainerNotEmptyException.

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Contains the ContentVerificationException object.

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Contains the class Object for ObjectStorage.
@ -46,457 +46,480 @@ namespace OpenStack\Storage\ObjectStorage;
* Likewise, a Container instance can retrieve Object instances from the
* remote object store.
*/
class Object {
class Object
{
const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
/**
* The name of the object.
*
* This can be path-like, subject to OpenStack's definition
* of "path-like".
*/
protected $name;
/**
* The name of the object.
*
* This can be path-like, subject to OpenStack's definition
* of "path-like".
*/
protected $name;
/**
* The content.
*
* Subclasses needn't use this to store an object's content,
* as they may prefer filesystem backing.
*/
protected $content;
/**
* The content.
*
* Subclasses needn't use this to store an object's content,
* as they may prefer filesystem backing.
*/
protected $content;
/**
* The content type.
*
* The default type is 'application/octet-stream', which marks this as
* a generic byte stream.
*/
protected $contentType = self::DEFAULT_CONTENT_TYPE;
/**
* The content type.
*
* The default type is 'application/octet-stream', which marks this as
* a generic byte stream.
*/
protected $contentType = self::DEFAULT_CONTENT_TYPE;
/**
* Associative array of stored metadata.
*/
protected $metadata = array();
/**
* Associative array of stored metadata.
*/
protected $metadata = array();
protected $contentEncoding;
protected $contentDisposition;
protected $contentEncoding;
protected $contentDisposition;
/**
* Extension mechanism for new headers.
*/
protected $additionalHeaders = array();
/**
* Extension mechanism for new headers.
*/
protected $additionalHeaders = array();
/**
* Construct a new object for storage.
*
* @param string $name A name (may be pathlike) for the object.
* @param string $content Optional content to store in this object. This is
* the same as calling setContent().
* @param string $type Optional content type for this content. This is the
* same as calling setContentType().
*/
public function __construct($name, $content = NULL, $type = NULL)
{
$this->name = $name;
/**
* Construct a new object for storage.
*
* @param string $name A name (may be pathlike) for the object.
* @param string $content Optional content to store in this object. This is
* the same as calling setContent().
* @param string $type Optional content type for this content. This is the
* same as calling setContentType().
*/
public function __construct($name, $content = NULL, $type = NULL) {
$this->name = $name;
if (!is_null($content)) {
$this->content = $content;
}
if (!empty($type)) {
$this->contentType = $type;
}
}
/**
* Set the metadata.
*
* OpenStack allows you to specify metadata for a file. Metadata items
* must follow these conventions:
*
* - names must contain only letters, numbers, and short dashes. Since
* OpenStack normalizes the name to begin with uppercase, it is
* suggested that you follow this convetion: Foo, not foo. Or you
* can do your own normalizing (such as converting all to lowercase.
* OpenStack limits the name length to 126 unicode chars.
* - values must be encoded if they contain newlines or binary data.
* While the exact encoding is up to you, Base-64 encoding is probably
* your best bet. OpenStack limits the value to 256 unicode chars.
*
* (The docs are ambiguous -- they say chars, but they may mean
* bytes.)
*
* This library does only minimal processing of metadata, and does no
* error checking, escaping, etc. This is up to the implementor. The
* OpenStack Swift implementation does not dictate what encoding is
* used, though it suggests url encoding of both name and values.
*
* Currently, no length checking is performed in the library, nor is
* any encoding of the data performed.
*
* IMPORTANT: Current versions of OpenStack Swift normalize metadata
* names so that the name is always given an initial capital leter.
* That is, `foo` becomes `Foo`.
*
* @param array $array An associative array of metadata names to values.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setMetadata(array $array) {
$this->metadata = $array;
return $this;
}
/**
* Get any associated metadata.
*
* This returns an associative array of all metadata for this object.
*
* @return array An associative array of metadata. This may be empty.
*/
public function metadata() {
return $this->metadata;
}
/**
* Override (change) the name of an object.
*
* Note that this changes only the local copy of an object. It
* does not rename the remote copy. In fact, changing the local name
* and then saving it will result in a new object being created in the
* object store.
*
* To copy an object:
* @see \OpenStack\Storage\ObjectStorage\Container::copyObject().
*
* @param string $name A file or object name.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setName($name) {
$this->name = $name;
return $this;
}
/**
* Get the name.
*
* Returns the name of an object. If the name has been overwritten
* using setName(), this will return the latest (overwritten) name.
*
* @return string The name of the object.
*/
public function name() {
return $this->name;
}
/**
* Set the content type (MIME type) for the object.
*
* Object storage is, to a certain degree, content-type aware. For
* that reason, a content type is mandatory.
*
* The default MIME type used is `application/octet-stream`, which is
* the generic content type for a byte stream. Where possible, you
* should set a more accurate content type.
*
* All HTTP type options are allowed. So, for example, you can add a
* charset to a text type:
*
* <?php
* $o = new Object('my.html');
* $o->setContentType('text/html; charset=iso-8859-13');
* ?>
*
* Content type is not parsed or verified locally (though it is
* remotely). It can be dangerous, too, to allow users to specify a
* content type.
*
* @param string $type A valid content type.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setContentType($type) {
$this->contentType = $type;
return $this;
}
/**
* Get the content type.
*
* This returns the currently set content type.
*
* @return string The content type, including any additional options.
*/
public function contentType() {
return $this->contentType;
}
/**
* Set the content for this object.
*
* Place the content into the object. Typically, this is string
* content that will be stored remotely.
*
* PHP's string is backed by a robust system that can accomodate
* moderately sized files. However, it is best to keep strings short
* (<2MB, for example -- test for your own system's sweet spot).
* Larger data may be better handled with file system entries or
* database storage.
*
* Note that the OpenStack will not allow files larger than 5G, and
* PHP will likely croak well before that marker. So use discretion.
*
* @param string $content The content of the object.
* @param string $type The content type (MIME type). This can be set here for
* convenience, or you can call setContentType() directly.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setContent($content, $type = NULL) {
$this->content = $content;
if (!empty($type)) {
$this->contentType = $type;
}
return $this;
}
/**
* Retrieve the content.
*
* Retrieve the ENTIRE content of an object.
*
* Note that this may be binary data (depending on what the original
* content is). PHP strings are generally binary safe, but use this
* with caution if you do not know what kind of data is stored in an
* object.
*
* OpenStack does not do anything to validate that the content type is
* accurate. While contentType() is intended to provide useful
* information, poorly managed data can be written with the wrong
* content type.
*
* When extending this class, you should make sure that this function
* returns the entire contents of an object.
*
* @return string The content of the file.
*/
public function content() {
return $this->content;
}
/**
* Calculate the content length.
*
* This returns the number of bytes in a piece of content (not
* the number of characters). Among other things, it is used to let
* the remote object store know how big of an object to expect when
* transmitting data.
*
* When extending this class, you should make sure to calculate the
* content length appropriately.
*
* @return int The length of the content, in bytes.
*/
public function contentLength() {
// strlen() is binary safe (or at least it seems to be).
return strlen($this->content);
}
/**
* Generate an ETag for the ObjectStorage server.
*
* OpenStack uses ETag to pass validation data. This generates an ETag
* using an MD5 hash of the content.
*
* When extending this class, generate an ETag by creating an MD5 of
* the entire object's content (but not the metadata or name).
*
* @return string An MD5 value as a string of 32 hex digits (0-9a-f).
*/
public function eTag() {
return md5($this->content);
}
/**
* Set the encoding for a file.
*
* You can use content encoding on compressed content to indicate to
* the receiving agent that a file is encoded using a specific
* compression type.
*
* Typical compression types are 'gzip', 'zip', and 'compress', though
* many others exist.
*
* This allows you, for example, to save a zipped file, yet preserve
* its underlying content type. For example, for a gzipped text/plain
* file, you can set the content type to "text/plain" and the encoding
* to "gzip". This allows many user agents to receive the compressed
* data and automatically decompress them and display them correctly.
*
* @param string $encoding A valid encoding type.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setEncoding($encoding) {
$this->contentEncoding = $encoding;
return $this;
}
/**
* Get the encoding (if any) for this object.
*
* Encoding is used to indicate how a file was encoded or compressed.
* See setEncoding() for more information.
*
* @return string The encoding type.
*/
public function encoding() {
return $this->contentEncoding;
}
/**
* Set the content disposition.
*
* This makes it possible to have the file act like a download (in a
* browser or similar agent), even if the MIME type normally triggers
* a display.
*
* The typical value for this is:
*
* <?php
* $object->setDisposition('attachment; filename=foo.png');
* ?>
*
* A disposition string should not include any newline characters or
* binary data.
*
* @param string $disposition A valid disposition declaration. These are
* defined in various HTTP specifications.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setDisposition($disposition) {
$this->contentDisposition = $disposition;
return $this;
}
/**
* Get the current disposition string, if any.
*
* See setDisposition() for discussion.
*
* @return string The disposition string, or NULL if none is set.
*/
public function disposition() {
return $this->contentDisposition;
}
/**
* Set additional headers for storage.
*
* EXPERT: You will need to understand OpenStack internals to use this
* effectively.
*
* Headers set here will be added to the HTTP request during save
* operations. They are not merged into existing headers until
* save-time.
*
* This provides a mechanism for adding extension headers. CORS
* headers and possibly others are stored by Swift, but have no
* semantic value to Swift or to popular user agents.
*
* There are a few things to note about this mechanism:
*
* - Existing headers cannot be overwritten. Only new headers can be
* added.
* - Headers are not merged. They are simply sent to the remote
* server. A new object must be retrieved from the server before
* these headers will be accessible.
* - Swift only stores certain headers. If you supply an unrecognized
* header to Swift, it may simply ignore it.
* - The RemoteObject::headers() method provides access to all of the
* headers returned from Swift.
* - Headers are merged in as they are, with no cleaning, encoding, or
* checking. You must ensure that the headers are in the proper
* format.
*
* @param array $headers An associative array where each name is an HTTP
* header name, and each value is the HTTP header value. No encoding or
* escaping is done.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setAdditionalHeaders($headers) {
$this->additionalHeaders = $headers;
return $this;
}
/**
* Return additional headers.
*
* Headers here have likely not been stored remotely until
* Container::save() is called on the object.
*/
public function additionalHeaders() {
return $this->additionalHeaders;
}
/**
* Remove headers.
*
* This takes an array of header names, and removes
* any matching headers. Typically, only headers set
* by setAdditionalHeaders() are removed from an Object.
* (RemoteObject works differently).
*
* Many headers are generated automatically, such as
* Content-Type and Content-Length. Removing these
* will simply result in their being regenerated.
*
* @param array $keys The header names to be removed.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this for the current
* object so it can be used in chaining methods.
*/
public function removeHeaders($keys) {
foreach ($keys as $k) {
unset($this->additionalHeaders[$k]);
if (!is_null($content)) {
$this->content = $content;
}
if (!empty($type)) {
$this->contentType = $type;
}
}
return $this;
}
/**
* Set the metadata.
*
* OpenStack allows you to specify metadata for a file. Metadata items
* must follow these conventions:
*
* - names must contain only letters, numbers, and short dashes. Since
* OpenStack normalizes the name to begin with uppercase, it is
* suggested that you follow this convetion: Foo, not foo. Or you
* can do your own normalizing (such as converting all to lowercase.
* OpenStack limits the name length to 126 unicode chars.
* - values must be encoded if they contain newlines or binary data.
* While the exact encoding is up to you, Base-64 encoding is probably
* your best bet. OpenStack limits the value to 256 unicode chars.
*
* (The docs are ambiguous -- they say chars, but they may mean
* bytes.)
*
* This library does only minimal processing of metadata, and does no
* error checking, escaping, etc. This is up to the implementor. The
* OpenStack Swift implementation does not dictate what encoding is
* used, though it suggests url encoding of both name and values.
*
* Currently, no length checking is performed in the library, nor is
* any encoding of the data performed.
*
* IMPORTANT: Current versions of OpenStack Swift normalize metadata
* names so that the name is always given an initial capital leter.
* That is, `foo` becomes `Foo`.
*
* @param array $array An associative array of metadata names to values.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setMetadata(array $array)
{
$this->metadata = $array;
/**
* This object should be transmitted in chunks.
*
* Indicates whether or not this object should be transmitted as
* chunked data (in HTTP).
*
* This should be used when (a) the file size is large, or (b) the
* exact size of the file is unknown.
*
* If this returns TRUE, it does not guarantee that the data
* will be transmitted in chunks. But it recommends that the
* underlying transport layer use chunked encoding.
*
* The contentLength() method is not called for chunked transfers. So
* if this returns TRUE, contentLength() is ignored.
*
* @return boolean TRUE to recommend chunked transfer, FALSE otherwise.
*/
public function isChunked() {
// Currently, this value is hard-coded. The default Object
// implementation does not get chunked.
return FALSE;
}
return $this;
}
/**
* Get any associated metadata.
*
* This returns an associative array of all metadata for this object.
*
* @return array An associative array of metadata. This may be empty.
*/
public function metadata()
{
return $this->metadata;
}
/**
* Override (change) the name of an object.
*
* Note that this changes only the local copy of an object. It
* does not rename the remote copy. In fact, changing the local name
* and then saving it will result in a new object being created in the
* object store.
*
* To copy an object:
* @see \OpenStack\Storage\ObjectStorage\Container::copyObject().
*
* @param string $name A file or object name.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get the name.
*
* Returns the name of an object. If the name has been overwritten
* using setName(), this will return the latest (overwritten) name.
*
* @return string The name of the object.
*/
public function name()
{
return $this->name;
}
/**
* Set the content type (MIME type) for the object.
*
* Object storage is, to a certain degree, content-type aware. For
* that reason, a content type is mandatory.
*
* The default MIME type used is `application/octet-stream`, which is
* the generic content type for a byte stream. Where possible, you
* should set a more accurate content type.
*
* All HTTP type options are allowed. So, for example, you can add a
* charset to a text type:
*
* <?php
* $o = new Object('my.html');
* $o->setContentType('text/html; charset=iso-8859-13');
* ?>
*
* Content type is not parsed or verified locally (though it is
* remotely). It can be dangerous, too, to allow users to specify a
* content type.
*
* @param string $type A valid content type.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setContentType($type)
{
$this->contentType = $type;
return $this;
}
/**
* Get the content type.
*
* This returns the currently set content type.
*
* @return string The content type, including any additional options.
*/
public function contentType()
{
return $this->contentType;
}
/**
* Set the content for this object.
*
* Place the content into the object. Typically, this is string
* content that will be stored remotely.
*
* PHP's string is backed by a robust system that can accomodate
* moderately sized files. However, it is best to keep strings short
* (<2MB, for example -- test for your own system's sweet spot).
* Larger data may be better handled with file system entries or
* database storage.
*
* Note that the OpenStack will not allow files larger than 5G, and
* PHP will likely croak well before that marker. So use discretion.
*
* @param string $content The content of the object.
* @param string $type The content type (MIME type). This can be set here for
* convenience, or you can call setContentType() directly.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setContent($content, $type = NULL)
{
$this->content = $content;
if (!empty($type)) {
$this->contentType = $type;
}
return $this;
}
/**
* Retrieve the content.
*
* Retrieve the ENTIRE content of an object.
*
* Note that this may be binary data (depending on what the original
* content is). PHP strings are generally binary safe, but use this
* with caution if you do not know what kind of data is stored in an
* object.
*
* OpenStack does not do anything to validate that the content type is
* accurate. While contentType() is intended to provide useful
* information, poorly managed data can be written with the wrong
* content type.
*
* When extending this class, you should make sure that this function
* returns the entire contents of an object.
*
* @return string The content of the file.
*/
public function content()
{
return $this->content;
}
/**
* Calculate the content length.
*
* This returns the number of bytes in a piece of content (not
* the number of characters). Among other things, it is used to let
* the remote object store know how big of an object to expect when
* transmitting data.
*
* When extending this class, you should make sure to calculate the
* content length appropriately.
*
* @return int The length of the content, in bytes.
*/
public function contentLength()
{
// strlen() is binary safe (or at least it seems to be).
return strlen($this->content);
}
/**
* Generate an ETag for the ObjectStorage server.
*
* OpenStack uses ETag to pass validation data. This generates an ETag
* using an MD5 hash of the content.
*
* When extending this class, generate an ETag by creating an MD5 of
* the entire object's content (but not the metadata or name).
*
* @return string An MD5 value as a string of 32 hex digits (0-9a-f).
*/
public function eTag()
{
return md5($this->content);
}
/**
* Set the encoding for a file.
*
* You can use content encoding on compressed content to indicate to
* the receiving agent that a file is encoded using a specific
* compression type.
*
* Typical compression types are 'gzip', 'zip', and 'compress', though
* many others exist.
*
* This allows you, for example, to save a zipped file, yet preserve
* its underlying content type. For example, for a gzipped text/plain
* file, you can set the content type to "text/plain" and the encoding
* to "gzip". This allows many user agents to receive the compressed
* data and automatically decompress them and display them correctly.
*
* @param string $encoding A valid encoding type.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setEncoding($encoding)
{
$this->contentEncoding = $encoding;
return $this;
}
/**
* Get the encoding (if any) for this object.
*
* Encoding is used to indicate how a file was encoded or compressed.
* See setEncoding() for more information.
*
* @return string The encoding type.
*/
public function encoding()
{
return $this->contentEncoding;
}
/**
* Set the content disposition.
*
* This makes it possible to have the file act like a download (in a
* browser or similar agent), even if the MIME type normally triggers
* a display.
*
* The typical value for this is:
*
* <?php
* $object->setDisposition('attachment; filename=foo.png');
* ?>
*
* A disposition string should not include any newline characters or
* binary data.
*
* @param string $disposition A valid disposition declaration. These are
* defined in various HTTP specifications.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setDisposition($disposition)
{
$this->contentDisposition = $disposition;
return $this;
}
/**
* Get the current disposition string, if any.
*
* See setDisposition() for discussion.
*
* @return string The disposition string, or NULL if none is set.
*/
public function disposition()
{
return $this->contentDisposition;
}
/**
* Set additional headers for storage.
*
* EXPERT: You will need to understand OpenStack internals to use this
* effectively.
*
* Headers set here will be added to the HTTP request during save
* operations. They are not merged into existing headers until
* save-time.
*
* This provides a mechanism for adding extension headers. CORS
* headers and possibly others are stored by Swift, but have no
* semantic value to Swift or to popular user agents.
*
* There are a few things to note about this mechanism:
*
* - Existing headers cannot be overwritten. Only new headers can be
* added.
* - Headers are not merged. They are simply sent to the remote
* server. A new object must be retrieved from the server before
* these headers will be accessible.
* - Swift only stores certain headers. If you supply an unrecognized
* header to Swift, it may simply ignore it.
* - The RemoteObject::headers() method provides access to all of the
* headers returned from Swift.
* - Headers are merged in as they are, with no cleaning, encoding, or
* checking. You must ensure that the headers are in the proper
* format.
*
* @param array $headers An associative array where each name is an HTTP
* header name, and each value is the HTTP header value. No encoding or
* escaping is done.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this so the method can be
* used in chaining.
*/
public function setAdditionalHeaders($headers)
{
$this->additionalHeaders = $headers;
return $this;
}
/**
* Return additional headers.
*
* Headers here have likely not been stored remotely until
* Container::save() is called on the object.
*/
public function additionalHeaders()
{
return $this->additionalHeaders;
}
/**
* Remove headers.
*
* This takes an array of header names, and removes
* any matching headers. Typically, only headers set
* by setAdditionalHeaders() are removed from an Object.
* (RemoteObject works differently).
*
* Many headers are generated automatically, such as
* Content-Type and Content-Length. Removing these
* will simply result in their being regenerated.
*
* @param array $keys The header names to be removed.
*
* @return \OpenStack\Storage\ObjectStorage\Object $this for the current
* object so it can be used in chaining methods.
*/
public function removeHeaders($keys)
{
foreach ($keys as $k) {
unset($this->additionalHeaders[$k]);
}
return $this;
}
/**
* This object should be transmitted in chunks.
*
* Indicates whether or not this object should be transmitted as
* chunked data (in HTTP).
*
* This should be used when (a) the file size is large, or (b) the
* exact size of the file is unknown.
*
* If this returns TRUE, it does not guarantee that the data
* will be transmitted in chunks. But it recommends that the
* underlying transport layer use chunked encoding.
*
* The contentLength() method is not called for chunked transfers. So
* if this returns TRUE, contentLength() is ignored.
*
* @return boolean TRUE to recommend chunked transfer, FALSE otherwise.
*/
public function isChunked()
{
// Currently, this value is hard-coded. The default Object
// implementation does not get chunked.
return FALSE;
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
namespace OpenStack\Storage\ObjectStorage;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Contains the stream wrapper for `swiftfs://` URLs.
@ -71,144 +71,145 @@ use \OpenStack\Storage\ObjectStorage;
*
* @see http://us3.php.net/manual/en/class.streamwrapper.php
*/
class StreamWrapperFS extends StreamWrapper {
class StreamWrapperFS extends StreamWrapper
{
const DEFAULT_SCHEME = 'swiftfs';
protected $schemeName = self::DEFAULT_SCHEME;
const DEFAULT_SCHEME = 'swiftfs';
protected $schemeName = self::DEFAULT_SCHEME;
/**
* Fake a make a dir.
*
* ObjectStorage has pathy objects not directories. If no objects with a path
* prefix exist we can pass creating a directory. If objects with a path
* prefix exist adding the directory will fail.
*/
public function mkdir($uri, $mode, $options)
{
return ($this->cxt('swiftfs_fake_isdir_true', FALSE) || !($this->testDirectoryExists($uri)));
/**
* Fake a make a dir.
*
* ObjectStorage has pathy objects not directories. If no objects with a path
* prefix exist we can pass creating a directory. If objects with a path
* prefix exist adding the directory will fail.
*/
public function mkdir($uri, $mode, $options) {
return ($this->cxt('swiftfs_fake_isdir_true', FALSE) || !($this->testDirectoryExists($uri)));
}
/**
* Fake Remove a directory.
*
* ObjectStorage has pathy objects not directories. If no objects with a path
* prefix exist we can pass removing it. If objects with a path prefix exist
* removing the directory will fail.
*/
public function rmdir($path, $options) {
return !($this->testDirectoryExists($path));
}
/**
* @see stream_stat().
*/
public function url_stat($path, $flags) {
$stat = parent::url_stat($path, $flags);
// If the file stat setup returned anything return it.
if ($stat) {
return $stat;
}
// When FALSE is returned there is no file to stat. So, we attempt to handle
// it like a directory.
else {
if ($this->cxt('swiftfs_fake_isdir_true', FALSE) || $this->testDirectoryExists($path)) {
// The directory prefix exists. Fake the directory file permissions.
return $this->fakeStat(TRUE);
}
else {
// The directory does not exist as a prefix.
return FALSE;
}
}
}
///////////////////////////////////////////////////////////////////
// INTERNAL METHODS
// All methods beneath this line are not part of the Stream API.
///////////////////////////////////////////////////////////////////
/**
* Test if a path prefix (directory like) esits.
*
* ObjectStorage has pathy objects not directories. If objects exist with a
* path prefix we can consider that the directory exists. For example, if
* we have an object at foo/bar/baz.txt and test the existance of the
* directory foo/bar/ we sould see it.
*
* @param string $path The directory path to test.
*
* @return boolean TRUE if the directory prefix exists and FALSE otherwise.
*/
protected function testDirectoryExists($path) {
$url = $this->parseUrl($path);
if (empty($url['host'])) {
trigger_error('Container name is required.' , E_USER_WARNING);
return FALSE;
}
try {
$this->initializeObjectStorage();
$container = $this->store->container($url['host']);
/**
* Fake Remove a directory.
*
* ObjectStorage has pathy objects not directories. If no objects with a path
* prefix exist we can pass removing it. If objects with a path prefix exist
* removing the directory will fail.
*/
public function rmdir($path, $options)
{
return !($this->testDirectoryExists($path));
if (empty($url['path'])) {
$this->dirPrefix = '';
}
else {
$this->dirPrefix = $url['path'];
}
$sep = '/';
$dirListing = $container->objectsWithPrefix($this->dirPrefix, $sep);
return !empty($dirListing);
}
catch (\OpenStack\Exception $e) {
trigger_error('Path could not be opened: ' . $e->getMessage(), E_USER_WARNING);
return FALSE;
/**
* @see stream_stat().
*/
public function url_stat($path, $flags)
{
$stat = parent::url_stat($path, $flags);
// If the file stat setup returned anything return it.
if ($stat) {
return $stat;
}
// When FALSE is returned there is no file to stat. So, we attempt to handle
// it like a directory.
else {
if ($this->cxt('swiftfs_fake_isdir_true', FALSE) || $this->testDirectoryExists($path)) {
// The directory prefix exists. Fake the directory file permissions.
return $this->fakeStat(TRUE);
} else {
// The directory does not exist as a prefix.
return FALSE;
}
}
}
}
/**
* Fake stat data.
*
* Under certain conditions we have to return totally trumped-up
* stats. This generates those.
*/
protected function fakeStat($dir = FALSE) {
///////////////////////////////////////////////////////////////////
// INTERNAL METHODS
// All methods beneath this line are not part of the Stream API.
///////////////////////////////////////////////////////////////////
$request_time = time();
/**
* Test if a path prefix (directory like) esits.
*
* ObjectStorage has pathy objects not directories. If objects exist with a
* path prefix we can consider that the directory exists. For example, if
* we have an object at foo/bar/baz.txt and test the existance of the
* directory foo/bar/ we sould see it.
*
* @param string $path The directory path to test.
*
* @return boolean TRUE if the directory prefix exists and FALSE otherwise.
*/
protected function testDirectoryExists($path)
{
$url = $this->parseUrl($path);
// Set inode type to directory or file.
$type = $dir ? 040000 : 0100000;
// Fake world-readible
$mode = $type + $this->cxt('swiftfs_fake_stat_mode', 0777);
if (empty($url['host'])) {
trigger_error('Container name is required.' , E_USER_WARNING);
$values = array(
'dev' => 0,
'ino' => 0,
'mode' => $mode,
'nlink' => 0,
'uid' => posix_getuid(),
'gid' => posix_getgid(),
'rdev' => 0,
'size' => 0,
'atime' => $request_time,
'mtime' => $request_time,
'ctime' => $request_time,
'blksize' => -1,
'blocks' => -1,
);
return FALSE;
}
$final = array_values($values) + $values;
try {
$this->initializeObjectStorage();
$container = $this->store->container($url['host']);
return $final;
}
if (empty($url['path'])) {
$this->dirPrefix = '';
} else {
$this->dirPrefix = $url['path'];
}
$sep = '/';
$dirListing = $container->objectsWithPrefix($this->dirPrefix, $sep);
return !empty($dirListing);
} catch (\OpenStack\Exception $e) {
trigger_error('Path could not be opened: ' . $e->getMessage(), E_USER_WARNING);
return FALSE;
}
}
/**
* Fake stat data.
*
* Under certain conditions we have to return totally trumped-up
* stats. This generates those.
*/
protected function fakeStat($dir = FALSE)
{
$request_time = time();
// Set inode type to directory or file.
$type = $dir ? 040000 : 0100000;
// Fake world-readible
$mode = $type + $this->cxt('swiftfs_fake_stat_mode', 0777);
$values = array(
'dev' => 0,
'ino' => 0,
'mode' => $mode,
'nlink' => 0,
'uid' => posix_getuid(),
'gid' => posix_getgid(),
'rdev' => 0,
'size' => 0,
'atime' => $request_time,
'mtime' => $request_time,
'ctime' => $request_time,
'blksize' => -1,
'blocks' => -1,
);
$final = array_values($values) + $values;
return $final;
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Contains the Subdir class.
@ -28,48 +28,50 @@ namespace OpenStack\Storage\ObjectStorage;
*
* Subdirs are used for things that are directory-like.
*/
class Subdir {
class Subdir
{
/**
* @var string The path string that this subdir describes
*/
protected $path;
/**
* @var string The path string that this subdir describes
*/
protected $path;
/**
* @var string The delimiter used in this path
*/
protected $delimiter;
/**
* @var string The delimiter used in this path
*/
protected $delimiter;
/**
* Create a new subdirectory.
*
* This represents a remote response's tag for a subdirectory.
*
* @param string $path The path string that this subdir describes.
* @param string $delimiter The delimiter used in this path.
*/
public function __construct($path, $delimiter = '/')
{
$this->path = $path;
$this->delimiter = $delimiter;
}
/**
* Create a new subdirectory.
*
* This represents a remote response's tag for a subdirectory.
*
* @param string $path The path string that this subdir describes.
* @param string $delimiter The delimiter used in this path.
*/
public function __construct($path, $delimiter = '/') {
$this->path = $path;
$this->delimiter = $delimiter;
}
/**
* Get the path.
*
* The path is delimited using the string returned by delimiter().
*
* @return string The path
*/
public function path() {
return $this->path;
}
/**
* Get the delimiter used by the server.
*
* @return string The value used as a delimiter.
*/
public function delimiter() {
return $this->delimiter;
}
}
/**
* Get the path.
*
* The path is delimited using the string returned by delimiter().
*
* @return string The path
*/
public function path()
{
return $this->path;
}
/**
* Get the delimiter used by the server.
*
* @return string The value used as a delimiter.
*/
public function delimiter()
{
return $this->delimiter;
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* The authorization exception.

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* This file contains the interface for transporters.
@ -32,94 +32,93 @@ namespace OpenStack\Transport;
* HTTP/HTTPS, and perhaps SPDY some day. The interface reflects this.
* it is not designed as a protocol-neutral transport layer
*/
interface ClientInterface {
interface ClientInterface
{
const HTTP_USER_AGENT = 'OpenStack-PHP/1.0';
const HTTP_USER_AGENT = 'OpenStack-PHP/1.0';
/**
* Setup for the HTTP Client.
*
* @param array $options Options for the HTTP Client including:
* - headers (array) A key/value mapping of default headers for each request.
* - proxy (string) A proxy specified as a URI.
* - debug (bool) True if debug output should be displayed.
* - timeout (int) The timeout, in seconds, a request should wait before
* timing out.
* - ssl_verify (bool|string) True, the default, verifies the SSL certificate,
* FALSE disables verification, and a string is the path to a CA to verify
* against.
*/
public function __construct(array $options = []);
/**
* Setup for the HTTP Client.
*
* @param array $options Options for the HTTP Client including:
* - headers (array) A key/value mapping of default headers for each request.
* - proxy (string) A proxy specified as a URI.
* - debug (bool) True if debug output should be displayed.
* - timeout (int) The timeout, in seconds, a request should wait before
* timing out.
* - ssl_verify (bool|string) True, the default, verifies the SSL certificate,
* FALSE disables verification, and a string is the path to a CA to verify
* against.
*/
public function __construct(array $options = []);
/**
* Perform a request.
*
* Invoking this method causes a single request to be relayed over the
* transporter. The transporter MUST be capable of handling multiple
* invocations of a doRequest() call.
*
* @param string $uri The target URI.
* @param string $method The method to be sent.
* @param array $headers An array of name/value header pairs.
* @param string $body The string containing the request body.
*
* @return \OpenStack\Transport\ResponseInterface The response. The response
* is implicit rather than explicit. The interface is based on a draft for
* messages from PHP FIG. Individual implementing libraries will have their
* own reference to interfaces. For example, see Guzzle.
*
* @throws \OpenStack\Transport\ForbiddenException
* @throws \OpenStack\Transport\UnauthorizedException
* @throws \OpenStack\Transport\FileNotFoundException
* @throws \OpenStack\Transport\MethodNotAllowedException
* @throws \OpenStack\Transport\ConflictException
* @throws \OpenStack\Transport\LengthRequiredException
* @throws \OpenStack\Transport\UnprocessableEntityException
* @throws \OpenStack\Transport\ServerException
* @throws \OpenStack\Exception
*/
public function doRequest($uri, $method = 'GET', array $headers = [], $body = '');
/**
* Perform a request.
*
* Invoking this method causes a single request to be relayed over the
* transporter. The transporter MUST be capable of handling multiple
* invocations of a doRequest() call.
*
* @param string $uri The target URI.
* @param string $method The method to be sent.
* @param array $headers An array of name/value header pairs.
* @param string $body The string containing the request body.
*
* @return \OpenStack\Transport\ResponseInterface The response. The response
* is implicit rather than explicit. The interface is based on a draft for
* messages from PHP FIG. Individual implementing libraries will have their
* own reference to interfaces. For example, see Guzzle.
*
* @throws \OpenStack\Transport\ForbiddenException
* @throws \OpenStack\Transport\UnauthorizedException
* @throws \OpenStack\Transport\FileNotFoundException
* @throws \OpenStack\Transport\MethodNotAllowedException
* @throws \OpenStack\Transport\ConflictException
* @throws \OpenStack\Transport\LengthRequiredException
* @throws \OpenStack\Transport\UnprocessableEntityException
* @throws \OpenStack\Transport\ServerException
* @throws \OpenStack\Exception
*/
public function doRequest($uri, $method = 'GET', array $headers = [], $body = '');
/**
* Perform a request, but use a resource to read the body.
*
* This is a special version of the doRequest() function.
* It handles a very spefic case where...
*
* - The HTTP verb requires a body (viz. PUT, POST)
* - The body is in a resource, not a string
*
* Examples of appropriate cases for this variant:
*
* - Uploading large files.
* - Streaming data out of a stream and into an HTTP request.
* - Minimizing memory usage ($content strings are big).
*
* Note that all parameters are required.
*
* @param string $uri The target URI.
* @param string $method The method to be sent.
* @param array $headers An array of name/value header pairs.
* @param mixed $resource The string with a file path or a stream URL; or a
* file object resource. If it is a string, then it will be opened with the
* default context. So if you need a special context, you should open the
* file elsewhere and pass the resource in here.
*
* @return \OpenStack\Transport\ResponseInterface The response. The response
* is implicit rather than explicit. The interface is based on a draft for
* messages from PHP FIG. Individual implementing libraries will have their
* own reference to interfaces. For example, see Guzzle.
*
* @throws \OpenStack\Transport\ForbiddenException
* @throws \OpenStack\Transport\UnauthorizedException
* @throws \OpenStack\Transport\FileNotFoundException
* @throws \OpenStack\Transport\MethodNotAllowedException
* @throws \OpenStack\Transport\ConflictException
* @throws \OpenStack\Transport\LengthRequiredException
* @throws \OpenStack\Transport\UnprocessableEntityException
* @throws \OpenStack\Transport\ServerException
* @throws \OpenStack\Exception
*/
public function doRequestWithResource($uri, $method, array $headers = [], $resource);
/**
* Perform a request, but use a resource to read the body.
*
* This is a special version of the doRequest() function.
* It handles a very spefic case where...
*
* - The HTTP verb requires a body (viz. PUT, POST)
* - The body is in a resource, not a string
*
* Examples of appropriate cases for this variant:
*
* - Uploading large files.
* - Streaming data out of a stream and into an HTTP request.
* - Minimizing memory usage ($content strings are big).
*
* Note that all parameters are required.
*
* @param string $uri The target URI.
* @param string $method The method to be sent.
* @param array $headers An array of name/value header pairs.
* @param mixed $resource The string with a file path or a stream URL; or a
* file object resource. If it is a string, then it will be opened with the
* default context. So if you need a special context, you should open the
* file elsewhere and pass the resource in here.
*
* @return \OpenStack\Transport\ResponseInterface The response. The response
* is implicit rather than explicit. The interface is based on a draft for
* messages from PHP FIG. Individual implementing libraries will have their
* own reference to interfaces. For example, see Guzzle.
*
* @throws \OpenStack\Transport\ForbiddenException
* @throws \OpenStack\Transport\UnauthorizedException
* @throws \OpenStack\Transport\FileNotFoundException
* @throws \OpenStack\Transport\MethodNotAllowedException
* @throws \OpenStack\Transport\ConflictException
* @throws \OpenStack\Transport\LengthRequiredException
* @throws \OpenStack\Transport\UnprocessableEntityException
* @throws \OpenStack\Transport\ServerException
* @throws \OpenStack\Exception
*/
public function doRequestWithResource($uri, $method, array $headers = [], $resource);
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
namespace OpenStack\Transport;

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
namespace OpenStack\Transport;

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* @file

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* This file contains the interface for transporter clients.
@ -20,203 +20,208 @@
namespace OpenStack\Transport;
class GuzzleClient implements ClientInterface, \Serializable {
class GuzzleClient implements ClientInterface, \Serializable
{
const HTTP_USER_AGENT_SUFFIX = ' Guzzle/4.0';
const HTTP_USER_AGENT_SUFFIX = ' Guzzle/4.0';
/**
* The Guzzle client used for the implementation.
*/
protected $client;
/**
* The Guzzle client used for the implementation.
*/
protected $client;
protected $options;
protected $options;
/**
* Setup for the HTTP Client.
*
* @param array $options Options for the HTTP Client including:
* - headers (array) A key/value mapping of default headers for each request.
* - proxy (string) A proxy specified as a URI.
* - debug (bool) True if debug output should be displayed.
* - timeout (int) The timeout, in seconds, a request should wait before
* timing out.
* - ssl_verify (bool|string) True, the default, verifies the SSL certificate,
* FALSE disables verification, and a string is the path to a CA to verify
* against.
* - client (mixed) A guzzle client object to use instead of the default.
* This can be either a string to the class or an existing object. If an
* existing object is passed in the other options will be ignored.
*/
public function __construct(array $options = [])
{
$this->options = $options;
/**
* Setup for the HTTP Client.
*
* @param array $options Options for the HTTP Client including:
* - headers (array) A key/value mapping of default headers for each request.
* - proxy (string) A proxy specified as a URI.
* - debug (bool) True if debug output should be displayed.
* - timeout (int) The timeout, in seconds, a request should wait before
* timing out.
* - ssl_verify (bool|string) True, the default, verifies the SSL certificate,
* FALSE disables verification, and a string is the path to a CA to verify
* against.
* - client (mixed) A guzzle client object to use instead of the default.
* This can be either a string to the class or an existing object. If an
* existing object is passed in the other options will be ignored.
*/
public function __construct(array $options = []) {
$this->options = $options;
$this->client = $this->setup($options);
}
/**
* Setup is a protected method to setup the client.
*
* The functionality would typically be in the constructor. It was broken out
* to be used by the constructor and serialization process.
*
* @param array $options The options as passed to the constructor.
* @return mixed The Guzzle based client.
*/
protected function setup(array $options = []) {
// If no client has been passed in we create one. This is the default case.
if (!isset($options['client']) || is_string($options['client'])) {
$defaultOptions = ['defaults' => []];
if (isset($options['headers'])) {
$defaultOptions['defaults']['headers'] = $options['headers'];
}
if (isset($options['proxy'])) {
$defaultOptions['defaults']['proxy'] = $options['proxy'];
}
if (isset($options['debug'])) {
$defaultOptions['defaults']['debug'] = $options['debug'];
}
if (isset($options['ssl'])) {
$defaultOptions['defaults']['verify'] = $options['ssl_verify'];
}
if (isset($options['timeout'])) {
$defaultOptions['defaults']['timeout'] = $options['timeout'];
}
// Add a user agent if not already specificed.
if (!isset($defaultOptions['defaults']['headers']['User-Agent'])) {
$defaultOptions['defaults']['headers']['User-Agent'] = self::HTTP_USER_AGENT . self::HTTP_USER_AGENT_SUFFIX;
}
$clientClass = '\GuzzleHttp\Client';
if (isset($options['client']) && is_string($options['client'])) {
$clientClass = $options['client'];
}
$options['client'] = new $clientClass($defaultOptions);
$this->client = $this->setup($options);
}
return $options['client'];
}
/**
* Setup is a protected method to setup the client.
*
* The functionality would typically be in the constructor. It was broken out
* to be used by the constructor and serialization process.
*
* @param array $options The options as passed to the constructor.
* @return mixed The Guzzle based client.
*/
protected function setup(array $options = [])
{
// If no client has been passed in we create one. This is the default case.
if (!isset($options['client']) || is_string($options['client'])) {
$defaultOptions = ['defaults' => []];
if (isset($options['headers'])) {
$defaultOptions['defaults']['headers'] = $options['headers'];
}
if (isset($options['proxy'])) {
$defaultOptions['defaults']['proxy'] = $options['proxy'];
}
if (isset($options['debug'])) {
$defaultOptions['defaults']['debug'] = $options['debug'];
}
if (isset($options['ssl'])) {
$defaultOptions['defaults']['verify'] = $options['ssl_verify'];
}
if (isset($options['timeout'])) {
$defaultOptions['defaults']['timeout'] = $options['timeout'];
}
/**
* {@inheritdoc}
*/
public function doRequest($uri, $method = 'GET', array $headers = [], $body = '') {
// Add a user agent if not already specificed.
if (!isset($defaultOptions['defaults']['headers']['User-Agent'])) {
$defaultOptions['defaults']['headers']['User-Agent'] = self::HTTP_USER_AGENT . self::HTTP_USER_AGENT_SUFFIX;
}
$options = [
'headers' => $headers,
'body' => $body,
];
$clientClass = '\GuzzleHttp\Client';
if (isset($options['client']) && is_string($options['client'])) {
$clientClass = $options['client'];
}
// We use our own exceptions for errors to provide a common exception
// interface to applications implementing the SDK.
try {
$response = $this->client->send($this->client->createRequest($method, $uri, $options));
} catch(\GuzzleHttp\Exception\ClientException $e) {
$this->handleException($e);
} catch(\GuzzleHttp\Exception\ServerException $e) {
$this->handleException($e);
} catch(\GuzzleHttp\Exception\RequestException $e) {
$this->handleException($e);
$options['client'] = new $clientClass($defaultOptions);
}
return $options['client'];
}
return $response;
}
/**
* {@inheritdoc}
*/
public function doRequest($uri, $method = 'GET', array $headers = [], $body = '')
{
$options = [
'headers' => $headers,
'body' => $body,
];
/**
* {@inheritdoc}
*/
public function doRequestWithResource($uri, $method, array $headers = [], $resource) {
// We use our own exceptions for errors to provide a common exception
// interface to applications implementing the SDK.
try {
$response = $this->client->send($this->client->createRequest($method, $uri, $options));
} catch (\GuzzleHttp\Exception\ClientException $e) {
$this->handleException($e);
} catch (\GuzzleHttp\Exception\ServerException $e) {
$this->handleException($e);
} catch (\GuzzleHttp\Exception\RequestException $e) {
$this->handleException($e);
}
// Guzzle messes with the resource in such a manner that it can no longer be
// used by something else after the fact. So, we clone the content into
// temporary stream.
$tmp = $out = fopen('php://temp', 'wb+');
stream_copy_to_stream($resource, $tmp);
$options = [
'headers' => $headers,
'body' => $tmp,
];
// We use our own exceptions for errors to provide a common exception
// interface to applications implementing the SDK.
try {
$response = $this->client->send($this->client->createRequest($method, $uri, $options));
} catch(\GuzzleHttp\Exception\ClientException $e) {
$this->handleException($e);
} catch(\GuzzleHttp\Exception\ServerException $e) {
$this->handleException($e);
} catch(\GuzzleHttp\Exception\RequestException $e) {
$this->handleException($e);
return $response;
}
return $response;
}
/**
* {@inheritdoc}
*/
public function doRequestWithResource($uri, $method, array $headers = [], $resource)
{
// Guzzle messes with the resource in such a manner that it can no longer be
// used by something else after the fact. So, we clone the content into
// temporary stream.
$tmp = $out = fopen('php://temp', 'wb+');
stream_copy_to_stream($resource, $tmp);
/**
* Handle errors on a response.
*
* @param mixed The Guzzle exception.
*
* @return \OpenStack\Transport\ResponseInterface The response.
*
* @throws \OpenStack\Transport\ForbiddenException
* @throws \OpenStack\Transport\UnauthorizedException
* @throws \OpenStack\Transport\FileNotFoundException
* @throws \OpenStack\Transport\MethodNotAllowedException
* @throws \OpenStack\Transport\ConflictException
* @throws \OpenStack\Transport\LengthRequiredException
* @throws \OpenStack\Transport\UnprocessableEntityException
* @throws \OpenStack\Transport\ServerException
* @throws \OpenStack\Exception
*/
protected function handleException($exception) {
$options = [
'headers' => $headers,
'body' => $tmp,
];
$response = $exception->getResponse();
$request = $exception->getRequest();
// We use our own exceptions for errors to provide a common exception
// interface to applications implementing the SDK.
try {
$response = $this->client->send($this->client->createRequest($method, $uri, $options));
} catch (\GuzzleHttp\Exception\ClientException $e) {
$this->handleException($e);
} catch (\GuzzleHttp\Exception\ServerException $e) {
$this->handleException($e);
} catch (\GuzzleHttp\Exception\RequestException $e) {
$this->handleException($e);
}
if (!is_null($response)) {
$code = $response->getStatusCode();
switch ($code) {
case '403':
throw new \OpenStack\Transport\ForbiddenException($response->getReasonPhrase());
case '401':
throw new \OpenStack\Transport\UnauthorizedException($response->getReasonPhrase());
case '404':
throw new \OpenStack\Transport\FileNotFoundException($response->getReasonPhrase() . " ({$response->getEffectiveUrl()})");
case '405':
throw new \OpenStack\Transport\MethodNotAllowedException($response->getReasonPhrase() . " ({$request->getMethod()} {$response->getEffectiveUrl()})");
case '409':
throw new \OpenStack\Transport\ConflictException($response->getReasonPhrase());
case '412':
throw new \OpenStack\Transport\LengthRequiredException($response->getReasonPhrase());
case '422':
throw new \OpenStack\Transport\UnprocessableEntityException($response->getReasonPhrase());
case '500':
throw new \OpenStack\Transport\ServerException($response->getReasonPhrase());
default:
throw new \OpenStack\Exception($response->getReasonPhrase());
}
}
// The exception was one other than a HTTP error. For example, a HTTP layer
// timeout occurred.
else {
throw new \OpenStack\Exception($exception->getMessage());
return $response;
}
return $response;
}
/**
* Handle errors on a response.
*
* @param mixed The Guzzle exception.
*
* @return \OpenStack\Transport\ResponseInterface The response.
*
* @throws \OpenStack\Transport\ForbiddenException
* @throws \OpenStack\Transport\UnauthorizedException
* @throws \OpenStack\Transport\FileNotFoundException
* @throws \OpenStack\Transport\MethodNotAllowedException
* @throws \OpenStack\Transport\ConflictException
* @throws \OpenStack\Transport\LengthRequiredException
* @throws \OpenStack\Transport\UnprocessableEntityException
* @throws \OpenStack\Transport\ServerException
* @throws \OpenStack\Exception
*/
protected function handleException($exception)
{
$response = $exception->getResponse();
$request = $exception->getRequest();
public function serialize() {
$data = ['options' => $this->options];
return serialize($data);
}
if (!is_null($response)) {
$code = $response->getStatusCode();
public function unserialize($data) {
$vals = unserialize($data);
$this->options = $vals['options'];
$this->client = $this->setup($vals['options']);
}
switch ($code) {
case '403':
throw new \OpenStack\Transport\ForbiddenException($response->getReasonPhrase());
case '401':
throw new \OpenStack\Transport\UnauthorizedException($response->getReasonPhrase());
case '404':
throw new \OpenStack\Transport\FileNotFoundException($response->getReasonPhrase() . " ({$response->getEffectiveUrl()})");
case '405':
throw new \OpenStack\Transport\MethodNotAllowedException($response->getReasonPhrase() . " ({$request->getMethod()} {$response->getEffectiveUrl()})");
case '409':
throw new \OpenStack\Transport\ConflictException($response->getReasonPhrase());
case '412':
throw new \OpenStack\Transport\LengthRequiredException($response->getReasonPhrase());
case '422':
throw new \OpenStack\Transport\UnprocessableEntityException($response->getReasonPhrase());
case '500':
throw new \OpenStack\Transport\ServerException($response->getReasonPhrase());
default:
throw new \OpenStack\Exception($response->getReasonPhrase());
}
}
// The exception was one other than a HTTP error. For example, a HTTP layer
// timeout occurred.
else {
throw new \OpenStack\Exception($exception->getMessage());
}
return $response;
}
public function serialize()
{
$data = ['options' => $this->options];
return serialize($data);
}
public function unserialize($data)
{
$vals = unserialize($data);
$this->options = $vals['options'];
$this->client = $this->setup($vals['options']);
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
namespace OpenStack\Transport;

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
namespace OpenStack\Transport;

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* This file contains the response interface for a HTTP request.
@ -26,157 +26,158 @@ namespace OpenStack\Transport;
* This interface is equivalent to the proposed PHP FIG http message interface
* for a response that can be found at https://github.com/php-fig/fig-standards/blob/master/proposed/http-message.md#33-psrhttpresponseinterface
*/
interface ResponseInterface {
/**
* Gets the response Status-Code, a 3-digit integer result code of the
* server's attempt to understand and satisfy the request.
*
* @return integer Status code.
*/
public function getStatusCode();
interface ResponseInterface
{
/**
* Gets the response Status-Code, a 3-digit integer result code of the
* server's attempt to understand and satisfy the request.
*
* @return integer Status code.
*/
public function getStatusCode();
/**
* Gets the response Reason-Phrase, a short textual description of the
* Status-Code.
*
* Because a Reason-Phrase is not a required element in response
* Status-Line, the Reason-Phrase value MAY be null. Implementations MAY
* choose to return the default RFC 2616 recommended reason phrase for the
* response's Status-Code.
*
* @return string|null Reason phrase, or null if unknown.
*/
public function getReasonPhrase();
/**
* Gets the HTTP protocol version.
*
* @return string HTTP protocol version.
*/
public function getProtocolVersion();
/**
* Gets the response Reason-Phrase, a short textual description of the
* Status-Code.
*
* Because a Reason-Phrase is not a required element in response
* Status-Line, the Reason-Phrase value MAY be null. Implementations MAY
* choose to return the default RFC 2616 recommended reason phrase for the
* response's Status-Code.
*
* @return string|null Reason phrase, or null if unknown.
*/
public function getReasonPhrase();
/**
* Gets the body of the message.
*
* @return StreamInterface|null Returns the body, or null if not set.
*/
public function getBody();
/**
* Gets the HTTP protocol version.
*
* @return string HTTP protocol version.
*/
public function getProtocolVersion();
/**
* Sets the body of the message.
*
* The body MUST be a StreamInterface object. Setting the body to null MUST
* remove the existing body.
*
* @param StreamInterface|null $body Body.
*
* @return self Returns the message.
*
* @throws \InvalidArgumentException When the body is not valid.
*/
public function setBody(StreamInterface $body = null);
/**
* Gets the body of the message.
*
* @return StreamInterface|null Returns the body, or null if not set.
*/
public function getBody();
/**
* Gets all message headers.
*
* The keys represent the header name as it will be sent over the wire, and
* each value is an array of strings associated with the header.
*
* // Represent the headers as a string
* foreach ($message->getHeaders() as $name => $values) {
* echo $name . ": " . implode(", ", $values);
* }
*
* @return array Returns an associative array of the message's headers.
*/
public function getHeaders();
/**
* Sets the body of the message.
*
* The body MUST be a StreamInterface object. Setting the body to null MUST
* remove the existing body.
*
* @param StreamInterface|null $body Body.
*
* @return self Returns the message.
*
* @throws \InvalidArgumentException When the body is not valid.
*/
public function setBody(StreamInterface $body = null);
/**
* Checks if a header exists by the given case-insensitive name.
*
* @param string $header Case-insensitive header name.
*
* @return bool Returns true if any header names match the given header
* name using a case-insensitive string comparison. Returns false if
* no matching header name is found in the message.
*/
public function hasHeader($header);
/**
* Gets all message headers.
*
* The keys represent the header name as it will be sent over the wire, and
* each value is an array of strings associated with the header.
*
* // Represent the headers as a string
* foreach ($message->getHeaders() as $name => $values) {
* echo $name . ": " . implode(", ", $values);
* }
*
* @return array Returns an associative array of the message's headers.
*/
public function getHeaders();
/**
* Retrieve a header by the given case-insensitive name.
*
* By default, this method returns all of the header values of the given
* case-insensitive header name as a string concatenated together using
* a comma. Because some header should not be concatenated together using a
* comma, this method provides a Boolean argument that can be used to
* retrieve the associated header values as an array of strings.
*
* @param string $header Case-insensitive header name.
* @param bool $asArray Set to true to retrieve the header value as an
* array of strings.
*
* @return array|string
*/
public function getHeader($header, $asArray = false);
/**
* Checks if a header exists by the given case-insensitive name.
*
* @param string $header Case-insensitive header name.
*
* @return bool Returns true if any header names match the given header
* name using a case-insensitive string comparison. Returns false if
* no matching header name is found in the message.
*/
public function hasHeader($header);
/**
* Sets a header, replacing any existing values of any headers with the
* same case-insensitive name.
*
* The header values MUST be a string or an array of strings.
*
* @param string $header Header name
* @param string|array $value Header value(s)
*
* @return self Returns the message.
*/
public function setHeader($header, $value);
/**
* Retrieve a header by the given case-insensitive name.
*
* By default, this method returns all of the header values of the given
* case-insensitive header name as a string concatenated together using
* a comma. Because some header should not be concatenated together using a
* comma, this method provides a Boolean argument that can be used to
* retrieve the associated header values as an array of strings.
*
* @param string $header Case-insensitive header name.
* @param bool $asArray Set to true to retrieve the header value as an
* array of strings.
*
* @return array|string
*/
public function getHeader($header, $asArray = false);
/**
* Sets headers, replacing any headers that have already been set on the
* message.
*
* The array keys MUST be a string. The array values must be either a
* string or an array of strings.
*
* @param array $headers Headers to set.
*
* @return self Returns the message.
*/
public function setHeaders(array $headers);
/**
* Sets a header, replacing any existing values of any headers with the
* same case-insensitive name.
*
* The header values MUST be a string or an array of strings.
*
* @param string $header Header name
* @param string|array $value Header value(s)
*
* @return self Returns the message.
*/
public function setHeader($header, $value);
/**
* Appends a header value to any existing values associated with the
* given header name.
*
* @param string $header Header name to add
* @param string $value Value of the header
*
* @return self
*/
public function addHeader($header, $value);
/**
* Sets headers, replacing any headers that have already been set on the
* message.
*
* The array keys MUST be a string. The array values must be either a
* string or an array of strings.
*
* @param array $headers Headers to set.
*
* @return self Returns the message.
*/
public function setHeaders(array $headers);
/**
* Merges in an associative array of headers.
*
* Each array key MUST be a string representing the case-insensitive name
* of a header. Each value MUST be either a string or an array of strings.
* For each value, the value is appended to any existing header of the same
* name, or, if a header does not already exist by the given name, then the
* header is added.
*
* @param array $headers Associative array of headers to add to the message
*
* @return self
*/
public function addHeaders(array $headers);
/**
* Appends a header value to any existing values associated with the
* given header name.
*
* @param string $header Header name to add
* @param string $value Value of the header
*
* @return self
*/
public function addHeader($header, $value);
/**
* Remove a specific header by case-insensitive name.
*
* @param string $header HTTP header to remove
*
* @return self
*/
public function removeHeader($header);
}
/**
* Merges in an associative array of headers.
*
* Each array key MUST be a string representing the case-insensitive name
* of a header. Each value MUST be either a string or an array of strings.
* For each value, the value is appended to any existing header of the same
* name, or, if a header does not already exist by the given name, then the
* header is added.
*
* @param array $headers Associative array of headers to add to the message
*
* @return self
*/
public function addHeaders(array $headers);
/**
* Remove a specific header by case-insensitive name.
*
* @param string $header HTTP header to remove
*
* @return self
*/
public function removeHeader($header);
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
namespace OpenStack\Transport;

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* The authorization exception.

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
namespace OpenStack\Transport;

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* This is a simple command-line test for authentication.
@ -27,10 +27,10 @@ use \OpenStack\Storage\ObjectStorage;
use \OpenStack\Services\IdentityService;
$config = array(
'transport' => '\OpenStack\Transport\PHPStreamTransport',
'transport.timeout' => 240,
//'transport.debug' => 1,
'transport.ssl.verify' => 0,
'transport' => '\OpenStack\Transport\PHPStreamTransport',
'transport.timeout' => 240,
//'transport.debug' => 1,
'transport.ssl.verify' => 0,
);
\OpenStack\Autoloader::useAutoloader();
@ -48,14 +48,13 @@ In both cases, you must supply a URL to the Identity Services endpoint.
$usage = "php {$argv[0]} USERNAME PASSWORD URL [TENANT_ID]";
if ($argc > 1 && $argv[1] == '--help') {
print PHP_EOL . "\t" . $usage . PHP_EOL;
print PHP_EOL . $help . PHP_EOL;
exit(1);
}
elseif ($argc < 4) {
print 'USERNAME, PASSWORD, and URL are all required.' . PHP_EOL;
print $usage . PHP_EOL;
exit(1);
print PHP_EOL . "\t" . $usage . PHP_EOL;
print PHP_EOL . $help . PHP_EOL;
exit(1);
} elseif ($argc < 4) {
print 'USERNAME, PASSWORD, and URL are all required.' . PHP_EOL;
print $usage . PHP_EOL;
exit(1);
}
$offset = 0;
@ -66,7 +65,7 @@ $uri = $argv[3 + $offset];
$tenantId = NULL;
if (!empty($argv[4 + $offset])) {
$tenantId = $argv[4 + $offset];
$tenantId = $argv[4 + $offset];
}
/*
@ -79,8 +78,8 @@ $cs = new IdentityService($uri);
$token = $cs->authenticateAsUser($user, $password, $tenantId);
if (empty($token)) {
print "Authentication seemed to succeed, but no token was returned." . PHP_EOL;
exit(1);
print "Authentication seemed to succeed, but no token was returned." . PHP_EOL;
exit(1);
}
$t = "You are logged in as %s with token %s (good until %s)." . PHP_EOL;
@ -93,7 +92,7 @@ print "The following services are available on this user:" . PHP_EOL;
$services = $cs->serviceCatalog();
foreach ($services as $service) {
print "\t" . $service['name'] . PHP_EOL;
print "\t" . $service['name'] . PHP_EOL;
}
//print_r($services);

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Base test case.
@ -25,233 +25,232 @@
* This group contains all of the unit testing classes.
*/
namespace OpenStack\Tests;
/**
* @ingroup Tests
*/
class TestCase extends \PHPUnit_Framework_TestCase {
class TestCase extends \PHPUnit_Framework_TestCase
{
public static $settings = array();
public static $settings = array();
public static $ostore = NULL;
public static $ostore = NULL;
/**
* The IdentityService instance.
*/
public static $ident;
/**
* The IdentityService instance.
*/
public static $ident;
public static $httpClient = NULL;
public static $httpClient = NULL;
//public function __construct(score $score = NULL, locale $locale = NULL, adapter $adapter = NULL) {
public static function setUpBeforeClass()
{
global $bootstrap_settings;
//public function __construct(score $score = NULL, locale $locale = NULL, adapter $adapter = NULL) {
public static function setUpBeforeClass() {
global $bootstrap_settings;
if (!isset($bootstrap_settings)) {
$bootstrap_settings = array();
}
self::$settings = $bootstrap_settings;
if (!isset($bootstrap_settings)) {
$bootstrap_settings = array();
}
self::$settings = $bootstrap_settings;
//$this->setTestNamespace('Tests\Units');
if (file_exists('test/settings.ini')) {
self::$settings += parse_ini_file('test/settings.ini');
} else {
throw new \Exception('Could not access test/settings.ini');
}
\OpenStack\Autoloader::useAutoloader();
\OpenStack\Bootstrap::setConfiguration(self::$settings);
//$this->setTestNamespace('Tests\Units');
if (file_exists('test/settings.ini')) {
self::$settings += parse_ini_file('test/settings.ini');
}
else {
throw new \Exception('Could not access test/settings.ini');
//parent::__construct($score, $locale, $adapter);
}
/**
* Get a configuration value.
*
* Optionally, specify a default value to be used
* if none was found.
*/
public static function conf($name, $default = NULL)
{
if (isset(self::$settings[$name])) {
return self::$settings[$name];
}
\OpenStack\Autoloader::useAutoloader();
\OpenStack\Bootstrap::setConfiguration(self::$settings);
//parent::__construct($score, $locale, $adapter);
}
/**
* Get a configuration value.
*
* Optionally, specify a default value to be used
* if none was found.
*/
public static function conf($name, $default = NULL) {
if (isset(self::$settings[$name])) {
return self::$settings[$name];
return $default;
}
return $default;
}
protected $containerFixture = NULL;
protected $containerFixture = NULL;
/**
* @deprecated
*/
protected function swiftAuth() {
$user = self::$settings['openstack.swift.account'];
$key = self::$settings['openstack.swift.key'];
$url = self::$settings['openstack.swift.url'];
//$url = self::$settings['openstack.identity.url'];
return \OpenStack\Storage\ObjectStorage::newFromSwiftAuth($user, $key, $url, $this->getTransportClient());
}
/**
* Get a handle to an IdentityService object.
*
* Authentication is performed, and the returned
* service has its tenant ID set already.
*
* <?php
* // Get the current token.
* $this->identity()->token();
* ?>
*/
protected function identity($reset = FALSE) {
if ($reset || empty(self::$ident)) {
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$url = self::conf('openstack.identity.url');
$is = new \OpenStack\Services\IdentityService($url);
$token = $is->authenticateAsUser($user, $pass, $tenantId);
self::$ident = $is;
}
return self::$ident;
}
protected function objectStore($reset = FALSE) {
if ($reset || empty(self::$ostore)) {
$ident = $this->identity($reset);
$objStore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
self::$ostore = $objStore;
/**
* @deprecated
*/
protected function swiftAuth()
{
$user = self::$settings['openstack.swift.account'];
$key = self::$settings['openstack.swift.key'];
$url = self::$settings['openstack.swift.url'];
//$url = self::$settings['openstack.identity.url'];
return \OpenStack\Storage\ObjectStorage::newFromSwiftAuth($user, $key, $url, $this->getTransportClient());
}
return self::$ostore;
}
/**
* Get a handle to an IdentityService object.
*
* Authentication is performed, and the returned
* service has its tenant ID set already.
*
* <?php
* // Get the current token.
* $this->identity()->token();
* ?>
*/
protected function identity($reset = FALSE)
{
if ($reset || empty(self::$ident)) {
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$url = self::conf('openstack.identity.url');
/**
* Get a container from the server.
*/
protected function containerFixture() {
$is = new \OpenStack\Services\IdentityService($url);
if (empty($this->containerFixture)) {
$store = $this->objectStore();
$cname = self::$settings['openstack.swift.container'];
$token = $is->authenticateAsUser($user, $pass, $tenantId);
try {
$store->createContainer($cname);
$this->containerFixture = $store->container($cname);
self::$ident = $is;
}
return self::$ident;
}
protected function objectStore($reset = FALSE)
{
if ($reset || empty(self::$ostore)) {
$ident = $this->identity($reset);
$objStore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
self::$ostore = $objStore;
}
return self::$ostore;
}
/**
* Get a container from the server.
*/
protected function containerFixture()
{
if (empty($this->containerFixture)) {
$store = $this->objectStore();
$cname = self::$settings['openstack.swift.container'];
try {
$store->createContainer($cname);
$this->containerFixture = $store->container($cname);
}
// This is why PHP needs 'finally'.
catch (\Exception $e) {
// Delete the container.
$store->deleteContainer($cname);
throw $e;
}
}
return $this->containerFixture;
}
/**
* Clear and destroy a container.
*
* Destroy all of the files in a container, then destroy the
* container.
*
* If the container doesn't exist, this will silently return.
*
* @param string $cname The name of the container.
*/
protected function eradicateContainer($cname)
{
$store = $this->objectStore();
try {
$container = $store->container($cname);
}
// The container was never created.
catch (\OpenStack\Transport\FileNotFoundException $e) {
return;
}
foreach ($container as $object) {
try {
$container->delete($object->name());
} catch (\Exception $e) {}
}
}
// This is why PHP needs 'finally'.
catch (\Exception $e) {
// Delete the container.
$store->deleteContainer($cname);
throw $e;
}
}
return $this->containerFixture;
}
/**
* Retrieve the HTTP Transport Client
*
* @return \OpenStack\Transport\ClientInterface A transport client.
*/
public static function getTransportClient()
{
if (is_null(self::$httpClient)) {
$options = [];
if (isset(self::$settings['transport.proxy'])) {
$options['proxy'] = self::$settings['transport.proxy'];
}
if (isset(self::$settings['transport.debug'])) {
$options['debug'] = self::$settings['transport.debug'];
}
if (isset(self::$settings['transport.ssl.verify'])) {
$options['ssl_verify'] = self::$settings['transport.ssl.verify'];
}
if (isset(self::$settings['transport.timeout'])) {
$options['timeout'] = self::$settings['transport.timeout'];
}
/**
* Clear and destroy a container.
*
* Destroy all of the files in a container, then destroy the
* container.
*
* If the container doesn't exist, this will silently return.
*
* @param string $cname The name of the container.
*/
protected function eradicateContainer($cname) {
$store = $this->objectStore();
try {
$container = $store->container($cname);
}
// The container was never created.
catch (\OpenStack\Transport\FileNotFoundException $e) {
return;
self::$httpClient = new self::$settings['transport']($options);
}
return self::$httpClient;
}
foreach ($container as $object) {
try {
$container->delete($object->name());
}
catch (\Exception $e) {}
/**
* Destroy a container fixture.
*
* This should be called in any method that uses containerFixture().
*/
protected function destroyContainerFixture()
{
$store = $this->objectStore();
$cname = self::$settings['openstack.swift.container'];
try {
$container = $store->container($cname);
}
// The container was never created.
catch (\OpenStack\Transport\FileNotFoundException $e) {
return;
}
foreach ($container as $object) {
try {
$container->delete($object->name());
} catch (\Exception $e) {
syslog(LOG_WARNING, $e);
}
}
$store->deleteContainer($cname);
}
$store->deleteContainer($cname);
}
/**
* Retrieve the HTTP Transport Client
*
* @return \OpenStack\Transport\ClientInterface A transport client.
*/
public static function getTransportClient() {
if (is_null(self::$httpClient)) {
$options = [];
if (isset(self::$settings['transport.proxy'])) {
$options['proxy'] = self::$settings['transport.proxy'];
}
if (isset(self::$settings['transport.debug'])) {
$options['debug'] = self::$settings['transport.debug'];
}
if (isset(self::$settings['transport.ssl.verify'])) {
$options['ssl_verify'] = self::$settings['transport.ssl.verify'];
}
if (isset(self::$settings['transport.timeout'])) {
$options['timeout'] = self::$settings['transport.timeout'];
}
self::$httpClient = new self::$settings['transport']($options);
}
return self::$httpClient;
}
/**
* Destroy a container fixture.
*
* This should be called in any method that uses containerFixture().
*/
protected function destroyContainerFixture() {
$store = $this->objectStore();
$cname = self::$settings['openstack.swift.container'];
try {
$container = $store->container($cname);
}
// The container was never created.
catch (\OpenStack\Transport\FileNotFoundException $e) {
return;
}
foreach ($container as $object) {
try {
$container->delete($object->name());
}
catch (\Exception $e) {
syslog(LOG_WARNING, $e);
}
}
$store->deleteContainer($cname);
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Unit tests for ObjectStorage ACLs.
@ -25,182 +25,193 @@ use \OpenStack\Storage\ObjectStorage\ACL;
/**
* @ingroup Tests
*/
class ACLTest extends \OpenStack\Tests\TestCase {
class ACLTest extends \OpenStack\Tests\TestCase
{
public function testConstructor()
{
$acl = new ACL();
$this->assertEmpty($acl->rules());
public function testConstructor() {
$acl = new ACL();
$this->assertEmpty($acl->rules());
}
}
public function testAddAccount()
{
$acl = new ACL();
public function testAddAccount() {
$acl = new ACL();
$acl->addAccount(ACL::READ, 'test');
$acl->addAccount(ACL::READ, 'test');
$rules = $acl->rules();
$rules = $acl->rules();
$this->assertEquals(1, count($rules));
$this->assertEquals(1, count($rules));
$rule = array_shift($rules);
$rule = array_shift($rules);
$this->assertEquals(ACL::READ, $rule['mask']);
$this->assertEquals('test', $rule['account']);
$this->assertEquals(ACL::READ, $rule['mask']);
$this->assertEquals('test', $rule['account']);
// Test with user
$acl = new ACL();
$acl->addAccount(ACL::WRITE, 'admin', 'earnie');
$rules = $acl->rules();
$rule = array_shift($rules);
// Test with user
$acl = new ACL();
$acl->addAccount(ACL::WRITE, 'admin', 'earnie');
$rules = $acl->rules();
$rule = array_shift($rules);
$this->assertEquals(ACL::WRITE, $rule['mask']);
$this->assertEquals('admin', $rule['account']);
$this->assertEquals('earnie', $rule['user']);
$this->assertEquals(ACL::WRITE, $rule['mask']);
$this->assertEquals('admin', $rule['account']);
$this->assertEquals('earnie', $rule['user']);
// Test with multiple users:
$acl = new ACL();
$acl->addAccount(ACL::WRITE, 'admin', array('earnie', 'bert'));
$rules = $acl->rules();
$rule = array_shift($rules);
// Test with multiple users:
$acl = new ACL();
$acl->addAccount(ACL::WRITE, 'admin', array('earnie', 'bert'));
$rules = $acl->rules();
$rule = array_shift($rules);
$this->assertEquals(ACL::WRITE, $rule['mask']);
$this->assertEquals('admin', $rule['account']);
$this->assertEquals('earnie', $rule['user'][0]);
$this->assertEquals('bert', $rule['user'][1]);
$this->assertEquals(ACL::WRITE, $rule['mask']);
$this->assertEquals('admin', $rule['account']);
$this->assertEquals('earnie', $rule['user'][0]);
$this->assertEquals('bert', $rule['user'][1]);
}
}
public function testAddReferrer()
{
$acl = new ACL();
$acl->addReferrer(ACL::READ, '.example.com');
$acl->addReferrer(ACL::READ_WRITE, '-bad.example.com');
public function testAddReferrer() {
$acl = new ACL();
$acl->addReferrer(ACL::READ, '.example.com');
$acl->addReferrer(ACL::READ_WRITE, '-bad.example.com');
$rules = $acl->rules();
$rules = $acl->rules();
$this->assertEquals(2, count($rules));
$this->assertEquals(2, count($rules));
$first = array_shift($rules);
$this->assertEquals(ACL::READ, $first['mask']);
$this->assertEquals('.example.com', $first['host']);
}
$first = array_shift($rules);
$this->assertEquals(ACL::READ, $first['mask']);
$this->assertEquals('.example.com', $first['host']);
}
public function testAllowListings()
{
$acl = new ACL();
$acl->allowListings();
$rules = $acl->rules();
public function testAllowListings() {
$acl = new ACL();
$acl->allowListings();
$rules = $acl->rules();
$this->assertEquals(1, count($rules));
$this->assertTrue($rules[0]['rlistings']);
$this->assertEquals(ACL::READ, $rules[0]['mask']);
}
$this->assertEquals(1, count($rules));
$this->assertTrue($rules[0]['rlistings']);
$this->assertEquals(ACL::READ, $rules[0]['mask']);
}
public function testHeaders()
{
$acl = new ACL();
$acl->addAccount(ACL::READ_WRITE, 'test');
public function testHeaders() {
$acl = new ACL();
$acl->addAccount(ACL::READ_WRITE, 'test');
$headers = $acl->headers();
$headers = $acl->headers();
$this->assertEquals(2, count($headers));
$read = $headers[ACL::HEADER_READ];
$write = $headers[ACL::HEADER_WRITE];
$this->assertEquals(2, count($headers));
$read = $headers[ACL::HEADER_READ];
$write = $headers[ACL::HEADER_WRITE];
$this->assertEquals('test', $read);
$this->assertEquals('test', $write);
$this->assertEquals('test', $read);
$this->assertEquals('test', $write);
// Test hostname rules, which should only appear in READ.
$acl = new ACL();
$acl->addReferrer(ACL::READ_WRITE, '.example.com');
$headers = $acl->headers();
// Test hostname rules, which should only appear in READ.
$acl = new ACL();
$acl->addReferrer(ACL::READ_WRITE, '.example.com');
$headers = $acl->headers();
$this->assertEquals(1, count($headers), print_r($headers, TRUE));
$read = $headers[ACL::HEADER_READ];
$this->assertEquals(1, count($headers), print_r($headers, TRUE));
$read = $headers[ACL::HEADER_READ];
$this->assertEquals('.r:.example.com', $read);
}
$this->assertEquals('.r:.example.com', $read);
}
public function testToString()
{
$acl = new ACL();
$acl->addReferrer(ACL::READ_WRITE, '.example.com');
public function testToString() {
$acl = new ACL();
$acl->addReferrer(ACL::READ_WRITE, '.example.com');
$str = (string) $acl;
$str = (string) $acl;
$this->assertEquals('X-Container-Read: .r:.example.com', $str);
}
$this->assertEquals('X-Container-Read: .r:.example.com', $str);
}
public function testMakePublic()
{
$acl = (string) ACL::makePublic();
public function testMakePublic() {
$acl = (string) ACL::makePublic();
$this->assertEquals('X-Container-Read: .r:*,.rlistings', $acl);
}
$this->assertEquals('X-Container-Read: .r:*,.rlistings', $acl);
}
public function testMakeNonPublic()
{
$acl = (string) ACL::makeNonPublic();
public function testMakeNonPublic() {
$acl = (string) ACL::makeNonPublic();
$this->assertEmpty($acl);
}
$this->assertEmpty($acl);
}
public function testNewFromHeaders()
{
$headers = array(
ACL::HEADER_READ => '.r:.example.com,.rlistings,.r:-*.evil.net',
ACL::HEADER_WRITE => 'testact2, testact3:earnie, .rlistings ',
);
public function testNewFromHeaders() {
$headers = array(
ACL::HEADER_READ => '.r:.example.com,.rlistings,.r:-*.evil.net',
ACL::HEADER_WRITE => 'testact2, testact3:earnie, .rlistings ',
);
$acl = ACL::newFromHeaders($headers);
$acl = ACL::newFromHeaders($headers);
$rules = $acl->rules();
$rules = $acl->rules();
$this->assertEquals(6, count($rules));
$this->assertEquals(6, count($rules));
// Yay, now we get to test each one.
// Yay, now we get to test each one.
$this->assertEquals(ACL::READ, $rules[0]['mask']);
$this->assertEquals('.example.com', $rules[0]['host']);
$this->assertTrue($rules[1]['rlistings']);
$this->assertEquals('-*.evil.net', $rules[2]['host']);
$this->assertEquals(ACL::READ, $rules[0]['mask']);
$this->assertEquals('.example.com', $rules[0]['host']);
$this->assertTrue($rules[1]['rlistings']);
$this->assertEquals('-*.evil.net', $rules[2]['host']);
$this->assertEquals(ACL::WRITE, $rules[3]['mask']);
$this->assertEquals('testact2', $rules[3]['account']);
$this->assertEquals('testact3', $rules[4]['account']);
$this->assertEquals('earnie', $rules[4]['user']);
$this->assertTrue($rules[5]['rlistings']);
$this->assertEquals(ACL::WRITE, $rules[3]['mask']);
$this->assertEquals('testact2', $rules[3]['account']);
$this->assertEquals('testact3', $rules[4]['account']);
$this->assertEquals('earnie', $rules[4]['user']);
$this->assertTrue($rules[5]['rlistings']);
// Final canary:
$headers = $acl->headers();
$read = $headers[ACL::HEADER_READ];
$write = $headers[ACL::HEADER_WRITE];
// Final canary:
$headers = $acl->headers();
$read = $headers[ACL::HEADER_READ];
$write = $headers[ACL::HEADER_WRITE];
$this->assertEquals('.r:.example.com,.rlistings,.r:-*.evil.net', $read);
// Note that the spurious .rlistings was removed.
$this->assertEquals('testact2,testact3:earnie', $write);
$this->assertEquals('.r:.example.com,.rlistings,.r:-*.evil.net', $read);
// Note that the spurious .rlistings was removed.
$this->assertEquals('testact2,testact3:earnie', $write);
}
}
public function testIsNonPublic()
{
$acl = new ACL();
public function testIsNonPublic() {
$acl = new ACL();
$this->assertTrue($acl->isNonPublic());
$this->assertTrue($acl->isNonPublic());
$acl->addReferrer(ACL::READ, '*.evil.net');
$this->assertFalse($acl->isNonPublic());
$acl->addReferrer(ACL::READ, '*.evil.net');
$this->assertFalse($acl->isNonPublic());
$acl = ACL::makeNonPublic();
$this->assertTrue($acl->isNonPublic());
}
$acl = ACL::makeNonPublic();
$this->assertTrue($acl->isNonPublic());
}
public function testIsPublic()
{
$acl = new ACL();
public function testIsPublic() {
$acl = new ACL();
$this->assertFalse($acl->isPublic());
$acl->allowListings();
$acl->addReferrer(ACL::READ, '*');
$this->assertFalse($acl->isPublic());
$acl->allowListings();
$acl->addReferrer(ACL::READ, '*');
$this->assertTrue($acl->isPublic());
$this->assertTrue($acl->isPublic());
$acl->addAccount(ACL::WRITE, 'foo', 'bar');
$this->assertTrue($acl->isPublic());
$acl->addAccount(ACL::WRITE, 'foo', 'bar');
$this->assertTrue($acl->isPublic());
$acl = ACL::makePublic();
$this->assertTrue($acl->isPublic());
}
$acl = ACL::makePublic();
$this->assertTrue($acl->isPublic());
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Unit tests for the Autoloader.
@ -22,25 +22,27 @@ namespace OpenStack\Tests;
require_once 'src/OpenStack/Autoloader.php';
require_once 'test/TestCase.php';
class AutoloaderTest extends \OpenStack\Tests\TestCase {
class AutoloaderTest extends \OpenStack\Tests\TestCase
{
/**
* Test the BaseDir.
*/
public function testBasedir()
{
$basedir = \OpenStack\Autoloader::$basedir;
$this->assertRegExp('/OpenStack/', $basedir);
}
/**
* Test the BaseDir.
*/
public function testBasedir() {
$basedir = \OpenStack\Autoloader::$basedir;
$this->assertRegExp('/OpenStack/', $basedir);
}
/**
* Test the autoloader.
*/
public function testAutoloader()
{
\OpenStack\Autoloader::useAutoloader();
/**
* Test the autoloader.
*/
public function testAutoloader() {
\OpenStack\Autoloader::useAutoloader();
// If we can construct a class, we are okay.
$test = new \OpenStack\Exception("TEST");
// If we can construct a class, we are okay.
$test = new \OpenStack\Exception("TEST");
$this->assertInstanceOf('\OpenStack\Exception', $test);
}
$this->assertInstanceOf('\OpenStack\Exception', $test);
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Unit tests for the Bootstrap.
@ -21,12 +21,13 @@ namespace OpenStack\Tests;
require_once 'test/TestCase.php';
class BootstrapTest extends \OpenStack\Tests\TestCase {
/**
* Canary test.
*/
public function testSettings() {
$this->assertTrue(!empty(self::$settings));
}
class BootstrapTest extends \OpenStack\Tests\TestCase
{
/**
* Canary test.
*/
public function testSettings()
{
$this->assertTrue(!empty(self::$settings));
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Unit tests for Containers.
@ -25,414 +25,423 @@ use \OpenStack\Storage\ObjectStorage\Container;
use \OpenStack\Storage\ObjectStorage\Object;
use \OpenStack\Storage\ObjectStorage\ACL;
class ContainerTest extends \OpenStack\Tests\TestCase {
class ContainerTest extends \OpenStack\Tests\TestCase
{
const FILENAME = 'unit-test-dummy.txt';
const FILESTR = 'This is a test.';
const FILENAME = 'unit-test-dummy.txt';
const FILESTR = 'This is a test.';
// The factory functions (newFrom*) are tested in the
// ObjectStorage tests, as they are required there.
// Rather than build a Mock to achieve the same test here,
// we just don't test them again.
// The factory functions (newFrom*) are tested in the
// ObjectStorage tests, as they are required there.
// Rather than build a Mock to achieve the same test here,
// we just don't test them again.
public function testConstructor()
{
$container = new Container('foo');
$this->assertEquals('foo', $container->name());
public function testConstructor() {
$container = new Container('foo');
$this->assertEquals('foo', $container->name());
// These will now cause the system to try to fetch a remote
// container.
//$this->assertEquals(0, $container->bytes());
//$this->assertEquals(0, $container->count());
}
/**
* @expectedException \OpenStack\Exception
*/
public function testConstructorFailure() {
$container = new Container('foo');
$this->assertEquals('foo', $container->name());
// These will now cause the system to try to fetch a remote
// container. This is a failure condition.
$this->assertEquals(0, $container->bytes());
}
public function testCountable() {
// Verify that the interface Countable is properly
// implemented.
$mockJSON = array('count' => 5, 'bytes' => 128, 'name' => 'foo');
$container = Container::newFromJSON($mockJSON, 'fake', 'fake');
$this->assertEquals(5, count($container));
}
const FNAME = 'testSave';
const FCONTENT = 'This is a test.';
const FTYPE = 'application/x-monkey-file';
public function testSave() {
// Clean up anything left.
$this->destroyContainerFixture();
$container = $this->containerFixture();
$obj = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
$obj->setMetadata(array('foo' => '1234'));
$this->assertEquals(self::FCONTENT, $obj->content());
try {
$ret = $container->save($obj);
}
catch (\Exception $e) {
$this->destroyContainerFixture();
throw $e;
// These will now cause the system to try to fetch a remote
// container.
//$this->assertEquals(0, $container->bytes());
//$this->assertEquals(0, $container->count());
}
$this->assertTrue($ret);
}
/**
* @depends testSave
*/
public function testRemoteObject() {
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$this->assertEquals(self::FNAME, $object->name());
$this->assertEquals(self::FTYPE, $object->contentType());
$etag = md5(self::FCONTENT);
$this->assertEquals($etag, $object->eTag());
$md = $object->metadata();
$this->assertEquals(1, count($md));
// Note that headers are normalized remotely to have initial
// caps. Since we have no way of knowing what the original
// metadata casing is, we leave it with initial caps.
$this->assertEquals('1234', $md['Foo']);
$content = $object->content();
$this->assertEquals(self::FCONTENT, $content);
// Make sure I can do this twice (regression).
// Note that this SHOULD perform another request.
$this->assertEquals(self::FCONTENT, $object->content());
// Overwrite the copy:
$object->setContent('HI');
$this->assertEquals('HI', $object->content());
// Make sure I can do this twice (regression check).
$this->assertEquals('HI', $object->content());
}
/**
* @depends testRemoteObject
*/
public function testRefresh() {
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$content = (string) $object->content();
$object->setContent('FOO');
$this->assertEquals('FOO', $object->content());
$object->refresh(TRUE);
$this->assertEquals($content, (string) $object->content());
$object->refresh(FALSE);
$this->assertEquals($content, (string) $object->content());
}
/**
* @depends testRemoteObject
*/
public function testObject() {
$container = $this->containerFixture();
$object = $container->object(self::FNAME);
$this->assertEquals(self::FNAME, $object->name());
$this->assertEquals(self::FTYPE, $object->contentType());
$etag = md5(self::FCONTENT);
$this->assertEquals($etag, $object->eTag());
$md = $object->metadata();
$this->assertEquals(1, count($md));
// Note that headers are normalized remotely to have initial
// caps. Since we have no way of knowing what the original
// metadata casing is, we leave it with initial caps.
$this->assertEquals('1234', $md['Foo']);
$content = $object->content();
$this->assertEquals(self::FCONTENT, $content);
// Overwrite the copy:
$object->setContent('HI');
$this->assertEquals('HI', $object->content());
// Make sure this throws a 404.
try {
$foo = $container->object('no/such');
}
catch (\OpenStack\Exception $e) {
$this->assertInstanceOf('\OpenStack\Transport\FileNotFoundException', $e);
}
}
/**
* @depends testSave
*/
public function testObjects() {
$container = $this->containerFixture();
$obj1 = new Object('a/' . self::FNAME, self::FCONTENT, self::FTYPE);
$obj2 = new Object('a/b/' . self::FNAME, self::FCONTENT, self::FTYPE);
$container->save($obj1);
$container->save($obj2);
// Now we have a container with three items.
$objects = $container->objects();
$this->assertEquals(3, count($objects));
$objects = $container->objects(1, 'a/' . self::FNAME);
$this->assertEquals(1, count($objects));
}
/**
* @depends testObjects
*/
public function testGetIterator() {
$container = $this->containerFixture();
$it = $container->getIterator();
$this->assertInstanceOf('Traversable', $it);
$i = 0;
foreach ($container as $item) {
++$i;
}
$this->assertEquals(3, $i);
}
/**
* @depends testObjects
*/
public function testObjectsWithPrefix() {
$container = $this->containerFixture();
$objects = $container->objectsWithPrefix('a/');
$this->assertEquals(2, count($objects));
foreach ($objects as $o) {
if ($o instanceof Object) {
$this->assertEquals('a/' . self::FNAME, $o->name());
}
else {
$this->assertEquals('a/b/', $o->path());
}
}
// Since we set the delimiter to ':' we will get back
// all of the objects in a/. This is because none of
// the objects contain ':' in their names.
$objects = $container->objectsWithPrefix('a/', ':');
$this->assertEquals(2, count($objects));
foreach ($objects as $o) {
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\Object', $o);
}
// This should give us one file and one subdir.
$objects = $container->objectsWithPrefix('', '/');
$this->assertEquals(2, count($objects));
foreach ($objects as $o) {
if ($o instanceof Object) {
$this->assertEquals(self::FNAME, $o->name());
}
else {
$this->assertEquals('a/', $o->path());
}
}
}
/**
* @depends testObjects
*/
public function testObjectsWithPath() {
$container = $this->containerFixture();
$objects = $container->objectsByPath('a/b/');
$this->assertEquals(1, count($objects));
$o = array_shift($objects);
$this->assertEquals('a/b/' . self::FNAME, $o->name());
/*
* The Open Stack documentation is unclear about how best to
* use paths. Experimentation suggests that if you rely on paths
* instead of prefixes, your best bet is to create directory
* markers.
/**
* @expectedException \OpenStack\Exception
*/
public function testConstructorFailure()
{
$container = new Container('foo');
$this->assertEquals('foo', $container->name());
// Test subdir listings:
// This does not work (by design?) with Path. You have to use prefix
// or else create directory markers.
// $obj1 = new Object('a/aa/aaa/' . self::FNAME, self::FCONTENT, self::FTYPE);
// $container->save($obj1);
// $objects = $container->objectsByPath('a/aaa', '/');
// $this->assertEquals(1, count($objects), 'One subdir');
// $objects = $container->objectsByPath('a/');
// throw new \Exception(print_r($objects, TRUE));
// $this->assertEquals(2, count($objects));
// foreach ($objects as $o) {
// if ($o instanceof Object) {
// $this->assertEquals('a/' . self::FNAME, $o->name());
// }
// else {
// $this->assertEquals('a/b/', $o->path());
// }
// }
}
/**
* @depends testRemoteObject
*/
public function testUpdateMetadata() {
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$md = $object->metadata();
$this->assertEquals('1234', $md['Foo']);
$md['Foo'] = 456;
$md['Bar'] = 'bert';
$object->setMetadata($md);
$container->updateMetadata($object);
$copy = $container->remoteObject(self::FNAME);
$this->assertEquals('456', $md['Foo']);
$this->assertEquals('bert', $md['Bar']);
// Now we need to canary test:
$this->assertEquals($object->contentType(), $copy->contentType());
$this->assertEquals($object->contentLength(), $copy->contentLength());
}
/**
* @depends testRemoteObject
*/
public function testCopy() {
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$container->copy($object, 'FOO-1.txt');
$copy = $container->remoteObject('FOO-1.txt');
$this->assertEquals($object->contentType(), $copy->contentType());
$this->assertEquals($object->etag(), $copy->etag());
$container->delete('foo-1.txt');
}
/**
* @depends testCopy
*/
public function testCopyAcrossContainers() {
// Create a new container.
$store = $this->objectStore();
$cname = self::$settings['openstack.swift.container'] . 'COPY';
if ($store->hasContainer($cname)) {
$this->eradicateContainer($cname);
// These will now cause the system to try to fetch a remote
// container. This is a failure condition.
$this->assertEquals(0, $container->bytes());
}
$store->createContainer($cname);
$newContainer = $store->container($cname);
public function testCountable()
{
// Verify that the interface Countable is properly
// implemented.
// Get teh old container and its object.
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$mockJSON = array('count' => 5, 'bytes' => 128, 'name' => 'foo');
$ret = $container->copy($object, 'foo-1.txt', $cname);
$container = Container::newFromJSON($mockJSON, 'fake', 'fake');
$this->assertTrue($ret);
$this->assertEquals(5, count($container));
$copy = $newContainer->remoteObject('foo-1.txt');
$this->assertEquals($object->etag(), $copy->etag());
$this->eradicateContainer($cname);
}
/**
* @depends testSave
*/
public function testDelete() {
$container = $this->containerFixture();
$ret = $container->delete(self::FNAME);
$fail = $container->delete('no_such_file.txt');
$this->destroyContainerFixture();
$this->assertTrue($ret);
$this->assertFalse($fail);
}
/**
* @group public
*/
public function testAcl() {
$store = $this->objectStore();
$cname = self::$settings['openstack.swift.container'] . 'PUBLIC';
if ($store->hasContainer($cname)) {
$store->deleteContainer($cname);
}
$store->createContainer($cname, ACL::makePublic());
const FNAME = 'testSave';
const FCONTENT = 'This is a test.';
const FTYPE = 'application/x-monkey-file';
public function testSave()
{
// Clean up anything left.
$this->destroyContainerFixture();
$container = $this->containerFixture();
$obj = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
$obj->setMetadata(array('foo' => '1234'));
$this->assertEquals(self::FCONTENT, $obj->content());
try {
$ret = $container->save($obj);
} catch (\Exception $e) {
$this->destroyContainerFixture();
throw $e;
}
$this->assertTrue($ret);
}
/**
* @depends testSave
*/
public function testRemoteObject()
{
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$this->assertEquals(self::FNAME, $object->name());
$this->assertEquals(self::FTYPE, $object->contentType());
$etag = md5(self::FCONTENT);
$this->assertEquals($etag, $object->eTag());
$md = $object->metadata();
$this->assertEquals(1, count($md));
// Note that headers are normalized remotely to have initial
// caps. Since we have no way of knowing what the original
// metadata casing is, we leave it with initial caps.
$this->assertEquals('1234', $md['Foo']);
$content = $object->content();
$this->assertEquals(self::FCONTENT, $content);
// Make sure I can do this twice (regression).
// Note that this SHOULD perform another request.
$this->assertEquals(self::FCONTENT, $object->content());
// Overwrite the copy:
$object->setContent('HI');
$this->assertEquals('HI', $object->content());
// Make sure I can do this twice (regression check).
$this->assertEquals('HI', $object->content());
}
$store->containers();
$container = $store->container($cname);
/**
* @depends testRemoteObject
*/
public function testRefresh()
{
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$acl = $container->acl();
$content = (string) $object->content();
$object->setContent('FOO');
$this->assertEquals('FOO', $object->content());
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\ACL', $acl);
$this->assertTrue($acl->isPublic());
$object->refresh(TRUE);
$this->assertEquals($content, (string) $object->content());
$store->deleteContainer($cname);
$object->refresh(FALSE);
$this->assertEquals($content, (string) $object->content());
}
}
/**
* @depends testRemoteObject
*/
public function testObject()
{
$container = $this->containerFixture();
$object = $container->object(self::FNAME);
$this->assertEquals(self::FNAME, $object->name());
$this->assertEquals(self::FTYPE, $object->contentType());
$etag = md5(self::FCONTENT);
$this->assertEquals($etag, $object->eTag());
$md = $object->metadata();
$this->assertEquals(1, count($md));
// Note that headers are normalized remotely to have initial
// caps. Since we have no way of knowing what the original
// metadata casing is, we leave it with initial caps.
$this->assertEquals('1234', $md['Foo']);
$content = $object->content();
$this->assertEquals(self::FCONTENT, $content);
// Overwrite the copy:
$object->setContent('HI');
$this->assertEquals('HI', $object->content());
// Make sure this throws a 404.
try {
$foo = $container->object('no/such');
} catch (\OpenStack\Exception $e) {
$this->assertInstanceOf('\OpenStack\Transport\FileNotFoundException', $e);
}
}
/**
* @depends testSave
*/
public function testObjects()
{
$container = $this->containerFixture();
$obj1 = new Object('a/' . self::FNAME, self::FCONTENT, self::FTYPE);
$obj2 = new Object('a/b/' . self::FNAME, self::FCONTENT, self::FTYPE);
$container->save($obj1);
$container->save($obj2);
// Now we have a container with three items.
$objects = $container->objects();
$this->assertEquals(3, count($objects));
$objects = $container->objects(1, 'a/' . self::FNAME);
$this->assertEquals(1, count($objects));
}
/**
* @depends testObjects
*/
public function testGetIterator()
{
$container = $this->containerFixture();
$it = $container->getIterator();
$this->assertInstanceOf('Traversable', $it);
$i = 0;
foreach ($container as $item) {
++$i;
}
$this->assertEquals(3, $i);
}
/**
* @depends testObjects
*/
public function testObjectsWithPrefix()
{
$container = $this->containerFixture();
$objects = $container->objectsWithPrefix('a/');
$this->assertEquals(2, count($objects));
foreach ($objects as $o) {
if ($o instanceof Object) {
$this->assertEquals('a/' . self::FNAME, $o->name());
} else {
$this->assertEquals('a/b/', $o->path());
}
}
// Since we set the delimiter to ':' we will get back
// all of the objects in a/. This is because none of
// the objects contain ':' in their names.
$objects = $container->objectsWithPrefix('a/', ':');
$this->assertEquals(2, count($objects));
foreach ($objects as $o) {
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\Object', $o);
}
// This should give us one file and one subdir.
$objects = $container->objectsWithPrefix('', '/');
$this->assertEquals(2, count($objects));
foreach ($objects as $o) {
if ($o instanceof Object) {
$this->assertEquals(self::FNAME, $o->name());
} else {
$this->assertEquals('a/', $o->path());
}
}
}
/**
* @depends testObjects
*/
public function testObjectsWithPath()
{
$container = $this->containerFixture();
$objects = $container->objectsByPath('a/b/');
$this->assertEquals(1, count($objects));
$o = array_shift($objects);
$this->assertEquals('a/b/' . self::FNAME, $o->name());
/*
* The Open Stack documentation is unclear about how best to
* use paths. Experimentation suggests that if you rely on paths
* instead of prefixes, your best bet is to create directory
* markers.
*/
// Test subdir listings:
// This does not work (by design?) with Path. You have to use prefix
// or else create directory markers.
// $obj1 = new Object('a/aa/aaa/' . self::FNAME, self::FCONTENT, self::FTYPE);
// $container->save($obj1);
// $objects = $container->objectsByPath('a/aaa', '/');
// $this->assertEquals(1, count($objects), 'One subdir');
// $objects = $container->objectsByPath('a/');
// throw new \Exception(print_r($objects, TRUE));
// $this->assertEquals(2, count($objects));
// foreach ($objects as $o) {
// if ($o instanceof Object) {
// $this->assertEquals('a/' . self::FNAME, $o->name());
// }
// else {
// $this->assertEquals('a/b/', $o->path());
// }
// }
}
/**
* @depends testRemoteObject
*/
public function testUpdateMetadata()
{
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$md = $object->metadata();
$this->assertEquals('1234', $md['Foo']);
$md['Foo'] = 456;
$md['Bar'] = 'bert';
$object->setMetadata($md);
$container->updateMetadata($object);
$copy = $container->remoteObject(self::FNAME);
$this->assertEquals('456', $md['Foo']);
$this->assertEquals('bert', $md['Bar']);
// Now we need to canary test:
$this->assertEquals($object->contentType(), $copy->contentType());
$this->assertEquals($object->contentLength(), $copy->contentLength());
}
/**
* @depends testRemoteObject
*/
public function testCopy()
{
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$container->copy($object, 'FOO-1.txt');
$copy = $container->remoteObject('FOO-1.txt');
$this->assertEquals($object->contentType(), $copy->contentType());
$this->assertEquals($object->etag(), $copy->etag());
$container->delete('foo-1.txt');
}
/**
* @depends testCopy
*/
public function testCopyAcrossContainers()
{
// Create a new container.
$store = $this->objectStore();
$cname = self::$settings['openstack.swift.container'] . 'COPY';
if ($store->hasContainer($cname)) {
$this->eradicateContainer($cname);
}
$store->createContainer($cname);
$newContainer = $store->container($cname);
// Get teh old container and its object.
$container = $this->containerFixture();
$object = $container->remoteObject(self::FNAME);
$ret = $container->copy($object, 'foo-1.txt', $cname);
$this->assertTrue($ret);
$copy = $newContainer->remoteObject('foo-1.txt');
$this->assertEquals($object->etag(), $copy->etag());
$this->eradicateContainer($cname);
}
/**
* @depends testSave
*/
public function testDelete()
{
$container = $this->containerFixture();
$ret = $container->delete(self::FNAME);
$fail = $container->delete('no_such_file.txt');
$this->destroyContainerFixture();
$this->assertTrue($ret);
$this->assertFalse($fail);
}
/**
* @group public
*/
public function testAcl()
{
$store = $this->objectStore();
$cname = self::$settings['openstack.swift.container'] . 'PUBLIC';
if ($store->hasContainer($cname)) {
$store->deleteContainer($cname);
}
$store->createContainer($cname, ACL::makePublic());
$store->containers();
$container = $store->container($cname);
$acl = $container->acl();
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\ACL', $acl);
$this->assertTrue($acl->isPublic());
$store->deleteContainer($cname);
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
namespace OpenStack\Tests;
@ -21,52 +21,55 @@ use OpenStack\Transport\GuzzleClient;
require_once 'test/TestCase.php';
class GuzzleClientTest extends \OpenStack\Tests\TestCase {
class GuzzleClientTest extends \OpenStack\Tests\TestCase
{
/**
* Get the config from the test settings file and pass that into the client.
*/
public function buildClient()
{
$options = array();
if (isset(self::$settings['transport.proxy'])) {
$options['proxy'] = self::$settings['transport.proxy'];
}
if (isset(self::$settings['transport.debug'])) {
$options['debug'] = self::$settings['transport.debug'];
}
if (isset(self::$settings['transport.ssl.verify'])) {
$options['ssl_verify'] = self::$settings['transport.ssl.verify'];
}
if (isset(self::$settings['transport.timeout'])) {
$options['timeout'] = self::$settings['transport.timeout'];
}
/**
* Get the config from the test settings file and pass that into the client.
*/
public function buildClient() {
$options = array();
if (isset(self::$settings['transport.proxy'])) {
$options['proxy'] = self::$settings['transport.proxy'];
}
if (isset(self::$settings['transport.debug'])) {
$options['debug'] = self::$settings['transport.debug'];
}
if (isset(self::$settings['transport.ssl.verify'])) {
$options['ssl_verify'] = self::$settings['transport.ssl.verify'];
}
if (isset(self::$settings['transport.timeout'])) {
$options['timeout'] = self::$settings['transport.timeout'];
return new GuzzleClient($options);
}
return new GuzzleClient($options);
}
public function testDoRequest()
{
$url = 'http://www.openstack.org';
$method = 'GET';
public function testDoRequest() {
$url = 'http://www.openstack.org';
$method = 'GET';
$client = $this->buildClient();
$client = $this->buildClient();
$this->assertInstanceOf('\OpenStack\Transport\GuzzleClient', $client);
$this->assertInstanceOf('\OpenStack\Transport\GuzzleClient', $client);
$response = $client->doRequest($url, $method);
$this->assertInstanceOf('\GuzzleHttp\Message\Response', $response);
$response = $client->doRequest($url, $method);
$this->assertInstanceOf('\GuzzleHttp\Message\Response', $response);
}
}
/**
* @depends testDoRequest
* @expectedException \OpenStack\Transport\FileNotFoundException
*/
public function testDoRequestException()
{
$url = 'http://www.openstack.org/this-does-no-exist';
$method = 'GET';
/**
* @depends testDoRequest
* @expectedException \OpenStack\Transport\FileNotFoundException
*/
public function testDoRequestException() {
$url = 'http://www.openstack.org/this-does-no-exist';
$method = 'GET';
$client = $this->buildClient();
$client->doRequest($url, $method);
}
$client = $this->buildClient();
$client->doRequest($url, $method);
}
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Unit tests for IdentityService.
@ -24,414 +24,423 @@ require_once 'test/TestCase.php';
use \OpenStack\Services\IdentityService;
use \OpenStack\Bootstrap;
class IdentityServicesTest extends \OpenStack\Tests\TestCase
{
public function testConstructor()
{
$endpoint = self::conf('openstack.identity.url');
$this->assertNotEmpty($endpoint);
class IdentityServiceTest extends \OpenStack\Tests\TestCase {
$service = new IdentityService($endpoint, $this->getTransportClient());
public function testConstructor(){
$endpoint = self::conf('openstack.identity.url');
$this->assertNotEmpty($endpoint);
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $service);
$service = new IdentityService($endpoint, $this->getTransportClient());
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $service);
return $service;
}
/**
* @depends testConstructor
*/
public function testUrl() {
$endpoint = self::conf('openstack.identity.url');
$service = new IdentityService($endpoint, $this->getTransportClient());
// If there is a trailing / we remove that from the endpoint. Our calls add
// the / back where appropriate.
$this->assertStringStartsWith(rtrim($endpoint, '/'), $service->url());
return $service;
}
/**
* @depends testUrl
*/
public function testAuthenticate($service){
// Canary: Make sure all the required params are declared.
$settings = array(
'openstack.identity.username',
'openstack.identity.password',
'openstack.identity.tenantId',
);
foreach ($settings as $setting) {
$this->assertNotEmpty(self::conf($setting), "Required param: " . $setting);
return $service;
}
// Test username/password auth.
$auth = array(
'passwordCredentials' => array(
'username' => self::conf('openstack.identity.username'),
'password' => self::conf('openstack.identity.password'),
),
'tenantId' => self::conf('openstack.identity.tenantId'),
);
$tok = $service->authenticate($auth);
$this->assertNotEmpty($tok);
/**
* @depends testConstructor
*/
public function testUrl()
{
$endpoint = self::conf('openstack.identity.url');
$service = new IdentityService($endpoint, $this->getTransportClient());
// We should get the same token if we request again.
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$tok2 = $service->authenticate($auth);
$this->assertEquals($tok, $tok2);
// If there is a trailing / we remove that from the endpoint. Our calls add
// the / back where appropriate.
$this->assertStringStartsWith(rtrim($endpoint, '/'), $service->url());
// Again with no tenant ID.
$auth = array(
'passwordCredentials' => array(
'username' => self::conf('openstack.identity.username'),
'password' => self::conf('openstack.identity.password'),
),
//'tenantId' => self::conf('openstack.identity.tenantId'),
);
$tok = $service->authenticate($auth);
$this->assertNotEmpty($tok);
}
/**
* @depends testAuthenticate
*/
public function testAuthenticateAsUser() {
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$tok = $service->authenticateAsUser($user, $pass, $tenantId);
$this->assertNotEmpty($tok);
// Try again, this time with no tenant ID.
$tok2 = $service->authenticateAsUser($user, $pass);
$this->assertNotEmpty($tok2);
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
return $service;
}
/**
* @depends testAuthenticateAsUser
*/
public function testToken($service) {
$this->assertNotEmpty($service->token());
}
/**
* @depends testAuthenticateAsUser
*/
public function testIsExpired($service) {
$this->assertFalse($service->isExpired());
$service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$this->assertTrue($service2->isExpired());
}
/**
* @depends testAuthenticateAsUser
*/
public function testTenantName() {
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantName = self::conf('openstack.identity.tenantName');
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$this->assertNull($service->tenantName());
$service->authenticateAsUser($user, $pass);
$this->assertEmpty($service->tenantName());
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$ret = $service->authenticateAsUser($user, $pass, NULL, $tenantName);
$this->assertNotEmpty($service->tenantName());
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$this->assertNull($service->tenantName());
}
/**
* @depends testAuthenticateAsUser
*/
public function testTenantId() {
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$this->assertNull($service->tenantId());
$service->authenticateAsUser($user, $pass);
$this->assertEmpty($service->tenantId());
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$service->authenticateAsUser($user, $pass, $tenantId);
$this->assertNotEmpty($service->tenantId());
}
/**
* @depends testAuthenticateAsUser
*/
public function testTokenDetails() {
$now = time();
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$service->authenticateAsUser($user, $pass);
// Details for user auth.
$details = $service->tokenDetails();
$this->assertNotEmpty($details['id']);
$this->assertFalse(isset($details['tenant']));
$ts = strtotime($details['expires']);
$this->assertGreaterThan($now, $ts);
// Test details for username auth.
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$service->authenticateAsUser($user, $pass, $tenantId);
$details = $service->tokenDetails();
$expectUser = self::conf('openstack.identity.username');
$this->assertStringStartsWith($expectUser, $details['tenant']['name']);
$this->assertNotEmpty($details['id']);
$this->assertNotEmpty($details['tenant']['id']);
$this->assertEquals($tenantId, $details['tenant']['id']);
$ts = strtotime($details['expires']);
$this->assertGreaterThan($now, $ts);
}
/**
* @depends testAuthenticateAsUser
*/
public function testServiceCatalog($service) {
$catalog = $service->serviceCatalog();
$this->assertGreaterThan(0, count($catalog));
$idService = NULL;
foreach ($catalog as $item) {
if ($item['type'] == 'identity') {
$idService = $item;
}
return $service;
}
$this->assertEquals('Identity', $idService['name']);
$this->assertNotEmpty($idService['endpoints']);
$this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
/**
* @depends testUrl
*/
public function testAuthenticate($service)
{
// Canary: Make sure all the required params are declared.
$settings = array(
'openstack.identity.username',
'openstack.identity.password',
'openstack.identity.tenantId',
);
foreach ($settings as $setting) {
$this->assertNotEmpty(self::conf($setting), "Required param: " . $setting);
}
// Test filters.
$justID = $service->serviceCatalog('identity');
$this->assertEquals(1, count($justID));
// Test username/password auth.
$auth = array(
'passwordCredentials' => array(
'username' => self::conf('openstack.identity.username'),
'password' => self::conf('openstack.identity.password'),
),
'tenantId' => self::conf('openstack.identity.tenantId'),
);
$tok = $service->authenticate($auth);
$this->assertNotEmpty($tok);
$idService = $justID[0];
$this->assertEquals('Identity', $idService['name']);
$this->assertNotEmpty($idService['endpoints']);
$this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
// We should get the same token if we request again.
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$tok2 = $service->authenticate($auth);
$this->assertEquals($tok, $tok2);
// Make sure a missed filter returns an empty set.
$expectEmpty = $service->serviceCatalog('no-such-servicename');
$this->assertEmpty($expectEmpty);
}
/**
* @depends testAuthenticateAsUser
*/
public function testUser($service) {
$user = $service->user();
$this->assertEquals(self::conf('openstack.identity.username'), $user['name']);
$this->assertNotEmpty($user['roles']);
}
/**
* @depends testAuthenticateAsUser
* @group serialize
*/
public function testSerialization($service) {
$ser = serialize($service);
$this->assertNotEmpty($ser);
$again = unserialize($ser);
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $again);
$this->assertEquals($service->tenantId(), $again->tenantId());
$this->assertEquals($service->serviceCatalog(), $again->serviceCatalog());
$this->assertEquals($service->tokenDetails(), $again->tokenDetails());
$this->assertEquals($service->user(), $again->user());
$this->assertFalse($again->isExpired());
$tenantId = $again->tenantId();
$newTok = $again->rescopeUsingTenantId($tenantId);
$this->assertNotEmpty($newTok);
}
/**
* @group tenant
*/
public function testTenants() {
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$service->authenticateAsUser($user, $pass, $tenantId);
$tenants = $service2->tenants($service->token());
$this->assertGreaterThan(0, count($tenants));
$this->assertNotEmpty($tenants[0]['name']);
$this->assertNotEmpty($tenants[0]['id']);
$tenants = $service->tenants();
$this->assertGreaterThan(0, count($tenants));
$this->assertNotEmpty($tenants[0]['name']);
$this->assertNotEmpty($tenants[0]['id']);
}
/**
* @group tenant
* @depends testTenants
*/
function testRescope() {
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
// Authenticate without a tenant ID.
$token = $service->authenticateAsUser($user, $pass);
$this->assertNotEmpty($token);
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
$service->rescopeUsingTenantId($tenantId);
$details = $service->tokenDetails();
$this->assertEquals($tenantId, $details['tenant']['id']);
// Test unscoping
$service->rescopeUsingTenantId('');
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
}
/**
* @group tenant
* @depends testTenants
*/
function testRescopeByTenantName() {
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantName = self::conf('openstack.identity.tenantName');
// Authenticate without a tenant ID.
$token = $service->authenticateAsUser($user, $pass);
$this->assertNotEmpty($token);
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
$service->rescopeUsingTenantName($tenantName);
$details = $service->tokenDetails();
$this->assertEquals($tenantName, $details['tenant']['name']);
// Test unscoping
$service->rescope('');
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
}
/**
* Test the bootstrap identity factory.
* @depends testAuthenticateAsUser
*/
function testBootstrap() {
// We need to save the config settings and reset the bootstrap to this.
// It does not remove the old settings. The means the identity fall through
// for different settings may not happen because of ordering. So, we cache
// and reset back to the default for each test.
$reset = Bootstrap::$config;
// Test authenticating as a user.
$settings = array(
'username' => self::conf('openstack.identity.username'),
'password' => self::conf('openstack.identity.password'),
'endpoint' => self::conf('openstack.identity.url'),
'tenantid' => self::conf('openstack.identity.tenantId'),
'transport' => self::conf('transport'),
'transport.debug' => self::conf('transport.debug', FALSE),
'transport.ssl_verify' => self::conf('transport.ssl', TRUE),
);
if (self::conf('transport.timeout')) {
$setting['transport.timeout'] = self::conf('transport.timeout');
// Again with no tenant ID.
$auth = array(
'passwordCredentials' => array(
'username' => self::conf('openstack.identity.username'),
'password' => self::conf('openstack.identity.password'),
),
//'tenantId' => self::conf('openstack.identity.tenantId'),
);
$tok = $service->authenticate($auth);
$this->assertNotEmpty($tok);
}
if (self::conf('transport.proxy')) {
$setting['transport.proxy'] = self::conf('transport.proxy');
/**
* @depends testAuthenticate
*/
public function testAuthenticateAsUser()
{
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$tok = $service->authenticateAsUser($user, $pass, $tenantId);
$this->assertNotEmpty($tok);
// Try again, this time with no tenant ID.
$tok2 = $service->authenticateAsUser($user, $pass);
$this->assertNotEmpty($tok2);
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
return $service;
}
Bootstrap::setConfiguration($settings);
$is = Bootstrap::identity(TRUE);
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $is);
// Test getting a second instance from the cache.
$is2 = Bootstrap::identity();
$this->assertEquals($is, $is2);
// Test that forcing a refresh does so.
$is2 = Bootstrap::identity(TRUE);
$this->assertNotEquals($is, $is2);
Bootstrap::$config = $reset;
// Test with tenant name
$settings = array(
'username' => self::conf('openstack.identity.username'),
'password' => self::conf('openstack.identity.password'),
'endpoint' => self::conf('openstack.identity.url'),
'tenantname' => self::conf('openstack.identity.tenantName'),
'transport' => self::conf('transport'),
'transport.debug' => self::conf('transport.debug', FALSE),
'transport.ssl_verify' => self::conf('transport.ssl', TRUE),
);
if (self::conf('transport.timeout')) {
$setting['transport.timeout'] = self::conf('transport.timeout');
/**
* @depends testAuthenticateAsUser
*/
public function testToken($service)
{
$this->assertNotEmpty($service->token());
}
if (self::conf('transport.proxy')) {
$setting['transport.proxy'] = self::conf('transport.proxy');
}
Bootstrap::setConfiguration($settings);
$is = Bootstrap::identity(TRUE);
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $is);
}
/**
* @depends testAuthenticateAsUser
*/
public function testIsExpired($service)
{
$this->assertFalse($service->isExpired());
$service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$this->assertTrue($service2->isExpired());
}
/**
* @depends testAuthenticateAsUser
*/
public function testTenantName()
{
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantName = self::conf('openstack.identity.tenantName');
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$this->assertNull($service->tenantName());
$service->authenticateAsUser($user, $pass);
$this->assertEmpty($service->tenantName());
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$ret = $service->authenticateAsUser($user, $pass, NULL, $tenantName);
$this->assertNotEmpty($service->tenantName());
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$this->assertNull($service->tenantName());
}
/**
* @depends testAuthenticateAsUser
*/
public function testTenantId()
{
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$this->assertNull($service->tenantId());
$service->authenticateAsUser($user, $pass);
$this->assertEmpty($service->tenantId());
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$service->authenticateAsUser($user, $pass, $tenantId);
$this->assertNotEmpty($service->tenantId());
}
/**
* @depends testAuthenticateAsUser
*/
public function testTokenDetails()
{
$now = time();
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$service->authenticateAsUser($user, $pass);
// Details for user auth.
$details = $service->tokenDetails();
$this->assertNotEmpty($details['id']);
$this->assertFalse(isset($details['tenant']));
$ts = strtotime($details['expires']);
$this->assertGreaterThan($now, $ts);
// Test details for username auth.
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$service->authenticateAsUser($user, $pass, $tenantId);
$details = $service->tokenDetails();
$expectUser = self::conf('openstack.identity.username');
$this->assertStringStartsWith($expectUser, $details['tenant']['name']);
$this->assertNotEmpty($details['id']);
$this->assertNotEmpty($details['tenant']['id']);
$this->assertEquals($tenantId, $details['tenant']['id']);
$ts = strtotime($details['expires']);
$this->assertGreaterThan($now, $ts);
}
/**
* @depends testAuthenticateAsUser
*/
public function testServiceCatalog($service)
{
$catalog = $service->serviceCatalog();
$this->assertGreaterThan(0, count($catalog));
$idService = NULL;
foreach ($catalog as $item) {
if ($item['type'] == 'identity') {
$idService = $item;
}
}
$this->assertEquals('Identity', $idService['name']);
$this->assertNotEmpty($idService['endpoints']);
$this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
// Test filters.
$justID = $service->serviceCatalog('identity');
$this->assertEquals(1, count($justID));
$idService = $justID[0];
$this->assertEquals('Identity', $idService['name']);
$this->assertNotEmpty($idService['endpoints']);
$this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
// Make sure a missed filter returns an empty set.
$expectEmpty = $service->serviceCatalog('no-such-servicename');
$this->assertEmpty($expectEmpty);
}
/**
* @depends testAuthenticateAsUser
*/
public function testUser($service)
{
$user = $service->user();
$this->assertEquals(self::conf('openstack.identity.username'), $user['name']);
$this->assertNotEmpty($user['roles']);
}
/**
* @depends testAuthenticateAsUser
* @group serialize
*/
public function testSerialization($service)
{
$ser = serialize($service);
$this->assertNotEmpty($ser);
$again = unserialize($ser);
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $again);
$this->assertEquals($service->tenantId(), $again->tenantId());
$this->assertEquals($service->serviceCatalog(), $again->serviceCatalog());
$this->assertEquals($service->tokenDetails(), $again->tokenDetails());
$this->assertEquals($service->user(), $again->user());
$this->assertFalse($again->isExpired());
$tenantId = $again->tenantId();
$newTok = $again->rescopeUsingTenantId($tenantId);
$this->assertNotEmpty($newTok);
}
/**
* @group tenant
*/
public function testTenants()
{
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
$service->authenticateAsUser($user, $pass, $tenantId);
$tenants = $service2->tenants($service->token());
$this->assertGreaterThan(0, count($tenants));
$this->assertNotEmpty($tenants[0]['name']);
$this->assertNotEmpty($tenants[0]['id']);
$tenants = $service->tenants();
$this->assertGreaterThan(0, count($tenants));
$this->assertNotEmpty($tenants[0]['name']);
$this->assertNotEmpty($tenants[0]['id']);
}
/**
* @group tenant
* @depends testTenants
*/
public function testRescope()
{
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantId = self::conf('openstack.identity.tenantId');
// Authenticate without a tenant ID.
$token = $service->authenticateAsUser($user, $pass);
$this->assertNotEmpty($token);
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
$service->rescopeUsingTenantId($tenantId);
$details = $service->tokenDetails();
$this->assertEquals($tenantId, $details['tenant']['id']);
// Test unscoping
$service->rescopeUsingTenantId('');
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
}
/**
* @group tenant
* @depends testTenants
*/
public function testRescopeByTenantName()
{
$service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
$user = self::conf('openstack.identity.username');
$pass = self::conf('openstack.identity.password');
$tenantName = self::conf('openstack.identity.tenantName');
// Authenticate without a tenant ID.
$token = $service->authenticateAsUser($user, $pass);
$this->assertNotEmpty($token);
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
$service->rescopeUsingTenantName($tenantName);
$details = $service->tokenDetails();
$this->assertEquals($tenantName, $details['tenant']['name']);
// Test unscoping
$service->rescope('');
$details = $service->tokenDetails();
$this->assertFalse(isset($details['tenant']));
}
/**
* Test the bootstrap identity factory.
* @depends testAuthenticateAsUser
*/
public function testBootstrap()
{
// We need to save the config settings and reset the bootstrap to this.
// It does not remove the old settings. The means the identity fall through
// for different settings may not happen because of ordering. So, we cache
// and reset back to the default for each test.
$reset = Bootstrap::$config;
// Test authenticating as a user.
$settings = array(
'username' => self::conf('openstack.identity.username'),
'password' => self::conf('openstack.identity.password'),
'endpoint' => self::conf('openstack.identity.url'),
'tenantid' => self::conf('openstack.identity.tenantId'),
'transport' => self::conf('transport'),
'transport.debug' => self::conf('transport.debug', FALSE),
'transport.ssl_verify' => self::conf('transport.ssl', TRUE),
);
if (self::conf('transport.timeout')) {
$setting['transport.timeout'] = self::conf('transport.timeout');
}
if (self::conf('transport.proxy')) {
$setting['transport.proxy'] = self::conf('transport.proxy');
}
Bootstrap::setConfiguration($settings);
$is = Bootstrap::identity(TRUE);
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $is);
// Test getting a second instance from the cache.
$is2 = Bootstrap::identity();
$this->assertEquals($is, $is2);
// Test that forcing a refresh does so.
$is2 = Bootstrap::identity(TRUE);
$this->assertNotEquals($is, $is2);
Bootstrap::$config = $reset;
// Test with tenant name
$settings = array(
'username' => self::conf('openstack.identity.username'),
'password' => self::conf('openstack.identity.password'),
'endpoint' => self::conf('openstack.identity.url'),
'tenantname' => self::conf('openstack.identity.tenantName'),
'transport' => self::conf('transport'),
'transport.debug' => self::conf('transport.debug', FALSE),
'transport.ssl_verify' => self::conf('transport.ssl', TRUE),
);
if (self::conf('transport.timeout')) {
$setting['transport.timeout'] = self::conf('transport.timeout');
}
if (self::conf('transport.proxy')) {
$setting['transport.proxy'] = self::conf('transport.proxy');
}
Bootstrap::setConfiguration($settings);
$is = Bootstrap::identity(TRUE);
$this->assertInstanceOf('\OpenStack\Services\IdentityService', $is);
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Unit tests for ObjectStorage.
@ -24,281 +24,292 @@ require_once 'test/TestCase.php';
use \OpenStack\Storage\ObjectStorage\Object;
use \OpenStack\Storage\ObjectStorage\ACL;
class ObjectStorageTest extends \OpenStack\Tests\TestCase {
/**
* Canary test.
*/
public function testSettings() {
$this->assertTrue(!empty(self::$settings));
}
/**
* Test Swift-based authentication.
* @group deprecated
*/
public function testSwiftAuthentication() {
$ostore = $this->swiftAuth();
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
}
/**
* @group auth
*/
public function testConstructor() {
$ident = $this->identity();
$services = $ident->serviceCatalog(\OpenStack\Storage\ObjectStorage::SERVICE_TYPE);
if (empty($services)) {
throw new \Exception('No object-store service found.');
}
//$serviceURL = $services[0]['endpoints'][0]['adminURL'];
$serviceURL = $services[0]['endpoints'][0]['publicURL'];
$ostore = new \OpenStack\Storage\ObjectStorage($ident->token(), $serviceURL, $this->getTransportClient());
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
}
public function testNewFromServiceCatalog() {
$ident = $this->identity();
$tok = $ident->token();
$cat = $ident->serviceCatalog();
$ostore = \OpenStack\Storage\ObjectStorage::newFromServiceCatalog($cat, $tok, self::$settings['openstack.swift.region'], $this->getTransportClient());
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
}
public function testFailedNewFromServiceCatalog(){
$ident = $this->identity();
$tok = $ident->token();
$cat = $ident->serviceCatalog();
$ostore = \OpenStack\Storage\ObjectStorage::newFromServiceCatalog($cat, $tok, 'region-w.geo-99999.fake', $this->getTransportClient());
$this->assertEmpty($ostore);
}
public function testNewFromIdnetity() {
$ident = $this->identity();
$ostore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
}
public function testNewFromIdentityAltRegion() {
$ident = $this->identity();
$ostore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, 'region-b.geo-1', $this->getTransportClient());
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
// Make sure the store is not the same as the default region.
$ostoreDefault = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
$this->assertNotEquals($ostore, $ostoreDefault);
}
/**
* @group auth
* @ group acl
*/
public function testCreateContainer() {
$testCollection = self::$settings['openstack.swift.container'];
$this->assertNotEmpty($testCollection, "Canary: container name must be in settings file.");
$store = $this->objectStore();//swiftAuth();
$this->destroyContainerFixture();
/*
if ($store->hasContainer($testCollection)) {
$store->deleteContainer($testCollection);
}
class ObjectStorageTest extends \OpenStack\Tests\TestCase
{
/**
* Canary test.
*/
$md = array('Foo' => 1234);
$ret = $store->createContainer($testCollection, NULL, $md);
$this->assertTrue($ret, "Create container");
}
/**
* @group auth
* @depends testCreateContainer
*/
public function testAccountInfo () {
$store = $this->objectStore();
$info = $store->accountInfo();
$this->assertGreaterThan(0, $info['containers']);
$this->assertGreaterThanOrEqual(0, $info['bytes']);
$this->assertGreaterThanOrEqual(0, $info['objects']);
}
/**
* @depends testCreateContainer
*/
public function testContainers() {
$store = $this->objectStore();
$containers = $store->containers();
$this->assertNotEmpty($containers);
//$first = array_shift($containers);
$testCollection = self::conf('openstack.swift.container');
$testContainer = $containers[$testCollection];
$this->assertEquals($testCollection, $testContainer->name());
$this->assertEquals(0, $testContainer->bytes());
$this->assertEquals(0, $testContainer->count());
// Make sure we get back an ACL:
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\ACL', $testContainer->acl());
}
/**
* @depends testCreateContainer
*/
public function testContainer() {
$testCollection = self::$settings['openstack.swift.container'];
$store = $this->objectStore();
$container = $store->container($testCollection);
$this->assertEquals(0, $container->bytes());
$this->assertEquals(0, $container->count());
$this->assertEquals($testCollection, $container->name());
$md = $container->metadata();
$this->assertEquals(1, count($md));
$this->assertEquals('1234', $md['Foo']);
}
/**
* @depends testCreateContainer
*/
public function testHasContainer() {
$testCollection = self::$settings['openstack.swift.container'];
$store = $this->objectStore();
$this->assertTrue($store->hasContainer($testCollection));
$this->assertFalse($store->hasContainer('nihil'));
}
/**
* @depends testHasContainer
*/
public function testDeleteContainer() {
$testCollection = self::$settings['openstack.swift.container'];
$store = $this->objectStore();
//$ret = $store->createContainer($testCollection);
//$this->assertTrue($store->hasContainer($testCollection));
$ret = $store->deleteContainer($testCollection);
$this->assertTrue($ret);
// Now we try to delete a container that does not exist.
$ret = $store->deleteContainer('nihil');
$this->assertFalse($ret);
}
/**
* @expectedException \OpenStack\Storage\ObjectStorage\ContainerNotEmptyException
*/
public function testDeleteNonEmptyContainer() {
$testCollection = self::$settings['openstack.swift.container'];
$this->assertNotEmpty($testCollection);
$store = $this->objectStore();
$store->createContainer($testCollection);
$container = $store->container($testCollection);
$container->save(new Object('test', 'test', 'text/plain'));
try {
$ret = $store->deleteContainer($testCollection);
}
catch (\Exception $e) {
$container->delete('test');
$store->deleteContainer($testCollection);
throw $e;
public function testSettings()
{
$this->assertTrue(!empty(self::$settings));
}
try {
$container->delete('test');
}
// Skip 404s.
catch (\Exception $e) {}
/**
* Test Swift-based authentication.
* @group deprecated
*/
public function testSwiftAuthentication()
{
$ostore = $this->swiftAuth();
$store->deleteContainer($testCollection);
}
/**
* @depends testCreateContainer
* @group acl
*/
public function testCreateContainerPublic() {
$testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
$store = $this->objectStore();
if ($store->hasContainer($testCollection)) {
$store->deleteContainer($testCollection);
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
}
$ret = $store->createContainer($testCollection, ACL::makePublic());
$container = $store->container($testCollection);
/**
* @group auth
*/
public function testConstructor()
{
$ident = $this->identity();
// Now test that we can get the container contents. Since there is
// no content in the container, we use the format=xml to make sure
// we get some data back.
$url = $container->url() . '?format=xml';
$services = $ident->serviceCatalog(\OpenStack\Storage\ObjectStorage::SERVICE_TYPE);
// Use CURL to get better debugging:
//$client = \OpenStack\Transport::instance();
//$response = $client->doRequest($url, 'GET');
if (empty($services)) {
throw new \Exception('No object-store service found.');
}
$data = file_get_contents($url);
$this->assertNotEmpty($data, $url);
//$serviceURL = $services[0]['endpoints'][0]['adminURL'];
$serviceURL = $services[0]['endpoints'][0]['publicURL'];
$containers = $store->containers();
//throw new \Exception(print_r($containers, TRUE));
$ostore = new \OpenStack\Storage\ObjectStorage($ident->token(), $serviceURL, $this->getTransportClient());
$store->deleteContainer($testCollection);
}
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
/**
* @depends testCreateContainerPublic
*/
public function testChangeContainerACL() {
$testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
$store = $this->objectStore();
if ($store->hasContainer($testCollection)) {
$store->deleteContainer($testCollection);
}
$ret = $store->createContainer($testCollection);
public function testNewFromServiceCatalog()
{
$ident = $this->identity();
$tok = $ident->token();
$cat = $ident->serviceCatalog();
$ostore = \OpenStack\Storage\ObjectStorage::newFromServiceCatalog($cat, $tok, self::$settings['openstack.swift.region'], $this->getTransportClient());
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
}
$acl = \OpenStack\Storage\ObjectStorage\ACL::makePublic();
$ret = $store->changeContainerACL($testCollection, $acl);
public function testFailedNewFromServiceCatalog()
{
$ident = $this->identity();
$tok = $ident->token();
$cat = $ident->serviceCatalog();
$ostore = \OpenStack\Storage\ObjectStorage::newFromServiceCatalog($cat, $tok, 'region-w.geo-99999.fake', $this->getTransportClient());
$this->assertEmpty($ostore);
}
$this->assertFalse($ret);
public function testNewFromIdnetity()
{
$ident = $this->identity();
$ostore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
}
$container = $store->container($testCollection);
$url = $container->url() . '?format=xml';
$data = file_get_contents($url);
$this->assertNotEmpty($data, $url);
public function testNewFromIdentityAltRegion()
{
$ident = $this->identity();
$ostore = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, 'region-b.geo-1', $this->getTransportClient());
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage', $ostore);
$this->assertTrue(strlen($ostore->token()) > 0);
$store->deleteContainer($testCollection);
}
// Make sure the store is not the same as the default region.
$ostoreDefault = \OpenStack\Storage\ObjectStorage::newFromIdentity($ident, self::$settings['openstack.swift.region'], $this->getTransportClient());
$this->assertNotEquals($ostore, $ostoreDefault);
}
/**
* @group auth
* @ group acl
*/
public function testCreateContainer()
{
$testCollection = self::$settings['openstack.swift.container'];
$this->assertNotEmpty($testCollection, "Canary: container name must be in settings file.");
$store = $this->objectStore();//swiftAuth();
$this->destroyContainerFixture();
/*
if ($store->hasContainer($testCollection)) {
$store->deleteContainer($testCollection);
}
*/
$md = array('Foo' => 1234);
$ret = $store->createContainer($testCollection, NULL, $md);
$this->assertTrue($ret, "Create container");
}
/**
* @group auth
* @depends testCreateContainer
*/
public function testAccountInfo()
{
$store = $this->objectStore();
$info = $store->accountInfo();
$this->assertGreaterThan(0, $info['containers']);
$this->assertGreaterThanOrEqual(0, $info['bytes']);
$this->assertGreaterThanOrEqual(0, $info['objects']);
}
/**
* @depends testCreateContainer
*/
public function testContainers()
{
$store = $this->objectStore();
$containers = $store->containers();
$this->assertNotEmpty($containers);
//$first = array_shift($containers);
$testCollection = self::conf('openstack.swift.container');
$testContainer = $containers[$testCollection];
$this->assertEquals($testCollection, $testContainer->name());
$this->assertEquals(0, $testContainer->bytes());
$this->assertEquals(0, $testContainer->count());
// Make sure we get back an ACL:
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\ACL', $testContainer->acl());
}
/**
* @depends testCreateContainer
*/
public function testContainer()
{
$testCollection = self::$settings['openstack.swift.container'];
$store = $this->objectStore();
$container = $store->container($testCollection);
$this->assertEquals(0, $container->bytes());
$this->assertEquals(0, $container->count());
$this->assertEquals($testCollection, $container->name());
$md = $container->metadata();
$this->assertEquals(1, count($md));
$this->assertEquals('1234', $md['Foo']);
}
/**
* @depends testCreateContainer
*/
public function testHasContainer()
{
$testCollection = self::$settings['openstack.swift.container'];
$store = $this->objectStore();
$this->assertTrue($store->hasContainer($testCollection));
$this->assertFalse($store->hasContainer('nihil'));
}
/**
* @depends testHasContainer
*/
public function testDeleteContainer()
{
$testCollection = self::$settings['openstack.swift.container'];
$store = $this->objectStore();
//$ret = $store->createContainer($testCollection);
//$this->assertTrue($store->hasContainer($testCollection));
$ret = $store->deleteContainer($testCollection);
$this->assertTrue($ret);
// Now we try to delete a container that does not exist.
$ret = $store->deleteContainer('nihil');
$this->assertFalse($ret);
}
/**
* @expectedException \OpenStack\Storage\ObjectStorage\ContainerNotEmptyException
*/
public function testDeleteNonEmptyContainer()
{
$testCollection = self::$settings['openstack.swift.container'];
$this->assertNotEmpty($testCollection);
$store = $this->objectStore();
$store->createContainer($testCollection);
$container = $store->container($testCollection);
$container->save(new Object('test', 'test', 'text/plain'));
try {
$ret = $store->deleteContainer($testCollection);
} catch (\Exception $e) {
$container->delete('test');
$store->deleteContainer($testCollection);
throw $e;
}
try {
$container->delete('test');
}
// Skip 404s.
catch (\Exception $e) {}
$store->deleteContainer($testCollection);
}
/**
* @depends testCreateContainer
* @group acl
*/
public function testCreateContainerPublic()
{
$testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
$store = $this->objectStore();
if ($store->hasContainer($testCollection)) {
$store->deleteContainer($testCollection);
}
$ret = $store->createContainer($testCollection, ACL::makePublic());
$container = $store->container($testCollection);
// Now test that we can get the container contents. Since there is
// no content in the container, we use the format=xml to make sure
// we get some data back.
$url = $container->url() . '?format=xml';
// Use CURL to get better debugging:
//$client = \OpenStack\Transport::instance();
//$response = $client->doRequest($url, 'GET');
$data = file_get_contents($url);
$this->assertNotEmpty($data, $url);
$containers = $store->containers();
//throw new \Exception(print_r($containers, TRUE));
$store->deleteContainer($testCollection);
}
/**
* @depends testCreateContainerPublic
*/
public function testChangeContainerACL()
{
$testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
$store = $this->objectStore();
if ($store->hasContainer($testCollection)) {
$store->deleteContainer($testCollection);
}
$ret = $store->createContainer($testCollection);
$acl = \OpenStack\Storage\ObjectStorage\ACL::makePublic();
$ret = $store->changeContainerACL($testCollection, $acl);
$this->assertFalse($ret);
$container = $store->container($testCollection);
$url = $container->url() . '?format=xml';
$data = file_get_contents($url);
$this->assertNotEmpty($data, $url);
$store->deleteContainer($testCollection);
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Unit tests for ObjectStorage Object.
@ -23,123 +23,130 @@ require_once 'test/TestCase.php';
use \OpenStack\Storage\ObjectStorage\Object;
class ObjectTest extends \OpenStack\Tests\TestCase {
class ObjectTest extends \OpenStack\Tests\TestCase
{
const FNAME = 'descartes.txt';
const FCONTENT = 'Cogito ergo sum.';
const FTYPE = 'text/plain; charset=ISO-8859-1';
const FNAME = 'descartes.txt';
const FCONTENT = 'Cogito ergo sum.';
const FTYPE = 'text/plain; charset=ISO-8859-1';
/**
* Set up a basic object fixture.
*
* This provides an Object initialized with the main constants defined
* for this class. Use this as a fixture to avoid repetition.
*
* @return Object An initialized object.
*/
public function basicObjectFixture()
{
$o = new Object(self::FNAME);
$o->setContent(self::FCONTENT, self::FTYPE);
/**
* Set up a basic object fixture.
*
* This provides an Object initialized with the main constants defined
* for this class. Use this as a fixture to avoid repetition.
*
* @return Object An initialized object.
*/
public function basicObjectFixture() {
return $o;
}
$o = new Object(self::FNAME);
$o->setContent(self::FCONTENT, self::FTYPE);
public function testConstructor()
{
$o = $this->basicObjectFixture();
return $o;
}
$this->assertEquals(self::FNAME, $o->name());
public function testConstructor() {
$o = $this->basicObjectFixture();
$o = new Object('a', 'b', 'text/plain');
$this->assertEquals(self::FNAME, $o->name());
$this->assertEquals('a', $o->name());
$this->assertEquals('b', $o->content());
$this->assertEquals('text/plain', $o->contentType());
}
$o = new Object('a', 'b', 'text/plain');
public function testContentType()
{
// Don't use the fixture, we want to test content
// type in its raw state.
$o = new Object('foo.txt');
$this->assertEquals('a', $o->name());
$this->assertEquals('b', $o->content());
$this->assertEquals('text/plain', $o->contentType());
}
$this->assertEquals('application/octet-stream', $o->contentType());
public function testContentType() {
// Don't use the fixture, we want to test content
// type in its raw state.
$o = new Object('foo.txt');
$o->setContentType('text/plain; charset=UTF-8');
$this->assertEquals('text/plain; charset=UTF-8', $o->contentType());
}
$this->assertEquals('application/octet-stream', $o->contentType());
public function testContent()
{
$o = $this->basicObjectFixture();
$o->setContentType('text/plain; charset=UTF-8');
$this->assertEquals('text/plain; charset=UTF-8', $o->contentType());
}
$this->assertEquals(self::FCONTENT, $o->content());
public function testContent() {
$o = $this->basicObjectFixture();
// Test binary data.
$bin = sha1(self::FCONTENT, TRUE);
$o->setContent($bin, 'application/octet-stream');
$this->assertEquals(self::FCONTENT, $o->content());
$this->assertEquals($bin, $o->content());
}
// Test binary data.
$bin = sha1(self::FCONTENT, TRUE);
$o->setContent($bin, 'application/octet-stream');
public function testEtag()
{
$o = $this->basicObjectFixture();
$md5 = md5(self::FCONTENT);
$this->assertEquals($bin, $o->content());
}
$this->assertEquals($md5, $o->eTag());
}
public function testEtag() {
$o = $this->basicObjectFixture();
$md5 = md5(self::FCONTENT);
public function testIsChunked()
{
$o = $this->basicObjectFixture();
$this->assertFalse($o->isChunked());
}
$this->assertEquals($md5, $o->eTag());
}
public function testContentLength()
{
$o = $this->basicObjectFixture();
$this->assertEquals(strlen(self::FCONTENT), $o->contentLength());
public function testIsChunked() {
$o = $this->basicObjectFixture();
$this->assertFalse($o->isChunked());
}
// Test on binary data.
$bin = sha1(self::FCONTENT, TRUE);
public function testContentLength() {
$o = $this->basicObjectFixture();
$this->assertEquals(strlen(self::FCONTENT), $o->contentLength());
$o->setContent($bin);
$this->assertFalse($o->contentLength() == 0);
$this->assertEquals(strlen($bin), $o->contentLength());
}
// Test on binary data.
$bin = sha1(self::FCONTENT, TRUE);
public function testMetadata()
{
$md = array(
'Immanuel' => 'Kant',
'David' => 'Hume',
'Gottfried' => 'Leibniz',
'Jean-Jaques' => 'Rousseau',
);
$o->setContent($bin);
$this->assertFalse($o->contentLength() == 0);
$this->assertEquals(strlen($bin), $o->contentLength());
}
$o = $this->basicObjectFixture();
$o->setMetadata($md);
public function testMetadata() {
$md = array(
'Immanuel' => 'Kant',
'David' => 'Hume',
'Gottfried' => 'Leibniz',
'Jean-Jaques' => 'Rousseau',
);
$got = $o->metadata();
$o = $this->basicObjectFixture();
$o->setMetadata($md);
$this->assertEquals(4, count($got));
$this->assertArrayHasKey('Immanuel', $got);
$this->assertEquals('Leibniz', $got['Gottfried']);
$got = $o->metadata();
}
$this->assertEquals(4, count($got));
$this->assertArrayHasKey('Immanuel', $got);
$this->assertEquals('Leibniz', $got['Gottfried']);
public function testAdditionalHeaders()
{
$o = $this->basicObjectFixture();
}
$extra = array(
'a' => 'b',
'aaa' => 'bbb',
'ccc' => 'bbb',
);
$o->setAdditionalHeaders($extra);
public function testAdditionalHeaders() {
$o = $this->basicObjectFixture();
$got = $o->additionalHeaders();
$this->assertEquals(3, count($got));
$extra = array(
'a' => 'b',
'aaa' => 'bbb',
'ccc' => 'bbb',
);
$o->setAdditionalHeaders($extra);
$o->removeHeaders(array('ccc'));
$got = $o->additionalHeaders();
$this->assertEquals(3, count($got));
$o->removeHeaders(array('ccc'));
$got = $o->additionalHeaders();
$this->assertEquals(2, count($got));
}
$got = $o->additionalHeaders();
$this->assertEquals(2, count($got));
}
}

View File

@ -2,17 +2,17 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Unit tests for ObjectStorage RemoteObject.
@ -25,291 +25,308 @@ use \OpenStack\Storage\ObjectStorage\RemoteObject;
use \OpenStack\Storage\ObjectStorage\Object;
use \OpenStack\Storage\ObjectStorage\Container;
class RemoteObjectTest extends \OpenStack\Tests\TestCase {
const FNAME = 'RemoteObjectTest';
//const FTYPE = 'text/plain; charset=UTF-8';
const FTYPE = 'application/octet-stream; charset=UTF-8';
const FCONTENT = 'Rah rah ah ah ah. Roma roma ma. Gaga oh la la.';
const FMETA_NAME = 'Foo';
const FMETA_VALUE = 'Bar';
const FDISPOSITION = 'attachment; roma.gaga';
const FENCODING = 'gzip';
const FCORS_NAME = 'Access-Control-Max-Age';
const FCORS_VALUE = '2000';
protected function createAnObject() {
$container = $this->containerFixture();
$object = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
$object->setMetadata(array(self::FMETA_NAME => self::FMETA_VALUE));
$object->setDisposition(self::FDISPOSITION);
$object->setEncoding(self::FENCODING);
$object->setAdditionalHeaders(array(
'Access-Control-Allow-Origin' => 'http://example.com',
'Access-control-allow-origin' => 'http://example.com',
));
// Need some headers that Swift actually stores and returns. This
// one does not seem to be returned ever.
//$object->setAdditionalHeaders(array(self::FCORS_NAME => self::FCORS_VALUE));
$container->save($object);
}
public function testNewFromHeaders() {
// This is tested via the container.
$this->destroyContainerFixture();
$container = $this->containerFixture();
$this->createAnObject();
$obj = $container->remoteObject(self::FNAME);
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\RemoteObject', $obj);
return $obj;
}
/**
* @depends testNewFromHeaders
*/
public function testContentLength($obj) {
$len = strlen(self::FCONTENT);
$this->assertEquals($len, $obj->contentLength());
return $obj;
}
/**
* @depends testContentLength
*/
public function testContentType($obj) {
$this->assertEquals(self::FTYPE, $obj->contentType());
class RemoteObjectTest extends \OpenStack\Tests\TestCase
{
const FNAME = 'RemoteObjectTest';
//const FTYPE = 'text/plain; charset=UTF-8';
const FTYPE = 'application/octet-stream; charset=UTF-8';
const FCONTENT = 'Rah rah ah ah ah. Roma roma ma. Gaga oh la la.';
const FMETA_NAME = 'Foo';
const FMETA_VALUE = 'Bar';
const FDISPOSITION = 'attachment; roma.gaga';
const FENCODING = 'gzip';
const FCORS_NAME = 'Access-Control-Max-Age';
const FCORS_VALUE = '2000';
protected function createAnObject()
{
$container = $this->containerFixture();
$object = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
$object->setMetadata(array(self::FMETA_NAME => self::FMETA_VALUE));
$object->setDisposition(self::FDISPOSITION);
$object->setEncoding(self::FENCODING);
$object->setAdditionalHeaders(array(
'Access-Control-Allow-Origin' => 'http://example.com',
'Access-control-allow-origin' => 'http://example.com',
));
// Need some headers that Swift actually stores and returns. This
// one does not seem to be returned ever.
//$object->setAdditionalHeaders(array(self::FCORS_NAME => self::FCORS_VALUE));
$container->save($object);
}
public function testNewFromHeaders()
{
// This is tested via the container.
$this->destroyContainerFixture();
$container = $this->containerFixture();
$this->createAnObject();
$obj = $container->remoteObject(self::FNAME);
$this->assertInstanceOf('\OpenStack\Storage\ObjectStorage\RemoteObject', $obj);
return $obj;
}
/**
* @depends testNewFromHeaders
*/
public function testContentLength($obj)
{
$len = strlen(self::FCONTENT);
$this->assertEquals($len, $obj->contentLength());
return $obj;
}
/**
* @depends testContentLength
*/
public function testContentType($obj)
{
$this->assertEquals(self::FTYPE, $obj->contentType());
return $obj;
}
/**
* @depends testContentType
*/
public function testEtag($obj)
{
$hash = md5(self::FCONTENT);
$this->assertEquals($hash, $obj->eTag());
return $obj;
}
/**
* @depends testContentType
*/
public function testLastModified($obj)
{
$date = $obj->lastModified();
$this->assertTrue(is_int($date));
$this->assertTrue($date > 0);
}
/**
* @depends testNewFromHeaders
*/
public function testMetadata($obj)
{
$md = $obj->metadata();
$this->assertArrayHasKey(self::FMETA_NAME, $md);
$this->assertEquals(self::FMETA_VALUE, $md[self::FMETA_NAME]);
}
/**
* @depends testNewFromHeaders
*/
public function testDisposition($obj)
{
$this->assertEquals(self::FDISPOSITION, $obj->disposition());
}
return $obj;
}
/**
* @depends testNewFromHeaders
*/
public function testEncoding($obj)
{
$this->assertEquals(self::FENCODING, $obj->encoding());
}
/**
* @depends testContentType
*/
public function testEtag($obj) {
$hash = md5(self::FCONTENT);
/**
* @depends testNewFromHeaders
*/
public function testHeaders($obj)
{
$headers = $obj->headers();
$this->assertTrue(count($headers) > 1);
$this->assertEquals($hash, $obj->eTag());
//fwrite(STDOUT, print_r($headers, TRUE));
return $obj;
}
$this->assertNotEmpty($headers['Date']);
/**
* @depends testContentType
*/
public function testLastModified($obj) {
$date = $obj->lastModified();
$obj->removeHeaders(array('Date'));
$this->assertTrue(is_int($date));
$this->assertTrue($date > 0);
}
$headers = $obj->headers();
$this->assertFalse(isset($headers['Date']));
/**
* @depends testNewFromHeaders
*/
public function testMetadata($obj) {
$md = $obj->metadata();
// Swift doesn't return CORS headers even though it is supposed to.
//$this->assertEquals(self::FCORS_VALUE, $headers[self::FCORS_NAME]);
}
$this->assertArrayHasKey(self::FMETA_NAME, $md);
$this->assertEquals(self::FMETA_VALUE, $md[self::FMETA_NAME]);
}
/**
* @depends testNewFromHeaders
*/
public function testUrl($obj)
{
$url = $obj->url();
/**
* @depends testNewFromHeaders
*/
public function testDisposition($obj) {
$this->assertEquals(self::FDISPOSITION, $obj->disposition());
}
$this->assertTrue(strpos($obj->url(), $obj->name())> 0);
}
/**
* @depends testNewFromHeaders
*/
public function testStream($obj)
{
$res = $obj->stream();
/**
* @depends testNewFromHeaders
*/
public function testEncoding($obj) {
$this->assertEquals(self::FENCODING, $obj->encoding());
}
$this->assertTrue(is_resource($res));
/**
* @depends testNewFromHeaders
*/
public function testHeaders($obj) {
$headers = $obj->headers();
$this->assertTrue(count($headers) > 1);
$res_md = stream_get_meta_data($res);
$content = fread($res, $obj->contentLength());
fclose($res);
//fwrite(STDOUT, print_r($headers, TRUE));
$this->assertEquals(self::FCONTENT, $content);
$this->assertNotEmpty($headers['Date']);
// Now repeat the tests, only with a local copy of the data.
// This allows us to test the local tempfile buffering.
$obj->removeHeaders(array('Date'));
$obj->setContent($content);
$headers = $obj->headers();
$this->assertFalse(isset($headers['Date']));
$res2 = $obj->stream();
$res_md = stream_get_meta_data($res2);
// Swift doesn't return CORS headers even though it is supposed to.
//$this->assertEquals(self::FCORS_VALUE, $headers[self::FCORS_NAME]);
}
$this->assertEquals('PHP', $res_md['wrapper_type']);
/**
* @depends testNewFromHeaders
*/
public function testUrl($obj) {
$url = $obj->url();
$content = fread($res2, $obj->contentLength());
$this->assertTrue(strpos($obj->url(), $obj->name())> 0);
}
/**
* @depends testNewFromHeaders
*/
public function testStream($obj) {
$res = $obj->stream();
fclose($res2);
$this->assertTrue(is_resource($res));
$this->assertEquals(self::FCONTENT, $content);
$res_md = stream_get_meta_data($res);
// Finally, we redo the first part of the test to make sure that
// refreshing gets us a new copy:
$content = fread($res, $obj->contentLength());
$res3 = $obj->stream(TRUE);
$res_md = stream_get_meta_data($res3);
$this->assertEquals('PHP', $res_md['wrapper_type']);
fclose($res3);
fclose($res);
return $obj;
}
$this->assertEquals(self::FCONTENT, $content);
// To avoid test tainting from testStream(), we start over.
public function testContent()
{
$container = $this->containerFixture();
$obj = $container->object(self::FNAME);
// Now repeat the tests, only with a local copy of the data.
// This allows us to test the local tempfile buffering.
$content = $obj->content();
$this->assertEquals(self::FCONTENT, $content);
$obj->setContent($content);
// Make sure remoteObject retrieves the same content.
$obj = $container->remoteObject(self::FNAME);
$content = $obj->content();
$this->assertEquals(self::FCONTENT, $content);
$res2 = $obj->stream();
$res_md = stream_get_meta_data($res2);
}
$this->assertEquals('PHP', $res_md['wrapper_type']);
/**
* @depends testStream
*/
public function testCaching()
{
$container = $this->containerFixture();
$obj = $container->remoteObject(self::FNAME);
$content = fread($res2, $obj->contentLength());
$this->assertFalse($obj->isCaching());
fclose($res2);
$content = $obj->content();
$this->assertEquals(self::FCONTENT, $content);
$res1 = $obj->stream();
$md = stream_get_meta_data($res1);
$this->assertEquals('PHP', $md['wrapper_type']);
// Finally, we redo the first part of the test to make sure that
// refreshing gets us a new copy:
fclose($res1);
$res3 = $obj->stream(TRUE);
$res_md = stream_get_meta_data($res3);
$this->assertEquals('PHP', $res_md['wrapper_type']);
fclose($res3);
// Enable caching and retest.
$obj->setCaching(TRUE);
$this->assertTrue($obj->isCaching());
return $obj;
}
// This will cache the content.
$content = $obj->content();
// To avoid test tainting from testStream(), we start over.
public function testContent() {
$container = $this->containerFixture();
$obj = $container->object(self::FNAME);
$res2 = $obj->stream();
$md = stream_get_meta_data($res2);
$content = $obj->content();
$this->assertEquals(self::FCONTENT, $content);
// If this is using the PHP version, it built content from the
// cached version.
$this->assertEquals('PHP', $md['wrapper_type']);
// Make sure remoteObject retrieves the same content.
$obj = $container->remoteObject(self::FNAME);
$content = $obj->content();
$this->assertEquals(self::FCONTENT, $content);
fclose($res2);
}
}
/**
* @depends testNewFromHeaders
*/
public function testContentVerification($obj)
{
$this->assertTrue($obj->isVerifyingContent());
$obj->setContentVerification(FALSE);
$this->assertFALSE($obj->isVerifyingContent());
$obj->setContentVerification(TRUE);
}
/**
* @depends testStream
*/
public function testCaching() {
$container = $this->containerFixture();
$obj = $container->remoteObject(self::FNAME);
/**
* @depends testCaching
*/
public function testIsDirty()
{
$container = $this->containerFixture();
$obj = $container->remoteObject(self::FNAME);
$this->assertFalse($obj->isCaching());
// THere is no content. Assert false.
$this->assertFalse($obj->isDirty());
$content = $obj->content();
$obj->setCaching(TRUE);
$obj->content();
$res1 = $obj->stream();
$md = stream_get_meta_data($res1);
$this->assertEquals('PHP', $md['wrapper_type']);
// THere is content, but it is unchanged.
$this->assertFalse($obj->isDirty());
fclose($res1);
// Change content and retest.
$obj->setContent('foo');
// Enable caching and retest.
$obj->setCaching(TRUE);
$this->assertTrue($obj->isCaching());
$this->assertTrue($obj->isDirty());
}
// This will cache the content.
$content = $obj->content();
/**
* @depends testIsDirty
*/
public function testRefresh()
{
$container = $this->containerFixture();
$obj = $container->remoteObject(self::FNAME);
$res2 = $obj->stream();
$md = stream_get_meta_data($res2);
$obj->setContent('foo');
$this->assertTrue($obj->isDirty());
// If this is using the PHP version, it built content from the
// cached version.
$this->assertEquals('PHP', $md['wrapper_type']);
$obj->refresh(FALSE);
$this->assertFalse($obj->isDirty());
$this->assertEquals(self::FCONTENT, $obj->content());
fclose($res2);
}
$obj->setContent('foo');
$this->assertTrue($obj->isDirty());
/**
* @depends testNewFromHeaders
*/
public function testContentVerification($obj) {
$this->assertTrue($obj->isVerifyingContent());
$obj->setContentVerification(FALSE);
$this->assertFALSE($obj->isVerifyingContent());
$obj->setContentVerification(TRUE);
}
$obj->refresh(TRUE);
$this->assertFalse($obj->isDirty());
$this->assertEquals(self::FCONTENT, $obj->content());
/**
* @depends testCaching
*/
public function testIsDirty() {
$container = $this->containerFixture();
$obj = $container->remoteObject(self::FNAME);
$this->destroyContainerFixture();
// THere is no content. Assert false.
$this->assertFalse($obj->isDirty());
$obj->setCaching(TRUE);
$obj->content();
// THere is content, but it is unchanged.
$this->assertFalse($obj->isDirty());
// Change content and retest.
$obj->setContent('foo');
$this->assertTrue($obj->isDirty());
}
/**
* @depends testIsDirty
*/
public function testRefresh() {
$container = $this->containerFixture();
$obj = $container->remoteObject(self::FNAME);
$obj->setContent('foo');
$this->assertTrue($obj->isDirty());
$obj->refresh(FALSE);
$this->assertFalse($obj->isDirty());
$this->assertEquals(self::FCONTENT, $obj->content());
$obj->setContent('foo');
$this->assertTrue($obj->isDirty());
$obj->refresh(TRUE);
$this->assertFalse($obj->isDirty());
$this->assertEquals(self::FCONTENT, $obj->content());
$this->destroyContainerFixture();
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,22 +2,22 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Helpers for testing using the CurlTransport.
*/
$bootstrap_settings = array(
'transport' => '\OpenStack\Transport\CURLTransport',
'transport' => '\OpenStack\Transport\CURLTransport',
);

View File

@ -2,22 +2,22 @@
/* ============================================================================
(c) Copyright 2012-2014 Hewlett-Packard Development Company, L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
============================================================================ */
/**
* Helpers for testing using the CurlTransport.
*/
$bootstrap_settings = array(
'transport' => '\OpenStack\Transport\PHPStreamTransport',
'transport' => '\OpenStack\Transport\PHPStreamTransport',
);