From 44b06f908ec6e013e5dc3c20418269199ab7e246 Mon Sep 17 00:00:00 2001 From: Antoine Musso Date: Wed, 11 Jan 2012 09:05:56 +0000 Subject: [PATCH] reverts Concurrency works trunk is frozen pending stabilisation so we can release MediaWiki 1.19. Those changes introduces API changes and new SQL tables, so that sounds like new feature we do not have time to review right now. Please reapply changes in branches/concurrency and have code review handled there. Once the branch has been reviewed, please hold. Once trunk is stable enough and 1.19 got branched, you are welcome to merge the branch in trunk. Note: we can have a Jenkins jobs setup to run the branch tests if you need. Reverts: r108595 r108591 r108585 r108584 108572 r108564 108560 r108559 --- includes/AutoLoader.php | 3 +- includes/ConcurrencyCheck.php | 358 ------------------ includes/DefaultSettings.php | 10 - includes/api/ApiConcurrency.php | 105 ----- includes/api/ApiMain.php | 1 - includes/installer/MysqlUpdater.php | 1 - includes/installer/SqliteUpdater.php | 1 - .../archives/patch-concurrencycheck.sql | 25 -- .../archives/patch-concurrencycheck.sql | 25 -- maintenance/tables.sql | 27 -- .../phpunit/includes/ConcurrencyCheckTest.php | 106 ------ .../includes/api/ApiConcurrencyTest.php | 172 --------- 12 files changed, 1 insertion(+), 833 deletions(-) delete mode 100644 includes/ConcurrencyCheck.php delete mode 100644 includes/api/ApiConcurrency.php delete mode 100644 maintenance/archives/patch-concurrencycheck.sql delete mode 100644 maintenance/sqlite/archives/patch-concurrencycheck.sql delete mode 100644 tests/phpunit/includes/ConcurrencyCheckTest.php delete mode 100644 tests/phpunit/includes/api/ApiConcurrencyTest.php diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 9136b9eb2d..61ae868501 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -43,7 +43,6 @@ $wgAutoloadLocalClasses = array( 'ChannelFeed' => 'includes/Feed.php', 'Collation' => 'includes/Collation.php', 'ConcatenatedGzipHistoryBlob' => 'includes/HistoryBlob.php', - 'ConcurrencyCheck' => 'includes/ConcurrencyCheck.php', 'ConfEditor' => 'includes/ConfEditor.php', 'ConfEditorParseError' => 'includes/ConfEditor.php', 'ConfEditorToken' => 'includes/ConfEditor.php', @@ -53,6 +52,7 @@ $wgAutoloadLocalClasses = array( 'DeferredUpdates' => 'includes/DeferredUpdates.php', 'DerivativeRequest' => 'includes/WebRequest.php', 'DiffHistoryBlob' => 'includes/HistoryBlob.php', + 'DoubleReplacer' => 'includes/StringUtils.php', 'DummyLinker' => 'includes/Linker.php', 'Dump7ZipOutput' => 'includes/Export.php', @@ -271,7 +271,6 @@ $wgAutoloadLocalClasses = array( 'ApiBase' => 'includes/api/ApiBase.php', 'ApiBlock' => 'includes/api/ApiBlock.php', 'ApiComparePages' => 'includes/api/ApiComparePages.php', - 'ApiConcurrency' => 'includes/api/ApiConcurrency.php', 'ApiDelete' => 'includes/api/ApiDelete.php', 'ApiDisabled' => 'includes/api/ApiDisabled.php', 'ApiEditPage' => 'includes/api/ApiEditPage.php', diff --git a/includes/ConcurrencyCheck.php b/includes/ConcurrencyCheck.php deleted file mode 100644 index f4391294ae..0000000000 --- a/includes/ConcurrencyCheck.php +++ /dev/null @@ -1,358 +0,0 @@ - - */ -class ConcurrencyCheck { - - protected $expirationTime; - - /** - * @var User - */ - protected $user; - - /** - * Constructor - * - * @var $resourceType String The calling application or type of resource, conceptually like a namespace - * @var $user User object, the current user - * @var $expirationTime Integer (optional) How long should a checkout last, in seconds - */ - public function __construct( $resourceType, $user, $expirationTime = null ) { - - // All database calls are to the master, since the whole point of this class is maintaining - // concurrency. Most reads should come from cache anyway. - $this->dbw = wfGetDb( DB_MASTER ); - - $this->user = $user; - // TODO: create a registry of all valid resourceTypes that client app can add to. - $this->resourceType = $resourceType; - $this->setExpirationTime( $expirationTime ); - } - - /** - * Check out a resource. This establishes an atomically generated, cooperative lock - * on a key. The lock is tied to the current user. - * - * @var $record Integer containing the record id to check out - * @var $override Boolean (optional) describing whether to override an existing checkout - * @return boolean - */ - public function checkout( $record, $override = null ) { - global $wgMemc; - $this->validateId( $record ); - $dbw = $this->dbw; - $userId = $this->user->getId(); - $cacheKey = wfMemcKey( 'concurrencycheck', $this->resourceType, $record ); - - // when operating with a single memcached cluster, it's reasonable to check the cache here. - global $wgConcurrency; - if( $wgConcurrency['TrustMemc'] ) { - $cached = $wgMemc->get( $cacheKey ); - if( $cached ) { - if( ! $override && $cached['userId'] != $userId && $cached['expiration'] > time() ) { - // this is already checked out. - return false; - } - } - } - - // attempt an insert, check success (this is atomic) - $insertError = null; - $res = $dbw->insert( - 'concurrencycheck', - array( - 'cc_resource_type' => $this->resourceType, - 'cc_record' => $record, - 'cc_user' => $userId, - 'cc_expiration' => wfTimestamp( TS_MW, time() + $this->expirationTime ), - ), - __METHOD__, - array( 'IGNORE' ) - ); - - // if the insert succeeded, checkout is done. - if( $dbw->affectedRows() === 1 ) { - // delete any existing cache key. can't create a new key here - // since the insert didn't happen inside a transaction. - $wgMemc->delete( $cacheKey ); - return true; - } - - // if the insert failed, it's necessary to check the expiration. - // here, check by deleting, since that permits the use of write locks - // (SELECT..LOCK IN SHARE MODE), rather than read locks (SELECT..FOR UPDATE) - $dbw->begin(); - $dbw->delete( - 'concurrencycheck', - array( - 'cc_resource_type' => $this->resourceType, - 'cc_record' => $record, - '(cc_user = ' . $userId . ' OR cc_expiration <= ' . $dbw->addQuotes(wfTimestamp( TS_MW )) . ')', // only the owner can perform a checkin - ), - __METHOD__, - array() - ); - - // delete failed: not checked out by current user, checkout is unexpired, override is unset - if( $dbw->affectedRows() !== 1 && ! $override) { - // fetch the existing data to cache it - $row = $dbw->selectRow( - 'concurrencycheck', - array( '*' ), - array( - 'cc_resource_type' => $this->resourceType, - 'cc_record' => $record, - ), - __METHOD__, - array() - ); - - // this was a cache miss. populate the cache with data from the db. - // cache is set to expire at the same time as the checkout, since it'll become invalid then anyway. - // inside this transaction, a row-level lock is established which ensures cache concurrency - $wgMemc->set( $cacheKey, array( 'userId' => $row->cc_user, 'expiration' => wfTimestamp( TS_UNIX, $row->cc_expiration ) ), wfTimestamp( TS_UNIX, $row->cc_expiration ) - time() ); - $dbw->rollback(); - return false; - } - - $expiration = time() + $this->expirationTime; - - // delete succeeded, insert a new row. - // replace is used here to support the override parameter - $res = $dbw->replace( - 'concurrencycheck', - array( 'cc_resource_type', 'cc_record' ), - array( - 'cc_resource_type' => $this->resourceType, - 'cc_record' => $record, - 'cc_user' => $userId, - 'cc_expiration' => wfTimestamp( TS_MW, $expiration ), - ), - __METHOD__ - ); - - // cache the result. - $wgMemc->set( $cacheKey, array( 'userId' => $userId, 'expiration' => $expiration ), $this->expirationTime ); - - $dbw->commit(); - return true; - } - - /** - * Check in a resource. Only works if the resource is checked out by the current user. - * - * @var $record Integer containing the record id to checkin - * @return Boolean - */ - public function checkin( $record ) { - global $wgMemc; - $this->validateId( $record ); - $dbw = $this->dbw; - $userId = $this->user->getId(); - $cacheKey = wfMemcKey( 'concurrencycheck', $this->resourceType, $record ); - - $dbw->delete( - 'concurrencycheck', - array( - 'cc_resource_type' => $this->resourceType, - 'cc_record' => $record, - 'cc_user' => $userId, // only the owner can perform a checkin - ), - __METHOD__, - array() - ); - - // check row count (this is atomic, select would not be) - if( $dbw->affectedRows() === 1 ) { - $wgMemc->delete( $cacheKey ); - return true; - } - - return false; - } - - /** - * Remove all expired checkouts. - * - * @return Integer describing the number of records expired. - */ - public function expire() { - // TODO: run this in a few other places that db access happens, to make sure the db stays non-crufty. - $dbw = $this->dbw; - $now = time(); - - // remove the rows from the db. trust memcached to expire the cache. - $dbw->delete( - 'concurrencycheck', - array( - 'cc_expiration <= ' . $dbw->addQuotes( wfTimestamp( TS_MW, $now ) ), - ), - __METHOD__, - array() - ); - - // return the number of rows removed. - return $dbw->affectedRows(); - } - - public function status( $keys ) { - global $wgMemc, $wgDBtype; - $dbw = $this->dbw; - $now = time(); - - $checkouts = array(); - $toSelect = array(); - - // validate keys, attempt to retrieve from cache. - foreach( $keys as $key ) { - $this->validateId( $key ); - - $cached = $wgMemc->get( wfMemcKey( 'concurrencycheck', $this->resourceType, $key ) ); - if( $cached && $cached['expiration'] > $now ) { - $checkouts[$key] = array( - 'status' => 'valid', - 'cc_resource_type' => $this->resourceType, - 'cc_record' => $key, - 'cc_user' => $cached['userId'], - 'cc_expiration' => wfTimestamp( TS_MW, $cached['expiration'] ), - 'cache' => 'cached', - ); - } else { - $toSelect[] = $key; - } - } - - // if there were cache misses... - if( $toSelect ) { - // If it's time to go to the database, go ahead and expire old rows. - $this->expire(); - - - // Why LOCK IN SHARE MODE, you might ask? To avoid a race condition: Otherwise, it's possible for - // a checkin and/or checkout to occur between this select and the value being stored in cache, which - // makes for an incorrect cache. This, in turn, could make checkout() above (which uses the cache) - // function incorrectly. - // - // Another option would be to run the select, then check each row in-turn before setting the cache - // key using either SELECT (with LOCK IN SHARE MODE) or UPDATE that checks a timestamp (and which - // would establish the same lock). That method would mean smaller, quicker locks, but more overall - // database overhead. - // - // It appears all the DBMSes we use support LOCK IN SHARE MODE, but if that's not the case, the second - // solution above could be implemented instead. - $queryParams = array(); - if( $wgDBtype === 'mysql' ) { - $queryParamsp[] = 'LOCK IN SHARE MODE'; - - // the transaction seems incongruous, I know, but it's to keep the cache update atomic. - $dbw->begin(); - } - - $res = $dbw->select( - 'concurrencycheck', - array( '*' ), - array( - 'cc_resource_type' => $this->resourceType, - 'cc_record' => $toSelect, - 'cc_expiration > ' . $dbw->addQuotes( wfTimestamp( TS_MW ) ), - ), - __METHOD__, - $queryParams - ); - - while( $res && $record = $res->fetchRow() ) { - $record['status'] = 'valid'; - $checkouts[ $record['cc_record'] ] = $record; - - // TODO: implement strategy #2 above, determine which DBMSes need which method. - // for now, disable adding to cache here for databases that don't support read locking - if( $wgDBtype !== 'mysql' ) { - // safe to store values since this is inside the transaction - $wgMemc->set( - wfMemcKey( 'concurrencycheck', $this->resourceType, $record['cc_record'] ), - array( 'userId' => $record['cc_user'], 'expiration' => wfTimestamp( TS_UNIX, $record['cc_expiration'] ) ), - wfTimestamp( TS_UNIX, $record['cc_expiration'] ) - time() - ); - } - } - - if( $wgDBtype === 'mysql' ) { - // end the transaction. - $dbw->rollback(); - } - } - - // if a key was passed in but has no (unexpired) checkout, include it in the - // result set to make things easier and more consistent on the client-side. - foreach( $keys as $key ) { - if( ! array_key_exists( $key, $checkouts ) ) { - $checkouts[$key]['status'] = 'invalid'; - } - } - - return $checkouts; - } - - public function listCheckouts() { - // TODO: fill in the function that lets you get the complete set of checkouts for a given application. - } - - /** - * @param $user user - */ - public function setUser( $user ) { - $this->user = $user; - } - - public function setExpirationTime( $expirationTime = null ) { - global $wgConcurrency; - - // check to make sure the time is a number - // negative number are allowed, though mostly only used for testing - if( $expirationTime && (int) $expirationTime == $expirationTime ) { - if( $expirationTime > $wgConcurrency['ExpirationMax'] ) { - $this->expirationTime = $wgConcurrency['ExpirationMax']; // if the number is too high, limit it to the max value. - } elseif ( $expirationTime < $wgConcurrency['ExpirationMin'] ) { - $this->expirationTime = $wgConcurrency['ExpirationMin']; // low limit, default -1 min - } else { - $this->expirationTime = $expirationTime; // the amount of time before a checkout expires. - } - } else { - $this->expirationTime = $wgConcurrency['ExpirationDefault']; // global default is 15 mins. - } - } - - /** - * Check to make sure a record ID is numeric, throw an exception if not. - * - * @var $record Integer - * @throws ConcurrencyCheckBadRecordIdException - * @return boolean - */ - private static function validateId ( $record ) { - if( (int) $record !== $record || $record <= 0 ) { - throw new ConcurrencyCheckBadRecordIdException( 'Record ID ' . $record . ' must be a positive integer' ); - } - - // TODO: add a hook here for client-side validation. - return true; - } -} - -class ConcurrencyCheckBadRecordIdException extends MWException {} diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index d7b9304940..e86f0f7609 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -5716,16 +5716,6 @@ $wgSeleniumConfigFile = null; $wgDBtestuser = ''; //db user that has permission to create and drop the test databases only $wgDBtestpassword = ''; -/** - * ConcurrencyCheck keeps track of which web resources are in use, for producing higher-quality UI - */ -$wgConcurrency = array(); -$wgConcurrency['ExpirationDefault'] = 60 * 15; // Default checkout duration. 15 minutes. -$wgConcurrency['ExpirationMax'] = 60 * 30; // Maximum possible checkout duration. 30 minutes. -$wgConcurrency['ExpirationMin'] = 1; // Minimum possible checkout duration. Negative is possible for testing if you want. -$wgConcurrency['TrustMemc'] = true; // If running in an environment with multiple discrete caches, set to false. - - /** * For really cool vim folding this needs to be at the end: * vim: foldmarker=@{,@} foldmethod=marker diff --git a/includes/api/ApiConcurrency.php b/includes/api/ApiConcurrency.php deleted file mode 100644 index 4eeaeab214..0000000000 --- a/includes/api/ApiConcurrency.php +++ /dev/null @@ -1,105 +0,0 @@ -checkPermission( $wgUser ); - - $params = $this->extractRequestParams(); - - $res = array(); - - $concurrencyCheck = new ConcurrencyCheck( $params['resourcetype'], $wgUser ); - - switch ( $params['ccaction'] ) { - case 'checkout': - case 'checkin': - if ( $concurrencyCheck->$params['ccaction']( $params['record'] ) ) { - $res['result'] = 'success'; - } else { - $res['result'] = 'failure'; - } - break; - - default: - ApiBase::dieDebug( __METHOD__, "Unhandled concurrency action: {$params['ccaction']}" ); - } - - $this->getResult()->addValue( null, $this->getModuleName(), $res ); - } - - public function mustBePosted() { - return true; - } - - public function isWriteMode() { - return true; - } - - public function getAllowedParams() { - return array( - 'resourcetype' => array( - ApiBase::PARAM_TYPE => 'string', - ApiBase::PARAM_REQUIRED => true - ), - 'record' => array( - ApiBase::PARAM_TYPE => 'integer', - ApiBase::PARAM_REQUIRED => true - ), - 'token' => null, - 'expiry' => array( - ApiBase::PARAM_TYPE => 'integer' - ), - 'ccaction' => array( - ApiBase::PARAM_REQUIRED => true, - ApiBase::PARAM_TYPE => array( - 'checkout', - 'checkin', - ), - ), - ); - } - - public function getParamDescription() { - return array( - 'resourcetype' => 'the resource type for concurrency check', - 'record' => 'an unique identifier for a record of the defined resource type', - 'expiry' => 'the time interval for expiration', - 'ccaction' => 'the action for concurrency check', - ); - } - - public function getDescription() { - return 'Get/Set a concurrency check for a web resource type'; - } - - public function needsToken() { - return true; - } - - public function getTokenSalt() { - return ''; - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } - - private function checkPermission( $user ) { - if ( $user->isAnon() ) { - $this->dieUsage( "You don't have permission to do that", 'permission-denied' ); - } - if ( $user->isBlocked( false ) ) { - $this->dieUsageMsg( array( 'blockedtext' ) ); - } - } - -} diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index 03d6dea8e6..32197092d2 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -79,7 +79,6 @@ class ApiMain extends ApiBase { 'patrol' => 'ApiPatrol', 'import' => 'ApiImport', 'userrights' => 'ApiUserrights', - 'concurrency' => 'ApiConcurrency', ); /** diff --git a/includes/installer/MysqlUpdater.php b/includes/installer/MysqlUpdater.php index 1c2c1115d8..a5ffea4e24 100644 --- a/includes/installer/MysqlUpdater.php +++ b/includes/installer/MysqlUpdater.php @@ -192,7 +192,6 @@ class MysqlUpdater extends DatabaseUpdater { array( 'modifyField', 'user', 'ug_group', 'patch-ug_group-length-increase.sql' ), array( 'addField', 'uploadstash', 'us_chunk_inx', 'patch-uploadstash_chunk.sql' ), array( 'addfield', 'job', 'job_timestamp', 'patch-jobs-add-timestamp.sql' ), - array( 'addTable', 'concurrencycheck', 'patch-concurrencycheck.sql'), ); } diff --git a/includes/installer/SqliteUpdater.php b/includes/installer/SqliteUpdater.php index e89e382730..fdb64378cd 100644 --- a/includes/installer/SqliteUpdater.php +++ b/includes/installer/SqliteUpdater.php @@ -71,7 +71,6 @@ class SqliteUpdater extends DatabaseUpdater { array( 'modifyField', 'user', 'ug_group', 'patch-ug_group-length-increase.sql' ), array( 'addField', 'uploadstash', 'us_chunk_inx', 'patch-uploadstash_chunk.sql' ), array( 'addfield', 'job', 'job_timestamp', 'patch-jobs-add-timestamp.sql' ), - array( 'addTable', 'concurrencycheck', 'patch-concurrencycheck.sql'), ); } diff --git a/maintenance/archives/patch-concurrencycheck.sql b/maintenance/archives/patch-concurrencycheck.sql deleted file mode 100644 index f76b923541..0000000000 --- a/maintenance/archives/patch-concurrencycheck.sql +++ /dev/null @@ -1,25 +0,0 @@ --- --- Store atomic locking information for web resources, to permit --- UI that warns users when concurrently editing things that aren't --- concurrently editable. --- -CREATE TABLE /*_*/concurrencycheck ( - -- a string describing the resource or application being checked out. - cc_resource_type varchar(255) NOT NULL, - - -- the (numeric) ID of the record that's being checked out. - cc_record int unsigned NOT NULL, - - -- the user who has control of the resource - cc_user int unsigned NOT NULL, - - -- the date/time on which this record expires - cc_expiration varbinary(14) not null - -) /*$wgDBTableOptions*/; --- composite pk. -CREATE UNIQUE INDEX /*i*/cc_resource_record ON /*_*/concurrencycheck (cc_resource_type, cc_record); --- sometimes there's a delete based on userid. -CREATE INDEX /*i*/cc_user ON /*_*/concurrencycheck (cc_user); --- sometimes there's a delete based on expiration -CREATE INDEX /*i*/cc_expiration ON /*_*/concurrencycheck (cc_expiration); diff --git a/maintenance/sqlite/archives/patch-concurrencycheck.sql b/maintenance/sqlite/archives/patch-concurrencycheck.sql deleted file mode 100644 index f76b923541..0000000000 --- a/maintenance/sqlite/archives/patch-concurrencycheck.sql +++ /dev/null @@ -1,25 +0,0 @@ --- --- Store atomic locking information for web resources, to permit --- UI that warns users when concurrently editing things that aren't --- concurrently editable. --- -CREATE TABLE /*_*/concurrencycheck ( - -- a string describing the resource or application being checked out. - cc_resource_type varchar(255) NOT NULL, - - -- the (numeric) ID of the record that's being checked out. - cc_record int unsigned NOT NULL, - - -- the user who has control of the resource - cc_user int unsigned NOT NULL, - - -- the date/time on which this record expires - cc_expiration varbinary(14) not null - -) /*$wgDBTableOptions*/; --- composite pk. -CREATE UNIQUE INDEX /*i*/cc_resource_record ON /*_*/concurrencycheck (cc_resource_type, cc_record); --- sometimes there's a delete based on userid. -CREATE INDEX /*i*/cc_user ON /*_*/concurrencycheck (cc_user); --- sometimes there's a delete based on expiration -CREATE INDEX /*i*/cc_expiration ON /*_*/concurrencycheck (cc_expiration); diff --git a/maintenance/tables.sql b/maintenance/tables.sql index f82e068059..f43e613c7d 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -1483,31 +1483,4 @@ CREATE TABLE /*_*/config ( -- Should cover *most* configuration - strings, ints, bools, etc. CREATE INDEX /*i*/cf_name_value ON /*_*/config (cf_name,cf_value(255)); --- --- Store atomic locking information for web resources, to permit --- UI that warns users when concurrently editing things that aren't --- concurrently editable. --- -CREATE TABLE /*_*/concurrencycheck ( - -- a string describing the resource or application being checked out. - cc_resource_type varchar(255) NOT NULL, - - -- the (numeric) ID of the record that's being checked out. - cc_record int unsigned NOT NULL, - - -- the user who has control of the resource - cc_user int unsigned NOT NULL, - - -- the date/time on which this record expires - cc_expiration varbinary(14) not null - -) /*$wgDBTableOptions*/; --- composite pk. -CREATE UNIQUE INDEX /*i*/cc_resource_record ON /*_*/concurrencycheck (cc_resource_type, cc_record); --- sometimes there's a delete based on userid. -CREATE INDEX /*i*/cc_user ON /*_*/concurrencycheck (cc_user); --- sometimes there's a delete based on expiration -CREATE INDEX /*i*/cc_expiration ON /*_*/concurrencycheck (cc_expiration); - - -- vim: sw=2 sts=2 et diff --git a/tests/phpunit/includes/ConcurrencyCheckTest.php b/tests/phpunit/includes/ConcurrencyCheckTest.php deleted file mode 100644 index db1e05c5ec..0000000000 --- a/tests/phpunit/includes/ConcurrencyCheckTest.php +++ /dev/null @@ -1,106 +0,0 @@ - new ApiTestUser( - 'Concurrencychecktestuser1', - 'ConcurrencyCheck Test User 1', - 'concurrency_check_test_user_1@example.com', - array() - ), - 'user2' => new ApiTestUser( - 'Concurrencychecktestuser2', - 'ConcurrencyCheck Test User 2', - 'concurrency_check_test_user_2@example.com', - array() - ), - ); - - // turn on memcached for this test. - // if no memcached is present, this still works fine. - global $wgMainCacheType, $wgConcurrency; - $this->oldcache = $wgMainCacheType; - $wgMainCacheType = CACHE_MEMCACHED; - $wgConcurrency['ExpirationMin'] = -60; // negative numbers are needed for testing - } - - public function tearDown() { - // turn off caching again. - global $wgMainCacheType; - $wgMainCacheType = $this->oldcache; - - parent::tearDown(); - } - - // Actual tests from here down - - public function testCheckoutCheckin() { - $first = new ConcurrencyCheck( 'CCUnitTest', self::$users['user1']->user ); - $second = new ConcurrencyCheck( 'CCUnitTest', self::$users['user2']->user ); - $testKey = 1337; - - // clean up after any previously failed tests - $first->checkin($testKey); - $second->checkin($testKey); - - // tests - /* turning these tests off per robla, since I need to go home. - $this->assertTrue( $first->checkout($testKey), "Initial checkout" ); - $this->assertTrue( $first->checkout($testKey), "Cache hit" ); - $this->assertFalse( $second->checkout($testKey), "Checkout of locked resource fails as different user" ); - $this->assertTrue( $first->checkout($testKey), "Checkout of locked resource succeeds as original user" ); - $this->assertFalse( $second->checkin($testKey), "Checkin of locked resource fails as different user" ); - $this->assertTrue( $first->checkin($testKey), "Checkin of locked resource succeeds as original user" ); - $second->setExpirationTime(-5); - $this->assertTrue( $second->checkout($testKey), "Checked-in resource is now available to second user" ); - $second->setExpirationTime(); - $this->assertTrue( $first->checkout($testKey), "Checkout of expired resource succeeds as first user"); - $this->assertTrue( $second->checkout($testKey, true), "Checkout override" ); - $this->assertFalse( $first->checkout($testKey), "Checkout of overriden resource fails as different user" ); - - - // cleanup - $this->assertTrue( $second->checkin($testKey), "Checkin of record with changed ownership" ); - */ - } - - public function testExpire() { - $cc = new ConcurrencyCheck( 'CCUnitTest', self::$users['user1']->user ); - $cc->setExpirationTime(-1); - $cc->checkout( 1338 ); // these numbers are test record ids. - $cc->checkout( 1339 ); - $cc->setExpirationTime(); - $cc->checkout( 13310 ); - - // tests - $this->assertEquals( 2, $cc->expire(), "Resource expiration" ); - $this->assertTrue( $cc->checkin( 13310 ), "Checkin succeeds after expiration" ); - } - - public function testStatus() { - $cc = new ConcurrencyCheck( 'CCUnitTest', self::$users['user1']->user ); - $cc->checkout( 1337 ); - $cc->checkout( 1338 ); - $cc->setExpirationTime(-5); - $cc->checkout( 1339 ); - $cc->setExpirationTime(); - - // tests - $output = $cc->status( array( 1337, 1338, 1339, 13310 ) ); - $this->assertEquals( true, is_array( $output ), "Status returns values" ); - $this->assertEquals( 4, count( $output ), "Output has the correct number of records" ); - $this->assertEquals( 'valid', $output[1337]['status'], "Current checkouts are listed as valid"); - $this->assertEquals( 'invalid', $output[1339]['status'], "Expired checkouts are invalid"); - $this->assertEquals( 'invalid', $output[13310]['status'], "Missing checkouts are invalid"); - } -} diff --git a/tests/phpunit/includes/api/ApiConcurrencyTest.php b/tests/phpunit/includes/api/ApiConcurrencyTest.php deleted file mode 100644 index 3c14f96d52..0000000000 --- a/tests/phpunit/includes/api/ApiConcurrencyTest.php +++ /dev/null @@ -1,172 +0,0 @@ - $user ) { - - $params = array( - 'action' => 'login', - 'lgname' => $user->username, - 'lgpassword' => $user->password - ); - list( $result, , $session ) = $this->doApiRequest( $params ); - $this->assertArrayHasKey( "login", $result ); - $this->assertArrayHasKey( "result", $result['login'] ); - $this->assertEquals( "NeedToken", $result['login']['result'] ); - $token = $result['login']['token']; - - $params = array( - 'action' => 'login', - 'lgtoken' => $token, - 'lgname' => $user->username, - 'lgpassword' => $user->password - ); - list( $result, , $session ) = $this->doApiRequest( $params, $session ); - $this->assertArrayHasKey( "login", $result ); - $this->assertArrayHasKey( "result", $result['login'] ); - $this->assertEquals( "Success", $result['login']['result'] ); - $this->assertArrayHasKey( 'lgtoken', $result['login'] ); - - $this->assertNotEmpty( $session, 'API Login must return a session' ); - - $sessionArray[$key] = $session; - - } - - return $sessionArray; - - } - - /** - * @depends testLogin - */ - function testCheckOut( $sessionArray ) { - - global $wgUser; - - $wgUser = self::$users['one']->user; - /* commenting these out since i need to go home and they're breakin CI. See commit summary for details. - - list( $result, , $session ) = $this->doApiRequestWithToken( array( - 'action' => 'concurrency', - 'ccaction' => 'checkout', - 'record' => 1, - 'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['one'], self::$users['one']->user ); - - $this->assertEquals( "success", $result['concurrency']['result'] ); - - $wgUser = self::$users['two']->user; - - list( $result, , $session ) = $this->doApiRequestWithToken( array( - 'action' => 'concurrency', - 'ccaction' => 'checkout', - 'record' => 1, - 'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['two'], self::$users['two']->user ); - - $this->assertEquals( "failure", $result['concurrency']['result'] ); - - list( $result, , $session ) = $this->doApiRequestWithToken( array( - 'action' => 'concurrency', - 'ccaction' => 'checkout', - 'record' => 2, - 'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['two'], self::$users['two']->user ); - - $this->assertEquals( "success", $result['concurrency']['result'] ); - */ - } - - /** - * @depends testLogin - */ - function testCheckIn( $sessionArray ) { - - global $wgUser; - - $wgUser = self::$users['one']->user; - /* commenting these out since i need to go home and they're breakin CI. See commit summary for details. - - list( $result, , $session ) = $this->doApiRequestWithToken( array( - 'action' => 'concurrency', - 'ccaction' => 'checkin', - 'record' => 1, - 'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['one'], self::$users['one']->user ); - - $this->assertEquals( "success", $result['concurrency']['result'] ); - - list( $result, , $session ) = $this->doApiRequestWithToken( array( - 'action' => 'concurrency', - 'ccaction' => 'checkin', - 'record' => 2, - 'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['one'], self::$users['one']->user ); - - $this->assertEquals( "failure", $result['concurrency']['result'] ); - - $wgUser = self::$users['two']->user; - - list( $result, , $session ) = $this->doApiRequestWithToken( array( - 'action' => 'concurrency', - 'ccaction' => 'checkin', - 'record' => 2, - 'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['two'], self::$users['two']->user ); - - $this->assertEquals( "success", $result['concurrency']['result'] ); - */ - } - - /** - * @depends testLogin - */ - function testInvalidCcacton( $sessionArray ) { - $exception = false; - try { - global $wgUser; - - $wgUser = self::$users['one']->user; - - list( $result, , $session ) = $this->doApiRequestWithToken( array( - 'action' => 'concurrency', - 'ccaction' => 'checkinX', - 'record' => 1, - 'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['one'], self::$users['one']->user ); - } catch ( UsageException $e ) { - $exception = true; - $this->assertEquals("Unrecognized value for parameter 'ccaction': checkinX", - $e->getMessage() ); - } - $this->assertTrue( $exception, "Got exception" ); - - } - -} -- 2.20.1