rhymix/modules/member/php-openid-1.2.3/Tests/Auth/OpenID/StoreTest.php
2008-12-19 11:00:19 +00:00

574 lines
18 KiB
PHP

<?php
/**
* A test script for the OpenIDStore classes.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
/**
* Require classes and functions to run the Store tests.
*/
require_once 'Auth/OpenID/Association.php';
require_once 'Auth/OpenID/CryptUtil.php';
require_once 'Auth/OpenID.php';
require_once 'PHPUnit.php';
function _Auth_OpenID_mkdtemp()
{
if (strpos(PHP_OS, 'WIN') === 0) {
$dir = $_ENV['TMP'];
if (!isset($dir)) {
$dir = 'C:\Windows\Temp';
}
} else {
$dir = @$_ENV['TMPDIR'];
if (!isset($dir)) {
$dir = '/tmp';
}
}
return Auth_OpenID_FileStore::_mkdtemp($dir);
}
/**
* This is the host where the SQL stores' databases should be created
* and destroyed.
*/
$_Auth_OpenID_db_test_host = 'dbtest';
/**
* Generate a sufficently unique database name so many hosts can run
* SQL store tests on the server at the same time and not step on each
* other.
*/
function _Auth_OpenID_getTmpDbName()
{
$hostname = php_uname('n');
$hostname = strtolower(str_replace('.', '_', $hostname));
return sprintf("%s_%d_%s_openid_test",
$hostname,
getmypid(),
strval(rand(1, time())));
}
/**
* Tests the OpenID stores.
*
* @package OpenID
*/
class Tests_Auth_OpenID_StoreTest extends PHPUnit_TestCase {
/**
* Prepares for the SQL store tests.
*/
function setUp()
{
$this->letters = Auth_OpenID_letters;
$this->digits = Auth_OpenID_digits;
$this->punct = Auth_OpenID_punct;
$this->allowed_nonce = $this->letters . $this->digits;
$this->allowed_handle = $this->letters . $this->digits . $this->punct;
}
/**
* Generates a nonce value.
*/
function generateNonce()
{
return Auth_OpenID_CryptUtil::randomString(8, $this->allowed_nonce);
}
/**
* Generates an association with the specified parameters.
*/
function genAssoc($now, $issued = 0, $lifetime = 600)
{
$sec = Auth_OpenID_CryptUtil::randomString(20);
$hdl = Auth_OpenID_CryptUtil::randomString(128, $this->allowed_handle);
return new Auth_OpenID_Association($hdl, $sec, $now + $issued,
$lifetime, 'HMAC-SHA1');
}
/**
* @access private
*/
function _checkRetrieve(&$store, $url, $handle, $expected, $name = null)
{
$retrieved_assoc = $store->getAssociation($url, $handle);
if (($expected === null) || ($store->isDumb())) {
$this->assertNull($retrieved_assoc, "Retrieved association " .
"was non-null");
} else {
if ($retrieved_assoc === null) {
$this->fail("$name: Got null when expecting " .
$expected->serialize());
} else {
$this->assertEquals($expected->serialize(),
$retrieved_assoc->serialize(), $name);
}
}
}
function _checkRemove(&$store, $url, $handle, $expected, $name = null)
{
$present = $store->removeAssociation($url, $handle);
$expectedPresent = (!$store->isDumb() && $expected);
$this->assertTrue((!$expectedPresent && !$present) ||
($expectedPresent && $present),
$name);
}
/**
* Make sure a given store has a minimum of API compliance. Call
* this function with an empty store.
*
* Raises AssertionError if the store does not work as expected.
*
* OpenIDStore -> NoneType
*/
function _testStore($store)
{
// Association functions
$now = time();
$server_url = 'http://www.myopenid.com/openid';
$assoc = $this->genAssoc($now);
$this->_checkRetrieve($store, $server_url, null, null,
'Make sure that a missing association returns no result');
$store->storeAssociation($server_url, $assoc);
$this->_checkRetrieve($store, $server_url, null, $assoc,
'Check that after storage, getting returns the same result');
$this->_checkRetrieve($store, $server_url, null, $assoc,
'more than once');
$store->storeAssociation($server_url, $assoc);
$this->_checkRetrieve($store, $server_url, null, $assoc,
'Storing more than once has no ill effect');
// Removing an association that does not exist returns not present
$this->_checkRemove($store, $server_url, $assoc->handle . 'x', false,
"Remove nonexistent association (1)");
// Removing an association that does not exist returns not present
$this->_checkRemove($store, $server_url . 'x', $assoc->handle, false,
"Remove nonexistent association (2)");
// Removing an association that is present returns present
$this->_checkRemove($store, $server_url, $assoc->handle, true,
"Remove existent association");
// but not present on subsequent calls
$this->_checkRemove($store, $server_url, $assoc->handle, false,
"Remove nonexistent association after removal");
// Put assoc back in the store
$store->storeAssociation($server_url, $assoc);
// More recent and expires after assoc
$assoc2 = $this->genAssoc($now, $issued = 1);
$store->storeAssociation($server_url, $assoc2);
$this->_checkRetrieve($store, $server_url, null, $assoc2,
'After storing an association with a different handle, but the
same $server_url, the handle with the later expiration is
returned.');
$this->_checkRetrieve($store, $server_url, $assoc->handle, $assoc,
'We can still retrieve the older association');
$this->_checkRetrieve($store, $server_url, $assoc2->handle, $assoc2,
'Plus we can retrieve the association with the later expiration
explicitly');
$assoc3 = $this->genAssoc($now, $issued = 2, $lifetime = 100);
$store->storeAssociation($server_url, $assoc3);
// More recent issued time, so assoc3 is expected.
$this->_checkRetrieve($store, $server_url, null, $assoc3, "(1)");
$this->_checkRetrieve($store, $server_url, $assoc->handle,
$assoc, "(2)");
$this->_checkRetrieve($store, $server_url, $assoc2->handle,
$assoc2, "(3)");
$this->_checkRetrieve($store, $server_url, $assoc3->handle,
$assoc3, "(4)");
$this->_checkRemove($store, $server_url, $assoc2->handle, true, "(5)");
$this->_checkRetrieve($store, $server_url, null, $assoc3, "(6)");
$this->_checkRetrieve($store, $server_url, $assoc->handle,
$assoc, "(7)");
$this->_checkRetrieve($store, $server_url, $assoc2->handle,
null, "(8)");
$this->_checkRetrieve($store, $server_url, $assoc3->handle,
$assoc3, "(9)");
$this->_checkRemove($store, $server_url, $assoc2->handle,
false, "(10)");
$this->_checkRemove($store, $server_url, $assoc3->handle,
true, "(11)");
$this->_checkRetrieve($store, $server_url, null, $assoc, "(12)");
$this->_checkRetrieve($store, $server_url, $assoc->handle,
$assoc, "(13)");
$this->_checkRetrieve($store, $server_url, $assoc2->handle,
null, "(14)");
$this->_checkRetrieve($store, $server_url, $assoc3->handle,
null, "(15)");
$this->_checkRemove($store, $server_url, $assoc2->handle,
false, "(16)");
$this->_checkRemove($store, $server_url, $assoc->handle,
true, "(17)");
$this->_checkRemove($store, $server_url, $assoc3->handle,
false, "(18)");
$this->_checkRetrieve($store, $server_url, null, null, "(19)");
$this->_checkRetrieve($store, $server_url, $assoc->handle,
null, "(20)");
$this->_checkRetrieve($store, $server_url, $assoc2->handle,
null, "(21)");
$this->_checkRetrieve($store, $server_url,$assoc3->handle,
null, "(22)");
$this->_checkRemove($store, $server_url, $assoc2->handle,
false, "(23)");
$this->_checkRemove($store, $server_url, $assoc->handle,
false, "(24)");
$this->_checkRemove($store, $server_url, $assoc3->handle,
false, "(25)");
// Put associations into store, for two different server URLs
$assoc1 = $this->genAssoc($now);
$assoc2 = $this->genAssoc($now + 2);
$server_url1 = "http://one.example.com/one";
$server_url2 = "http://two.localhost.localdomain/two";
$store->storeAssociation($server_url1, $assoc1);
$store->storeAssociation($server_url2, $assoc2);
// Ask for each one, make sure we get it
$this->_checkRetrieve($store, $server_url1, $assoc1->handle,
$assoc1, "(26)");
$this->_checkRetrieve($store, $server_url2, $assoc2->handle,
$assoc2, "(27)");
$store->storeAssociation($server_url1, $assoc1);
$store->storeAssociation($server_url2, $assoc2);
// Ask for each one, make sure we get it
$this->_checkRetrieve($store, $server_url1, null,
$assoc1, "(28)");
$this->_checkRetrieve($store, $server_url2, null,
$assoc2, "(29)");
}
function _checkUseNonce(&$store, $nonce, $expected, $msg=null)
{
$actual = $store->useNonce($nonce);
$expected = $store->isDumb() || $expected;
$val = ($actual && $expected) || (!$actual && !$expected);
$this->assertTrue($val, "_checkUseNonce failed: $msg");
}
function _testNonce(&$store)
{
// Nonce functions
// Random nonce (not in store)
$nonce1 = $this->generateNonce();
// A nonce is not present by default
$this->_checkUseNonce($store, $nonce1, false, 1);
// Storing once causes useNonce to return true the first, and
// only the first, time it is called after the $store->
$store->storeNonce($nonce1);
$this->_checkUseNonce($store, $nonce1, true, 2);
$this->_checkUseNonce($store, $nonce1, false, 3);
$this->_checkUseNonce($store, $nonce1, false, 4);
// Storing twice has the same effect as storing once.
$store->storeNonce($nonce1);
$store->storeNonce($nonce1);
$this->_checkUseNonce($store, $nonce1, true, 5);
$this->_checkUseNonce($store, $nonce1, false, 6);
$this->_checkUseNonce($store, $nonce1, false, 7);
// Auth key functions
// There is no key to start with, so generate a new key and
// return it.
$key = $store->getAuthKey();
// The second time around should return the same as last time.
$key2 = $store->getAuthKey();
$this->assertEquals($key, $key2, "Auth keys differ");
$this->assertEquals(strlen($key), $store->AUTH_KEY_LEN,
"Key length not equals AUTH_KEY_LEN");
}
function test_memstore()
{
require_once 'Tests/Auth/OpenID/MemStore.php';
$store = new Tests_Auth_OpenID_MemStore('Bogus auth key ');
$this->_testStore(&$store);
$this->_testNonce(&$store);
}
function test_filestore()
{
require_once 'Auth/OpenID/FileStore.php';
$temp_dir = _Auth_OpenID_mkdtemp();
if (!$temp_dir) {
trigger_error('Could not create temporary directory ' .
'with Auth_OpenID_FileStore::_mkdtemp',
E_USER_WARNING);
return null;
}
$store = new Auth_OpenID_FileStore($temp_dir);
$this->_testStore($store);
$this->_testNonce($store);
$store->destroy();
}
function test_postgresqlstore()
{
// If the postgres extension isn't loaded or loadable, succeed
// because we can't run the test.
if (!(extension_loaded('pgsql') ||
@dl('pgsql.' . PHP_SHLIB_SUFFIX))) {
$this->pass();
return;
}
require_once 'Auth/OpenID/PostgreSQLStore.php';
require_once 'DB.php';
global $_Auth_OpenID_db_test_host;
$temp_db_name = _Auth_OpenID_getTmpDbName();
$connect_db_name = 'test_master';
$dsn = array(
'phptype' => 'pgsql',
'username' => 'openid_test',
'password' => '',
'hostspec' => $_Auth_OpenID_db_test_host,
'database' => $connect_db_name
);
$allowed_failures = 5;
$result = null;
$sleep_time = 1.0;
$sql = sprintf("CREATE DATABASE %s", $temp_db_name);
for ($failures = 0; $failures < $allowed_failures; $failures++) {
$template_db =& DB::connect($dsn);
if (PEAR::isError($template_db)) {
$result &= $template_db;
} else {
// Try to create the test database.
$result = $template_db->query($sql);
$template_db->disconnect();
unset($template_db);
if (!PEAR::isError($result)) {
break;
}
}
$sleep_time *= ((mt_rand(1, 100) / 100.0) + 1.5);
print "Failed to create database $temp_db_name.\n".
"Waiting $sleep_time before trying again\n";
$int_sleep = floor($sleep_time);
$frac_sleep = $sleep_time - $int_sleep;
sleep($int_sleep);
usleep($frac_sleep * 1000000.0);
}
if ($failures == $allowed_failures) {
$this->fail("Temporary database creation failed after $failures ".
" tries ('$temp_db_name'): " . $result->getMessage());
return;
}
// Disconnect from template1 and reconnect to the temporary
// testing database.
$dsn['database'] = $temp_db_name;
$db =& DB::connect($dsn);
if (PEAR::isError($db)) {
$this->fail("Temporary database connection failed " .
" ('$temp_db_name'): " . $db->getMessage());
return;
}
$store =& new Auth_OpenID_PostgreSQLStore($db);
$store->createTables();
$this->_testStore($store);
$this->_testNonce($store);
$db->disconnect();
unset($db);
// Connect to template1 again so we can drop the temporary
// database.
$dsn['database'] = $connect_db_name;
$template_db =& DB::connect($dsn);
if (PEAR::isError($template_db)) {
$this->fail("Template database connection (to drop " .
"temporary database) failed: " .
$template_db->getMessage());
return;
}
$result = $template_db->query(sprintf("DROP DATABASE %s",
$temp_db_name));
if (PEAR::isError($result)) {
$this->fail("Dropping temporary database failed: " .
$result->getMessage());
return;
}
$template_db->disconnect();
unset($template_db);
}
function test_sqlitestore()
{
// If the postgres extension isn't loaded or loadable, succeed
// because we can't run the test.
if (!(extension_loaded('sqlite') ||
@dl('sqlite.' . PHP_SHLIB_SUFFIX))) {
$this->pass();
return;
}
require_once 'Auth/OpenID/SQLiteStore.php';
require_once 'DB.php';
$temp_dir = _Auth_OpenID_mkdtemp();
if (!$temp_dir) {
trigger_error('Could not create temporary directory ' .
'with Auth_OpenID_FileStore::_mkdtemp',
E_USER_WARNING);
return null;
}
$dsn = sprintf("sqlite:///%s/file.db", $temp_dir);
$db =& DB::connect($dsn);
if (PEAR::isError($db)) {
$this->fail("SQLite database connection failed: " .
$db->getMessage());
} else {
$store =& new Auth_OpenID_SQLiteStore($db);
$this->assertTrue($store->createTables(), "Table creation failed");
$this->_testStore($store);
$this->_testNonce($store);
}
$db->disconnect();
unset($db);
unset($store);
unlink($temp_dir . '/file.db');
rmdir($temp_dir);
}
function test_mysqlstore()
{
// If the mysql extension isn't loaded or loadable, succeed
// because we can't run the test.
if (!(extension_loaded('mysql') ||
@dl('mysql.' . PHP_SHLIB_SUFFIX))) {
$this->pass();
return;
}
require_once 'Auth/OpenID/MySQLStore.php';
require_once 'DB.php';
global $_Auth_OpenID_db_test_host;
$dsn = array(
'phptype' => 'mysql',
'username' => 'openid_test',
'password' => '',
'hostspec' => $_Auth_OpenID_db_test_host
);
$db =& DB::connect($dsn);
if (PEAR::isError($db)) {
print "MySQL database connection failed: " .
$db->getMessage();
$this->pass();
return;
}
$temp_db_name = _Auth_OpenID_getTmpDbName();
$result = $db->query("CREATE DATABASE $temp_db_name");
if (PEAR::isError($result)) {
$this->fail("Error creating MySQL temporary database: " .
$result->getMessage());
return;
}
$db->query("USE $temp_db_name");
$store =& new Auth_OpenID_MySQLStore($db);
$store->createTables();
$this->_testStore($store);
$this->_testNonce($store);
$db->query("DROP DATABASE $temp_db_name");
}
}
?>