$this->assertEquals( $n, $calls );
}
- /**
- * @covers BagOStuff::merge
- * @dataProvider provideTestMerge_fork
- */
- public function testMerge_fork( $exists, $childWins, $resCAS ) {
- $key = $this->cache->makeKey( self::TEST_KEY );
- $pCallback = function ( BagOStuff $cache, $key, $oldVal ) {
- return ( $oldVal === false ) ? 'init-parent' : $oldVal . '-merged-parent';
- };
- $cCallback = function ( BagOStuff $cache, $key, $oldVal ) {
- return ( $oldVal === false ) ? 'init-child' : $oldVal . '-merged-child';
- };
-
- if ( $exists ) {
- $this->cache->set( $key, 'x', 5 );
- }
-
- /*
- * Test concurrent merges by forking this process, if:
- * - not manually called with --use-bagostuff
- * - pcntl_fork is supported by the system
- * - cache type will correctly support calls over forks
- */
- $fork = (bool)$this->getCliArg( 'use-bagostuff' );
- $fork &= function_exists( 'pcntl_fork' );
- $fork &= !$this->cache instanceof HashBagOStuff;
- $fork &= !$this->cache instanceof EmptyBagOStuff;
- $fork &= !$this->cache instanceof MultiWriteBagOStuff;
- if ( $fork ) {
- $pid = null;
- // Function to start merge(), run another merge() midway through, then finish
- $func = function ( $cache, $key, $cur ) use ( $pCallback, $cCallback, &$pid ) {
- $pid = pcntl_fork();
- if ( $pid == -1 ) {
- return false;
- } elseif ( $pid ) {
- pcntl_wait( $status );
-
- return $pCallback( $cache, $key, $cur );
- } else {
- $this->cache->merge( $key, $cCallback, 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, $func, 0, 1 );
-
- if ( $pid == -1 ) {
- return; // can't fork, ignore this test...
- }
-
- // merge has failed because child process was merging (and we only attempted once)
- $this->assertEquals( !$childWins, $merged );
- $this->assertEquals( $this->cache->get( $key ), $resCAS );
- } else {
- $this->markTestSkipped( 'No pcntl methods available' );
- }
- }
-
- function provideTestMerge_fork() {
- return [
- // (already exists, child wins CAS, result of CAS)
- [ false, true, 'init-child' ],
- [ true, true, 'x-merged-child' ]
- ];
- }
-
/**
* @covers BagOStuff::changeTTL
*/