blob: 30a854fb82cfe28475f422661e92b053fa10a32a [file] [log] [blame]
<?php
/**
* ezcCacheStorageFileApcArrayTest
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* 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.
*
* @package Cache
* @subpackage Tests
* @version //autogen//
* @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
*/
/**
* Require parent test class.
*/
require_once 'storage_test.php';
require_once 'wrappers/apc_array_wrapper.php';
/**
* Test suite for ezcCacheStorageFileApcArray class.
*
* @package Cache
* @subpackage Tests
*/
class ezcCacheStorageFileApcArrayTest extends ezcCacheStorageTest
{
/**
* Test data.
*
* @var array(string=>mixed)
*/
protected $testData = array(
0 => array( 'a' ),
1 => array( 1, 2, 3 ),
2 => array( 'a', 1, 'b', 2, 'c', 3 ),
3 => array(
1, 2, 3,
array( 'a', 'b', 'c' ),
4, 5
),
4 => array(
array(
array( 1 ), array( 2, 3 )
),
1, 2, 3,
array( 'a', 'b', 'c' ),
),
5 => "Test 1 2 3 4 5 6 7 8\\\\",
6 => 'La la la 02064 lololo',
7 => true,
// 8 => false, // 6 tests fail with this
9 => 12345,
10 => 12.3746,
);
protected function setUp()
{
if ( !ezcBaseFeatures::hasExtensionSupport( 'apc' ) )
{
$this->markTestSkipped( "PHP must have APC support." );
}
// Class name == <inheriting class> - "Test"
$storageClass = ( $this->storageClass = substr( get_class( $this ), 0, strlen( get_class( $this ) ) - 4 ) );
$this->storage = new $storageClass( $this->createTempDir( 'ezcCacheTest' ), array( 'ttl' => 10 ) );
}
// Override test from parent class
public function testConstructorErrorLocationNotWriteable()
{
return true;
}
// Override test from parent class
public function testStoreRestoreOutdatedWithoutAttributes()
{
$options = array( 'ttl' => 10 );
$storage = new ezcCacheStorageFileApcArrayWrapper( $this->getTempDir(), $options );
foreach ( $this->data as $id => $dataArr )
{
$storage->store( $id, $dataArr );
// Hack the cache to be outdated by 100 seconds
$data = $storage->restore( $id );
$registry = $storage->getRegistry();
foreach ( $registry as $location => $dataObj )
{
if ( isset( $dataObj->data )
&& $dataArr === $dataObj->data
&& strpos( $location, $this->getTempDir() ) !== false )
{
break;
}
}
$registry[$location]->mtime = time() - 100;
$storage->setRegistry( $registry );
$data = $storage->restore( $id );
$this->assertTrue( $data === false, "Restore data broken for ID <{$id}>." );
}
$this->removeTempDir();
}
// Override test from parent class
public function testStoreRestoreOutdatedWithAttributes()
{
$options = array( 'ttl' => 10 );
$storage = new ezcCacheStorageFileApcArrayWrapper( $this->getTempDir(), $options );
foreach ( $this->data as $id => $dataArr )
{
$attributes = array(
'name' => 'test',
'title' => 'Test item',
'date' => time() . $id,
);
$storage->store( $id, $dataArr, $attributes );
// Hack the cache to be outdated by 100 seconds
$data = $storage->restore( $id, $attributes );
$registry = $storage->getRegistry();
foreach ( $registry as $location => $dataObj )
{
if ( isset( $dataObj->data )
&& $dataArr === $dataObj->data
&& strpos( $location, $this->getTempDir() ) !== false )
{
break;
}
}
$registry[$location]->mtime = time() - 100;
$storage->setRegistry( $registry );
// Wait for cache to be outdated.
$data = $storage->restore( $id, $attributes );
$this->assertTrue( $data === false, "Restore data broken for ID <{$id}>." );
}
$this->removeTempDir();
}
public function testMockApcBackend()
{
$apcBackend = $this->getMock( 'ezcCacheApcBackend', array( 'store' ), array() );
$apcBackend->expects( $this->any() )
->method( 'store' )
->will( $this->returnValue( false ) );
$options = array( 'ttl' => 10 );
$storage = new ezcCacheStorageFileApcArrayWrapper( $this->getTempDir(), $options );
$storage->setBackend( $apcBackend );
$id = 'id';
try
{
$storage->store( $id, 'data' );
$this->fail( "Expected exception was not thrown." );
}
catch ( ezcCacheApcException $e )
{
$this->assertEquals( "APC store failed.", $e->getMessage() );
}
$this->removeTempDir();
}
public function testStoreResource()
{
$resource = fopen( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'wrappers' . DIRECTORY_SEPARATOR . 'apc_wrapper.php', 'r' );
try
{
$this->storage->store( "key", $resource );
fclose( $resource );
$this->fail( "Expected exception was not thrown." );
}
catch ( ezcCacheInvalidDataException $e )
{
fclose( $resource );
$this->assertEquals( "The given data was of type 'resource', which can not be stored. Expecting: 'simple, array'.", $e->getMessage() );
}
}
public function testWrapperFetchDataUseApc()
{
$options = array( 'ttl' => 10 );
$storage = new ezcCacheStorageFileApcArrayWrapper( $this->getTempDir(), $options );
$data = 'data';
$key = 'key';
$storage->store( $key, $data );
$storage->restore( $key );
$registry = $storage->getRegistry();
list( $identifier, $dataArr ) = each( $registry );
$dataFetched = $storage->fetchData( $identifier, true );
$this->assertEquals( $data, $dataFetched );
$this->removeTempDir();
}
public function testWrapperPrepareDataUseApcResourceFail()
{
$resource = fopen( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'wrappers' . DIRECTORY_SEPARATOR . 'apc_wrapper.php', 'r' );
$options = array( 'ttl' => 10 );
$storage = new ezcCacheStorageFileApcArrayWrapper( $this->getTempDir(), $options );
try
{
$storage->prepareData( $resource, true );
fclose( $resource );
$this->fail( "Expected exception was not thrown." );
}
catch ( ezcCacheInvalidDataException $e )
{
fclose( $resource );
$this->assertEquals( "The given data was of type 'resource', which can not be stored. Expecting: 'simple, array, object'.", $e->getMessage() );
}
$this->removeTempDir();
}
public function testWrapperCalcLifetimeNoApc()
{
$options = array( 'ttl' => 10 );
$storage = new ezcCacheStorageFileApcArrayWrapper( $this->getTempDir(), $options );
$data = 'data';
$key = 'key';
$filename = $this->getTempDir() . DIRECTORY_SEPARATOR . $storage->generateIdentifier( $key, array() );
file_put_contents( $filename, $data );
$lifetime = $storage->calcLifetime( $filename, false );
// 8 for the case that the second switched just during this request
$this->assertGreaterThan(
8,
$lifetime
);
$this->removeTempDir();
}
public function testCacheManagerLocationEmpty()
{
$options = array( 'ttl' => 10 );
ezcCacheManager::createCache( 'memory', null, 'ezcCacheStorageFileApcArray', $options );
try
{
$storage = ezcCacheManager::getCache( 'memory' );
$this->fail( "Expected exception was not thrown" );
}
catch ( ezcBaseFilePermissionException $e )
{
$this->assertEquals( "The file '/' can not be opened for writing. (Cache location is not a directory.)", $e->getMessage() );
}
}
public function testStorageFileApcArrayOptions()
{
$opt = new ezcCacheStorageFileApcArrayOptions();
$this->assertTrue( isset( $opt->ttl ) );
$this->assertTrue( isset( $opt->extension ) );
$this->assertTrue( isset( $opt->permissions ) );
$this->assertFalse( isset( $opt->foo ) );
$this->assertEquals( $opt->ttl, 86400 );
$this->assertEquals( $opt->extension, ".cache" );
$this->assertEquals( $opt->permissions, 0644 );
$this->assertSetProperty(
$opt,
'ttl',
array( 0, 23, false )
);
$this->assertSetProperty(
$opt,
'permissions',
array( 0777 )
);
$this->assertSetProperty(
$opt,
'extension',
array( '.foo' )
);
$this->assertSetPropertyFails(
$opt,
'ttl',
array( true, 23.42, 'foo', array(), new stdClass() )
);
$this->assertSetPropertyFails(
$opt,
'permissions',
array( true, 23.42, 'foo', array(), new stdClass() )
);
$this->assertSetPropertyFails(
$opt,
'extension',
array( true, false, 23.42, array(), new stdClass() )
);
}
public function testStorageApcOptions()
{
$opt = new ezcCacheStorageFileApcArrayOptions();
$this->assertTrue( isset( $opt->ttl ) );
$this->assertTrue( isset( $opt->extension ) );
$this->assertTrue( isset( $opt->permissions ) );
$this->assertFalse( isset( $opt->foo ) );
$this->assertEquals( $opt->ttl, 86400 );
$this->assertEquals( $opt->extension, ".cache" );
$this->assertEquals( $opt->permissions, 0644 );
$this->assertSetProperty(
$opt,
'ttl',
array( 0, 23, false )
);
$this->assertSetProperty(
$opt,
'permissions',
array( 0, 0777 )
);
$this->assertSetProperty(
$opt,
'extension',
array( '.foo' )
);
$this->assertSetPropertyFails(
$opt,
'ttl',
array( true, 23.42, 'foo', array(), new stdClass() )
);
$this->assertSetPropertyFails(
$opt,
'permissions',
array( true, 23.42, 'foo', array(), new stdClass() )
);
$this->assertSetPropertyFails(
$opt,
'extension',
array( true, false, 23.42, array(), new stdClass() )
);
}
public function testResetSuccess()
{
$options = array( 'ttl' => 10 );
$storage = new ezcCacheStorageFileApcArray( $this->getTempDir( __CLASS__ ), $options );
$storage->reset();
$data = array(
'ID',
'Some/Dir/ID',
'Some/other/Dir/ID/1',
'Some/other/Dir/ID/2',
'Some/other/Dir/ID/3',
);
foreach ( $data as $id )
{
$storage->store( $id, $id );
}
$this->assertEquals(
5,
$storage->countDataItems()
);
$storage->reset();
$this->assertEquals(
0,
$storage->countDataItems()
);
$this->removeTempDir();
}
public function testDeleteReturnIds()
{
$storage = new ezcCacheStorageFileApcArray(
$this->getTempDir( __CLASS__ ),
array( 'ttl' => 100 )
);
$storage->reset();
$data = array(
'ID',
'Some/Dir/ID',
'Some/other/Dir/ID/1',
'Some/other/Dir/ID/2',
'Some/other/Dir/ID/3',
);
$attributes = array(
'lang' => 'en',
);
foreach ( $data as $id )
{
$storage->store( $id, $id, $attributes );
}
$deleted = $storage->delete( 'Some/other/Dir/ID/3', $attributes, true );
$this->assertEquals(
array( 'Some/other/Dir/ID/3' ),
$deleted,
'Deleted IDs not returned correctly.'
);
$deleted = $storage->delete( null, $attributes, true );
$this->assertEquals(
array(
'ID',
'Some/Dir/ID',
'Some/other/Dir/ID/1',
'Some/other/Dir/ID/2',
),
$deleted,
'Deleted IDs not returned correctly.'
);
$this->removeTempDir();
}
public function testPurgeNoLimit()
{
$storage = new ezcCacheStorageFileApcArray(
$this->getTempDir( __FILE__ ),
array( 'ttl' => 1 )
);
$storage->reset();
$data = array(
'ID',
'Some/Dir/ID',
'Some/other/Dir/ID/1',
'Some/other/Dir/ID/2',
'Some/other/Dir/ID/3',
);
foreach ( $data as $id )
{
$storage->store( $id, $id );
}
// Outdate
usleep( 1000002 );
$purgedIds = $storage->purge();
$this->assertEquals(
$data,
$purgedIds,
'Purged IDs not returned correctly.'
);
$this->removeTempDir();
}
public function testPurgeLimit()
{
$storage = new ezcCacheStorageFileApcArray(
$this->getTempDir( __CLASS__ ),
array( 'ttl' => 1 )
);
$storage->reset();
$data = array(
'ID',
'Some/Dir/ID',
'Some/other/Dir/ID/1',
'Some/other/Dir/ID/2',
'Some/other/Dir/ID/3',
);
foreach ( $data as $id )
{
$storage->store( $id, $id );
}
// Outdate
usleep( 1000002 );
$purgedIds = $storage->purge( 3 );
$this->assertEquals(
array(
'ID',
'Some/Dir/ID',
'Some/other/Dir/ID/1',
),
$purgedIds,
'Purged IDs not returned correctly.'
);
$this->removeTempDir();
}
public function testLockSimple()
{
$storage = new ezcCacheStorageFileApcArray(
$this->getTempDir( __CLASS__ ),
array( 'ttl' => 1 )
);
$storage->reset();
$lockKey = urlencode( $storage->getLocation() ) . '_'
. $storage->options->lockKey;
$this->assertFalse(
apc_fetch( $lockKey ),
'Lock key exists.'
);
$this->assertFalse(
$this->readAttribute( $storage, 'lock' ),
'Lock stat not correctly initialized'
);
$storage->lock();
$this->assertNotEquals(
false,
apc_fetch( $lockKey ),
'Lock key not created correctly.'
);
$this->assertTrue(
$this->readAttribute( $storage, 'lock' ),
'Lock stat not correctly switched.'
);
$storage->unlock();
$this->assertFalse(
apc_fetch( $lockKey ),
'Lock key exists.'
);
$this->assertFalse(
$this->readAttribute( $storage, 'lock' ),
'Lock stat not correctly initialized'
);
$this->removeTempDir();
}
public function testLockTimeout()
{
// Init 2 storages on same Memcache
$opts = array(
'ttl' => 1,
'maxLockTime' => 1
);
$storage = new ezcCacheStorageFileApcArray(
$this->getTempDir( '1' . __CLASS__ ),
$opts
);
$storage->reset();
$secondStorage = new ezcCacheStorageFileApcArray(
$this->getTempDir( '2' . __CLASS__ ),
$opts
);
$secondStorage->reset();
$lockKey = urlencode( $storage->getLocation() ) . '_'
. $storage->options->lockKey;
// Assert initial state
$this->assertFalse(
apc_fetch( $lockKey ),
'Lock key exists.'
);
$this->assertFalse(
$this->readAttribute( $storage, 'lock' ),
'Lock state not correctly initialized'
);
$this->assertFalse(
$this->readAttribute( $secondStorage, 'lock' ),
'Lock state not correctly initialized in second storage'
);
$lockTime = time();
// Perform lock
$storage->lock();
// Assert locked state
$this->assertNotEquals(
false,
( $oldLock = apc_fetch( $lockKey ) ),
'Lock key not created correctly.'
);
$this->assertTrue(
$this->readAttribute( $storage, 'lock' ),
'Lock stat not correctly switched.'
);
$this->assertFalse(
$this->readAttribute( $secondStorage, 'lock' ),
'Lock state not correctly initialized in second storage'
);
// Should kill lock file after 1 sec
$secondStorage->lock();
// Assert that kill did not occur earlier
$this->assertGreaterThanOrEqual(
1,
( time() - $lockTime ),
'Lock did not last for 1 sec.'
);
// Assert that lock key exists again
$this->assertNotEquals(
false,
apc_fetch( $lockKey ),
'Lock key not created correctly.'
);
// Assert that the new lock is not the same as the old one
$this->assertGreaterThan(
$oldLock,
apc_fetch( $lockKey ),
'Lock key not created correctly.'
);
// First storage does not note that its lock disappeared
$this->assertTrue(
$this->readAttribute( $storage, 'lock' ),
'Lock state switched unexpectedly.'
);
// Second storage now has the lock
$this->assertTrue(
$this->readAttribute( $secondStorage, 'lock' ),
'Lock state not correctly initialized in second storage'
);
$secondStorage->unlock();
$this->assertFalse(
apc_fetch( $lockKey ),
'Lock key not created correctly.'
);
// First storage does not note that its lock disappeared and was not unlocked
$this->assertTrue(
$this->readAttribute( $storage, 'lock' ),
'Lock state switched unexpectedly.'
);
// Second storage released the lock
$this->assertFalse(
$this->readAttribute( $secondStorage, 'lock' ),
'Lock state not correctly initialized in second storage'
);
$this->removeTempDir();
}
public function testMetaDataSuccess()
{
$storage = new ezcCacheStorageFileApcArray(
$this->getTempDir( __CLASS__ ),
array( 'ttl' => 1 )
);
$storage->reset();
$metaDataKey = urlencode( $storage->getLocation() ) . '_'
. $storage->options->metaDataKey;
$meta = new ezcCacheStackLruMetaData();
$meta->setState(
array(
'replacementData' => array(
'id_1' => 23,
'id_2' => 42,
),
'storageData' => array(
'storage_id_1' => array(
'id_1' => true,
'id_2' => true,
),
'storage_id_2' => array(
'id_2' => true,
),
),
)
);
$this->assertFalse(
apc_fetch( $metaDataKey ),
'Meta data key existed before the storage was created.'
);
$storage->storeMetaData( $meta );
$this->assertEquals(
$meta,
apc_fetch( $metaDataKey )->var,
'Meta data file existed before the storage was created.'
);
$restoredMeta = $storage->restoreMetaData();
$this->assertEquals(
$meta,
$restoredMeta,
'Meta data not restored correctly.'
);
$this->assertEquals(
$meta,
apc_fetch( $metaDataKey )->var,
'Meta data file existed before the storage was created.'
);
$this->removeTempDir();
}
public function testMetaDataFailure()
{
$storage = new ezcCacheStorageFileApcArray(
$this->getTempDir( __CLASS__ ),
array( 'ttl' => 1 )
);
$storage->reset();
$metaDataKey = urlencode( $storage->getLocation() ) . '_'
. $storage->options->metaDataKey;
$this->assertFalse(
apc_fetch( $metaDataKey ),
'Meta data file existed before the storage was created.'
);
$restoredMeta = $storage->restoreMetaData();
$this->assertNull(
$restoredMeta,
'Meta data not restored correctly.'
);
$this->assertFalse(
apc_fetch( $metaDataKey ),
'Meta data file existed before the storage was created.'
);
$this->removeTempDir();
}
public static function suite()
{
return new PHPUnit_Framework_TestSuite( __CLASS__ );
}
}
?>