/** @var BagOStuff */
private $cache;
+ const TEST_KEY = 'test';
+
protected function setUp() {
parent::setUp();
$this->cache = new HashBagOStuff;
}
- $this->cache->delete( wfMemcKey( 'test' ) );
+ $this->cache->delete( $this->cache->makeKey( self::TEST_KEY ) );
}
/**
/**
* @covers BagOStuff::merge
* @covers BagOStuff::mergeViaLock
+ * @covers BagOStuff::mergeViaCas
*/
public function testMerge() {
- $key = wfMemcKey( 'test' );
-
- $usleep = 0;
-
- /**
- * Callback method: append "merged" to whatever is in cache.
- *
- * @param BagOStuff $cache
- * @param string $key
- * @param int $existingValue
- * @use int $usleep
- * @return int
- */
- $callback = function ( BagOStuff $cache, $key, $existingValue ) use ( &$usleep ) {
- // let's pretend this is an expensive callback to test concurrent merge attempts
- usleep( $usleep );
-
- if ( $existingValue === false ) {
- return 'merged';
- }
-
- return $existingValue . 'merged';
+ $key = $this->cache->makeKey( self::TEST_KEY );
+ $callback = function ( BagOStuff $cache, $key, $oldVal ) {
+ return ( $oldVal === false ) ? 'merged' : $oldVal . 'merged';
};
// merge on non-existing value
- $merged = $this->cache->merge( $key, $callback, 0 );
+ $merged = $this->cache->merge( $key, $callback, 5 );
$this->assertTrue( $merged );
$this->assertEquals( $this->cache->get( $key ), 'merged' );
// merge on existing value
- $merged = $this->cache->merge( $key, $callback, 0 );
+ $merged = $this->cache->merge( $key, $callback, 5 );
$this->assertTrue( $merged );
$this->assertEquals( $this->cache->get( $key ), 'mergedmerged' );
+ }
+ /**
+ * @covers BagOStuff::merge
+ * @covers BagOStuff::mergeViaLock
+ */
+ public function testMerge_fork() {
+ $key = $this->cache->makeKey( self::TEST_KEY );
+ $callback = function ( BagOStuff $cache, $key, $oldVal ) {
+ return ( $oldVal === false ) ? 'merged' : $oldVal . 'merged';
+ };
/*
* Test concurrent merges by forking this process, if:
* - not manually called with --use-bagostuff
$fork &= !$this->cache instanceof EmptyBagOStuff;
$fork &= !$this->cache instanceof MultiWriteBagOStuff;
if ( $fork ) {
- // callback should take awhile now so that we can test concurrent merge attempts
- $pid = pcntl_fork();
+ $pid = null;
+ // Function to start merge(), run another merge() midway through, then finish
+ $outerFunc = function ( BagOStuff $cache, $key, $oldVal ) use ( $callback, &$pid ) {
+ $pid = pcntl_fork();
+ if ( $pid == -1 ) {
+ return false;
+ } elseif ( $pid ) {
+ pcntl_wait( $status );
+
+ return $callback( $cache, $key, $oldVal );
+ } else {
+ $this->cache->merge( $key, $callback, 0, 1 );
+ // Bail out of the outer merge() in the child process since it does not
+ // need to attempt to write anything. Success is checked by the parent.
+ parent::tearDown(); // avoid phpunit notices
+ exit;
+ }
+ };
+
+ // attempt a merge - this should fail
+ $merged = $this->cache->merge( $key, $outerFunc, 0, 1 );
+
if ( $pid == -1 ) {
- // can't fork, ignore this test...
- } elseif ( $pid ) {
- // wait a little, making sure that the child process is calling merge
- usleep( 3000 );
-
- // attempt a merge - this should fail
- $merged = $this->cache->merge( $key, $callback, 0, 1 );
-
- // merge has failed because child process was merging (and we only attempted once)
- $this->assertFalse( $merged );
-
- // make sure the child's merge is completed and verify
- usleep( 3000 );
- $this->assertEquals( $this->cache->get( $key ), 'mergedmergedmerged' );
- } else {
- $this->cache->merge( $key, $callback, 0, 1 );
-
- // Note: I'm not even going to check if the merge worked, I'll
- // compare values in the parent process to test if this merge worked.
- // I'm just going to exit this child process, since I don't want the
- // child to output any test results (would be rather confusing to
- // have test output twice)
- exit;
+ return; // can't fork, ignore this test...
}
+
+ // merge has failed because child process was merging (and we only attempted once)
+ $this->assertFalse( $merged );
+
+ // make sure the child's merge is completed and verify
+ $this->assertEquals( $this->cache->get( $key ), 'mergedmerged' );
+ } else {
+ $this->markTestSkipped( 'No pcntl methods available' );
}
}
* @covers BagOStuff::changeTTL
*/
public function testChangeTTL() {
- $key = wfMemcKey( 'test' );
+ $key = $this->cache->makeKey( self::TEST_KEY );
$value = 'meow';
- $this->cache->add( $key, $value );
+ $this->cache->add( $key, $value, 5 );
$this->assertTrue( $this->cache->changeTTL( $key, 5 ) );
$this->assertEquals( $this->cache->get( $key ), $value );
$this->cache->delete( $key );
* @covers BagOStuff::add
*/
public function testAdd() {
- $key = wfMemcKey( 'test' );
- $this->assertTrue( $this->cache->add( $key, 'test' ) );
+ $key = $this->cache->makeKey( self::TEST_KEY );
+ $this->assertTrue( $this->cache->add( $key, 'test', 5 ) );
}
/**
public function testGet() {
$value = [ 'this' => 'is', 'a' => 'test' ];
- $key = wfMemcKey( 'test' );
- $this->cache->add( $key, $value );
+ $key = $this->cache->makeKey( self::TEST_KEY );
+ $this->cache->add( $key, $value, 5 );
$this->assertEquals( $this->cache->get( $key ), $value );
}
/**
+ * @covers BagOStuff::get
+ * @covers BagOStuff::set
* @covers BagOStuff::getWithSetCallback
*/
public function testGetWithSetCallback() {
- $key = wfMemcKey( 'test' );
+ $key = $this->cache->makeKey( self::TEST_KEY );
$value = $this->cache->getWithSetCallback(
$key,
30,
* @covers BagOStuff::incr
*/
public function testIncr() {
- $key = wfMemcKey( 'test' );
- $this->cache->add( $key, 0 );
+ $key = $this->cache->makeKey( self::TEST_KEY );
+ $this->cache->add( $key, 0, 5 );
$this->cache->incr( $key );
$expectedValue = 1;
$actualValue = $this->cache->get( $key );
* @covers BagOStuff::incrWithInit
*/
public function testIncrWithInit() {
- $key = wfMemcKey( 'test' );
+ $key = $this->cache->makeKey( self::TEST_KEY );
$val = $this->cache->incrWithInit( $key, 0, 1, 3 );
$this->assertEquals( 3, $val, "Correct init value" );
$value3 = [ 'testing a key that may be encoded when sent to cache backend' ];
$value4 = [ 'another test where chars in key will be encoded' ];
- $key1 = wfMemcKey( 'test1' );
- $key2 = wfMemcKey( 'test2' );
+ $key1 = $this->cache->makeKey( 'test-1' );
+ $key2 = $this->cache->makeKey( 'test-2' );
// internally, MemcachedBagOStuffs will encode to will-%25-encode
- $key3 = wfMemcKey( 'will-%-encode' );
- $key4 = wfMemcKey(
+ $key3 = $this->cache->makeKey( 'will-%-encode' );
+ $key4 = $this->cache->makeKey(
'flowdb:flow_ref:wiki:by-source:v3:Parser\'s_"broken"_+_(page)_&_grill:testwiki:1:4.7'
);
- $this->cache->add( $key1, $value1 );
- $this->cache->add( $key2, $value2 );
- $this->cache->add( $key3, $value3 );
- $this->cache->add( $key4, $value4 );
+ // cleanup
+ $this->cache->delete( $key1 );
+ $this->cache->delete( $key2 );
+ $this->cache->delete( $key3 );
+ $this->cache->delete( $key4 );
+
+ $this->cache->add( $key1, $value1, 5 );
+ $this->cache->add( $key2, $value2, 5 );
+ $this->cache->add( $key3, $value3, 5 );
+ $this->cache->add( $key4, $value4, 5 );
$this->assertEquals(
[ $key1 => $value1, $key2 => $value2, $key3 => $value3, $key4 => $value4 ],
* @covers BagOStuff::getScopedLock
*/
public function testGetScopedLock() {
- $key = wfMemcKey( 'test' );
+ $key = $this->cache->makeKey( self::TEST_KEY );
$value1 = $this->cache->getScopedLock( $key, 0 );
$value2 = $this->cache->getScopedLock( $key, 0 );