Aude has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/227691

Change subject: Update Wikidata - add usage tracking job
......................................................................

Update Wikidata - add usage tracking job

Change-Id: I33a392262eb58778a01e0e05d6c9815429ab67f7
---
M composer.lock
M extensions/Wikibase/.jscsrc
M extensions/Wikibase/client/WikibaseClient.php
M extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php
M extensions/Wikibase/client/includes/Usage/EntityUsage.php
A extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php
M extensions/Wikibase/client/includes/store/ClientStore.php
M extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php
M extensions/Wikibase/client/tests/phpunit/MockClientStore.php
M 
extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
M extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php
A 
extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php
M extensions/Wikibase/composer.json
M extensions/Wikibase/package.json
M vendor/composer/autoload_classmap.php
M vendor/composer/installed.json
16 files changed, 523 insertions(+), 47 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikidata 
refs/changes/91/227691/1

diff --git a/composer.lock b/composer.lock
index 717f103..07826bc 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1326,12 +1326,12 @@
             "source": {
                 "type": "git",
                 "url": 
"https://github.com/wikimedia/mediawiki-extensions-Wikibase.git";,
-                "reference": "2498f76188fe714f19fdd68ca89a6ac34ecd4e4c"
+                "reference": "7ed9b2a65f6ff6be7293d796b01e597dd9164c81"
             },
             "dist": {
                 "type": "zip",
-                "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/2498f76188fe714f19fdd68ca89a6ac34ecd4e4c";,
-                "reference": "2498f76188fe714f19fdd68ca89a6ac34ecd4e4c",
+                "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/7ed9b2a65f6ff6be7293d796b01e597dd9164c81";,
+                "reference": "7ed9b2a65f6ff6be7293d796b01e597dd9164c81",
                 "shasum": ""
             },
             "require": {
@@ -1350,8 +1350,8 @@
                 "php": ">=5.3.2",
                 "wikibase/data-model": "~3.0",
                 "wikibase/data-model-javascript": "^1.0.2",
-                "wikibase/data-model-serialization": "~1.4",
-                "wikibase/internal-serialization": "~1.4",
+                "wikibase/data-model-serialization": "~1.4.0",
+                "wikibase/internal-serialization": "~1.4.0",
                 "wikibase/javascript-api": "~1.0",
                 "wikibase/serialization-javascript": "~2.0"
             },
@@ -1399,7 +1399,7 @@
                 "wikibaserepo",
                 "wikidata"
             ],
-            "time": "2015-07-23 01:52:42"
+            "time": "2015-07-29 02:42:33"
         },
         {
             "name": "wikibase/wikimedia-badges",
diff --git a/extensions/Wikibase/.jscsrc b/extensions/Wikibase/.jscsrc
index f66f6bd..312c030 100644
--- a/extensions/Wikibase/.jscsrc
+++ b/extensions/Wikibase/.jscsrc
@@ -3,12 +3,26 @@
        "preset": "wikimedia",
 
        // ----
-       // Rules from wikimedia preset we don't follow
+       // Rules from wikimedia preset we don't yet? follow
 
        "validateIndentation": null,
        "requireMultipleVarDecl": null,
        "disallowDanglingUnderscores": null,
-       "requireSpacesInsideArrayBrackets": null,
+       "requireSpacesInsideBrackets": null,
+       "requireVarDeclFirst": null,
+       "jsDoc": {
+               // what we don't yet follow is commented out
+               //"checkAnnotations": "jsduck5",
+               //"checkParamNames": true,
+               "requireParamTypes": true,
+               "checkRedundantParams": true,
+               //"checkReturnTypes": true,
+               "checkRedundantReturns": true,
+               //"requireReturnTypes": true,
+               //"checkTypes": "capitalizedNativeCase",
+               "checkRedundantAccess": true
+               //"requireNewlineAfterDescription": true
+       },
 
        // ----
        // Own rules
@@ -24,5 +38,5 @@
                "else"
        ],
 
-       "excludeFiles": [ "node_modules/**", "vendor/**" ]
+       "excludeFiles": [ "node_modules/**", "vendor/**", "extensions/**" ]
 }
diff --git a/extensions/Wikibase/client/WikibaseClient.php 
b/extensions/Wikibase/client/WikibaseClient.php
index 4c48108..deefc1f 100644
--- a/extensions/Wikibase/client/WikibaseClient.php
+++ b/extensions/Wikibase/client/WikibaseClient.php
@@ -67,6 +67,7 @@
        global $wgExtensionCredits, $wgExtensionMessagesFiles, $wgHooks;
        global $wgAPIMetaModules, $wgAPIPropModules, $wgSpecialPages, 
$wgResourceModules;
        global $wgWBClientSettings, $wgRecentChangesFlags, $wgMessagesDirs;
+       global $wgJobClasses;
 
        $wgExtensionCredits['wikibase'][] = array(
                'path' => __DIR__,
@@ -123,6 +124,9 @@
        // extension hooks
        $wgHooks['WikibaseDeleteData'][]                        = 
'\Wikibase\ClientHooks::onWikibaseDeleteData';
 
+       // job classes
+       $wgJobClasses['wikibase-addUsagesForPage'] = 
'Wikibase\Client\Store\AddUsagesForPageJob';
+
        // api modules
        $wgAPIMetaModules['wikibase'] = array(
                'class' => 'Wikibase\ApiClientInfo',
diff --git 
a/extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php 
b/extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php
index 8b12966..6776f65 100644
--- a/extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php
+++ b/extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php
@@ -3,6 +3,8 @@
 namespace Wikibase\Client\Hooks;
 
 use Content;
+use EnqueueJob;
+use JobQueueGroup;
 use LinksUpdate;
 use ManualLogEntry;
 use ParserCache;
@@ -10,6 +12,7 @@
 use ParserOutput;
 use Title;
 use User;
+use Wikibase\Client\Store\AddUsagesForPageJob;
 use Wikibase\Client\Store\UsageUpdater;
 use Wikibase\Client\Usage\ParserOutputUsageAccumulator;
 use Wikibase\Client\WikibaseClient;
@@ -34,19 +37,15 @@
         */
        private $usageUpdater;
 
+       /**
+        * @var JobQueueGroup
+        */
+       private $jobScheduler;
+
        public static function newFromGlobalState() {
-               $wikibaseClient = WikibaseClient::getDefaultInstance();
-               $settings = $wikibaseClient->getSettings();
-
-               $usageUpdater = new UsageUpdater(
-                       $settings->getSetting( 'siteGlobalID' ),
-                       $wikibaseClient->getStore()->getUsageTracker(),
-                       $wikibaseClient->getStore()->getUsageLookup(),
-                       $wikibaseClient->getStore()->getSubscriptionManager()
-               );
-
                return new DataUpdateHookHandlers(
-                       $usageUpdater
+                       
WikibaseClient::getDefaultInstance()->getStore()->getUsageUpdater(),
+                       JobQueueGroup::singleton()
                );
        }
 
@@ -113,9 +112,11 @@
        }
 
        public function __construct(
-               UsageUpdater $usageUpdater
+               UsageUpdater $usageUpdater,
+               JobQueueGroup $jobScheduler
        ) {
                $this->usageUpdater = $usageUpdater;
+               $this->jobScheduler = $jobScheduler;
        }
 
        /**
@@ -160,7 +161,7 @@
         * Implemented to update usage tracking information via UsageUpdater.
         *
         * @param ParserOutput $parserOutput
-        * @param $title $title
+        * @param Title $title
         */
        public function doParserCacheSaveComplete( ParserOutput $parserOutput, 
Title $title ) {
                $usageAcc = new ParserOutputUsageAccumulator( $parserOutput );
@@ -169,13 +170,24 @@
                // These timestamps should usually be the same, but asking 
$title may cause a database query.
                $touched = $parserOutput->getTimestamp() ?: 
$title->getTouched();
 
+               if ( count( $usageAcc->getUsages() ) === 0 ) {
+                       // no usages, bail out
+                       return;
+               }
+
                // Add or touch any usages present in the new rendering.
                // This allows us to track usages in each user language 
separately, for multilingual sites.
-               $this->usageUpdater->addUsagesForPage(
-                       $title->getArticleId(),
-                       $usageAcc->getUsages(),
-                       $touched
-               );
+
+               // NOTE: Since parser cache updates may be triggered by page 
views (in a new language),
+               // schedule the usage updates in the job queue, to avoid 
writing to the database
+               // during a GET request.
+
+               //TODO: Before posting a job, check slave database. If no 
changes are needed, skip update.
+
+               $addUsagesForPageJob = AddUsagesForPageJob::newSpec( $title, 
$usageAcc->getUsages(), $touched );
+               $enqueueJob = EnqueueJob::newFromLocalJobs( 
$addUsagesForPageJob );
+
+               $this->jobScheduler->lazyPush( $enqueueJob );
        }
 
        /**
diff --git a/extensions/Wikibase/client/includes/Usage/EntityUsage.php 
b/extensions/Wikibase/client/includes/Usage/EntityUsage.php
index 5876d7a..864efce 100644
--- a/extensions/Wikibase/client/includes/Usage/EntityUsage.php
+++ b/extensions/Wikibase/client/includes/Usage/EntityUsage.php
@@ -146,6 +146,17 @@
        }
 
        /**
+        * @return array array( 'entityId' => $entityId, 'aspect' => $aspect, 
'modifier' => $modifier )
+        */
+       public function asArray() {
+               return array(
+                       'entityId' => $this->entityId->getSerialization(),
+                       'aspect' => $this->aspect,
+                       'modifier' => $this->modifier
+               );
+       }
+
+       /**
         * @param string $aspectKey
         *
         * @return string One of the EntityUsage::..._USAGE constants with the 
modifier split off.
diff --git a/extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php 
b/extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php
new file mode 100644
index 0000000..335fd3e
--- /dev/null
+++ b/extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php
@@ -0,0 +1,153 @@
+<?php
+
+namespace Wikibase\Client\Store;
+
+use Job;
+use JobSpecification;
+use Title;
+use Wikibase\Client\Usage\EntityUsage;
+use Wikibase\Client\WikibaseClient;
+use Wikibase\DataModel\Entity\EntityIdParser;
+use Wikimedia\Assert\Assert;
+
+/**
+ * Job for scheduled invocation of UsageUpdater::addUsagesForPage
+ *
+ * @license GPL 2+
+ * @author Daniel Kinzler
+ */
+class AddUsagesForPageJob extends Job {
+
+       /**
+        * @var integer
+        */
+       private $pageId;
+
+       /**
+        * @var EntityUsage[]
+        */
+       private $usages;
+
+       /**
+        * @var string timestamp
+        */
+       private $touched;
+
+       /**
+        * @var UsageUpdater
+        */
+       private $usageUpdater;
+
+       /**
+        * @var EntityIdParser $idParser
+        */
+       private $idParser;
+
+       /**
+        * Spec constructor, for creating JobSpecifications to be pushed to the 
job queue.
+        *
+        * @param Title $title
+        * @param EntityUsage[] $usages
+        * @param string $touched
+        *
+        * @return JobSpecification
+        */
+       public static function newSpec( Title $title, array $usages, $touched ) 
{
+               // NOTE: Map EntityUsage objects to scalar arrays, for JSON 
serialization in the job queue.
+               $usages = array_map( function ( EntityUsage $usage ) {
+                       return $usage->asArray();
+               }, $usages );
+
+               $jobParams = array(
+                       'pageId' => $title->getArticleId(),
+                       'usages' => $usages,
+                       'touched' => $touched
+               );
+
+               return new JobSpecification(
+                       'wikibase-addUsagesForPage',
+                       $jobParams,
+                       array( 'removeDuplicates' => true ),
+                       $title
+               );
+       }
+
+       /**
+        * @param Title $title
+        * @param array $params
+        */
+       public function __construct( Title $title, array $params ) {
+               parent::__construct( 'wikibase-addUsagesForPage', $title, 
$params );
+
+               Assert::parameter(
+                       isset( $params['pageId'] ) && is_int( $params['pageId'] 
) && $params['pageId'] > 0,
+                       '$params["pageId"]',
+                       'must be a positive integer' );
+
+               Assert::parameter(
+                       isset( $params['usages'] ) && is_array( 
$params['usages'] ) && !empty( $params['usages'] ),
+                       '$params["usages"]',
+                       'must be a non-empty array' );
+
+               Assert::parameter(
+                       isset( $params['touched'] ) && is_string( 
$params['touched'] ) && $params['touched'] !== '',
+                       '$params["touched"]',
+                       'must be a timestamp string' );
+
+               Assert::parameterElementType(
+                       'array',
+                       $params['usages'],
+                       '$params["usages"]' );
+
+               $this->pageId = $params['pageId'];
+               $this->usages = $params['usages'];
+               $this->touched = $params['touched'];
+
+               $usageUpdater = 
WikibaseClient::getDefaultInstance()->getStore()->getUsageUpdater();
+               $idParser = 
WikibaseClient::getDefaultInstance()->getEntityIdParser();
+               $this->overrideServices( $usageUpdater, $idParser );
+       }
+
+       /**
+        * Service override for testing
+        *
+        * @param UsageUpdater $usageUpdater
+        * @param EntityIdParser $idParser
+        */
+       public function overrideServices( UsageUpdater $usageUpdater, 
EntityIdParser $idParser ) {
+               $this->usageUpdater = $usageUpdater;
+               $this->idParser = $idParser;
+       }
+
+       /**
+        * @return EntityUsage[]
+        */
+       private function getUsages() {
+               // Turn serialized usage info into EntityUsage objects
+               $idParser = $this->idParser;
+               $usages = array_map( function ( array $usageArray ) use ( 
$idParser ) {
+                       // This is the inverse of EntityUsage::asArray()
+                       return new EntityUsage(
+                               $idParser->parse( $usageArray['entityId'] ),
+                               $usageArray['aspect'],
+                               $usageArray['modifier']
+                       );
+               }, $this->usages );
+
+               return $usages;
+       }
+
+       /**
+        * Call UsageUpdater::addUsagesForPage
+        *
+        * @return bool Success
+        */
+       public function run() {
+               $this->usageUpdater->addUsagesForPage(
+                       $this->pageId,
+                       $this->getUsages(),
+                       $this->touched
+               );
+       }
+
+}
diff --git a/extensions/Wikibase/client/includes/store/ClientStore.php 
b/extensions/Wikibase/client/includes/store/ClientStore.php
index 66b381a..51d052f 100644
--- a/extensions/Wikibase/client/includes/store/ClientStore.php
+++ b/extensions/Wikibase/client/includes/store/ClientStore.php
@@ -3,6 +3,7 @@
 namespace Wikibase;
 
 use MWException;
+use Wikibase\Client\Store\UsageUpdater;
 use Wikibase\Client\Usage\SubscriptionManager;
 use Wikibase\Client\Usage\UsageLookup;
 use Wikibase\Client\Usage\UsageTracker;
@@ -125,4 +126,11 @@
         */
        public function getEntityPrefetcher();
 
+       /**
+        * @since 0.5
+        *
+        * @return UsageUpdater
+        */
+       public function getUsageUpdater();
+
 }
diff --git a/extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php 
b/extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php
index 010b1a7..80d42cf 100644
--- a/extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php
+++ b/extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php
@@ -7,6 +7,7 @@
 use Wikibase\Client\Store\Sql\ConsistentReadConnectionManager;
 use Wikibase\Client\Store\Sql\PagePropsEntityIdLookup;
 use Wikibase\Client\Store\TitleFactory;
+use Wikibase\Client\Store\UsageUpdater;
 use Wikibase\Client\Usage\NullSubscriptionManager;
 use Wikibase\Client\Usage\NullUsageTracker;
 use Wikibase\Client\Usage\SiteLinkUsageLookup;
@@ -463,4 +464,17 @@
 
                return $this->entityPrefetcher;
        }
+
+       /**
+        * @return UsageUpdater
+        */
+       public function getUsageUpdater() {
+               return new UsageUpdater(
+                       $this->siteId,
+                       $this->getUsageTracker(),
+                       $this->getUsageLookup(),
+                       $this->getSubscriptionManager()
+               );
+       }
+
 }
diff --git a/extensions/Wikibase/client/tests/phpunit/MockClientStore.php 
b/extensions/Wikibase/client/tests/phpunit/MockClientStore.php
index a6aaa73..5a78d04 100644
--- a/extensions/Wikibase/client/tests/phpunit/MockClientStore.php
+++ b/extensions/Wikibase/client/tests/phpunit/MockClientStore.php
@@ -3,6 +3,7 @@
 namespace Wikibase\Test;
 
 use Wikibase\ChangesTable;
+use Wikibase\Client\Store\UsageUpdater;
 use Wikibase\Client\Usage\NullSubscriptionManager;
 use Wikibase\Client\Usage\NullUsageTracker;
 use Wikibase\Client\Usage\SubscriptionManager;
@@ -10,6 +11,7 @@
 use Wikibase\Client\Usage\UsageTracker;
 use Wikibase\ClientStore;
 use Wikibase\Lib\Store\EntityLookup;
+use Wikibase\Lib\Store\EntityPrefetcher;
 use Wikibase\Lib\Store\EntityRevisionLookup;
 use Wikibase\Lib\Store\NullEntityPrefetcher;
 use Wikibase\Lib\Store\SiteLinkLookup;
@@ -187,4 +189,18 @@
                return new NullEntityPrefetcher();
        }
 
+       /**
+        * @since 0.5
+        *
+        * @return UsageUpdater
+        */
+       public function getUsageUpdater() {
+               return new UsageUpdater(
+                       'mock',
+                       $this->getUsageTracker(),
+                       $this->getUsageLookup(),
+                       $this->getSubscriptionManager()
+               );
+       }
+
 }
diff --git 
a/extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
 
b/extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
index 0e1733e..f2b3976 100644
--- 
a/extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
+++ 
b/extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
@@ -2,6 +2,8 @@
 
 namespace Wikibase\Client\Tests\Hooks;
 
+use JobQueueGroup;
+use JobSpecification;
 use ParserOutput;
 use Title;
 use Wikibase\Client\Hooks\DataUpdateHookHandlers;
@@ -26,13 +28,20 @@
 
        /**
         * @param Title $title
-        * @param EntityUsage[]|null $expectedUsages
+        * @param array $expectedUsages
         * @param string|null $touched
-        * @param bool $prune
+        * @param bool $prune whether pruneUsagesForPage() should be used
+        * @param bool $add whether addUsagesForPage() should be used
         *
         * @return UsageUpdater
         */
-       private function newUsageUpdater( Title $title, array $expectedUsages = 
null, $touched = null, $prune = true ) {
+       private function newUsageUpdater(
+               Title $title,
+               array $expectedUsages = null,
+               $touched = null,
+               $prune = true,
+               $add = true
+       ) {
                $usageUpdater = $this->getMockBuilder( 
'Wikibase\Client\Store\UsageUpdater' )
                        ->disableOriginalConstructor()
                        ->getMock();
@@ -47,7 +56,7 @@
                // greater timestamp.
                $touchedMatcher = $this->greaterThanOrEqual( $touched );
 
-               if ( $expectedUsages === null ) {
+               if ( $expectedUsages === null || !$add ) {
                        $usageUpdater->expects( $this->never() )
                                ->method( 'addUsagesForPage' );
                } else {
@@ -70,17 +79,87 @@
 
        /**
         * @param Title $title
+        * @param array|null $expectedUsages
+        * @param string|null $touched
+        * @param bool $useJobQueue whether we expect the job queue to be used
+        *
+        * @return JobQueueGroup
+        */
+       private function newJobScheduler(
+               Title $title,
+               array $expectedUsages = null,
+               $touched = null,
+               $useJobQueue = false
+       ) {
+               $jobScheduler = $this->getMockBuilder( 'JobQueueGroup' )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               if ( empty( $expectedUsages ) || !$useJobQueue ) {
+                       $jobScheduler->expects( $this->never() )
+                               ->method( 'lazyPush' );
+               } else {
+                       $expectedUsageArray = array_map( function ( EntityUsage 
$usage ) {
+                               return $usage->asArray();
+                       }, $expectedUsages );
+
+                       $params = array(
+                               'jobsByWiki' => array(
+                                       wfWikiID() => array(
+                                               array(
+                                                       'type' => 
'wikibase-addUsagesForPage',
+                                                       'params' => array(
+                                                               'pageId' => 
$title->getArticleID(),
+                                                               'usages' => 
$expectedUsageArray,
+                                                               'touched' => 
$touched
+                                                       ),
+                                                       'opts' => array(
+                                                               
'removeDuplicates' => true
+                                                       ),
+                                                       'title' => array(
+                                                               'ns' => NS_MAIN,
+                                                               'key' => 
'Oxygen'
+                                                       )
+                                               )
+                                       )
+                               )
+                       );
+
+                       $jobScheduler->expects( $this->once() )
+                               ->method( 'lazyPush' )
+                               ->with( $this->callback( function ( $job ) use 
( $params ) {
+                                       
DataUpdateHookHandlersTest::assertEquals( 'enqueue', $job->getType() );
+                                       
DataUpdateHookHandlersTest::assertEquals( $params, $job->getParams() );
+                                       return true;
+                               } ) );
+
+               }
+
+               return $jobScheduler;
+       }
+
+       /**
+        * @param Title $title
         * @param EntityUsage[]|null $expectedUsages
         * @param string|null $touched timestamp
-        * @param bool $prune
+        * @param bool $prune whether pruneUsagesForPage() should be used
+        * @param bool $asyncAdd whether addUsagesForPage() should be called 
via the job queue
         *
         * @return DataUpdateHookHandlers
         */
-       private function newDataUpdateHookHandlers( Title $title, array 
$expectedUsages = null, $touched = null, $prune = true ) {
-               $usageUpdater = $this->newUsageUpdater( $title, 
$expectedUsages, $touched, $prune );
+       private function newDataUpdateHookHandlers(
+               Title $title,
+               array $expectedUsages = null,
+               $touched = null,
+               $prune = true,
+               $asyncAdd = false
+       ) {
+               $usageUpdater = $this->newUsageUpdater( $title, 
$expectedUsages, $touched, $prune, !$asyncAdd );
+               $jobScheduler = $this->newJobScheduler( $title, 
$expectedUsages, $touched, $asyncAdd );
 
                return new DataUpdateHookHandlers(
-                       $usageUpdater
+                       $usageUpdater,
+                       $jobScheduler
                );
        }
 
@@ -164,7 +243,7 @@
                $linksUpdate = $this->newLinksUpdate( $title, $usage, 
$timestamp );
 
                // Assertions are done by the UsageUpdater mock
-               $handler = $this->newDataUpdateHookHandlers( $title, $usage, 
$timestamp, true );
+               $handler = $this->newDataUpdateHookHandlers( $title, $usage, 
$timestamp, true, false );
                $handler->doLinksUpdateComplete( $linksUpdate );
        }
 
@@ -178,7 +257,7 @@
                $parserOutput = $this->newParserOutput( $usage, $timestamp );
 
                // Assertions are done by the UsageUpdater mock
-               $handler = $this->newDataUpdateHookHandlers( $title, $usage, 
$timestamp, false );
+               $handler = $this->newDataUpdateHookHandlers( $title, $usage, 
$timestamp, false, true );
                $handler->doParserCacheSaveComplete( $parserOutput, $title );
        }
 
@@ -188,7 +267,7 @@
                $timestamp = '20150505000000';
 
                // Assertions are done by the UsageUpdater mock
-               $handler = $this->newDataUpdateHookHandlers( $title, null, 
$timestamp, true );
+               $handler = $this->newDataUpdateHookHandlers( $title, null, 
$timestamp, true, false );
                $handler->doArticleDeleteComplete( $title->getNamespace(), 
$title->getArticleID(), $timestamp );
        }
 
diff --git 
a/extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php 
b/extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php
index 1a20b61..48f9bc6 100644
--- 
a/extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php
+++ 
b/extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php
@@ -55,6 +55,25 @@
                $this->assertEquals( "$aspect.$modifier", 
$usage->getAspectKey() );
        }
 
+       public function testAsArray() {
+               $id = new ItemId( 'Q7' );
+               $aspect = EntityUsage::LABEL_USAGE;
+               $modifier = 'ru';
+
+               $expected = array(
+                       'entityId' => $id->getSerialization(),
+                       'aspect' => $aspect,
+                       'modifier' => null
+               );
+
+               $usage = new EntityUsage( $id, $aspect );
+               $this->assertEquals( $expected, $usage->asArray() );
+
+               $expected['modifier'] = $modifier;
+               $usage = new EntityUsage( $id, $aspect, $modifier );
+               $this->assertEquals( $expected, $usage->asArray() );
+       }
+
        public function aspectKeyProvider() {
                return array(
                        array( 'L', array( 'L', null ) ),
diff --git 
a/extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php
 
b/extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php
new file mode 100644
index 0000000..cb15661
--- /dev/null
+++ 
b/extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php
@@ -0,0 +1,144 @@
+<?php
+
+namespace Wikibase\Client\Test\Store;
+
+use Title;
+use Wikibase\Client\Store\AddUsagesForPageJob;
+use Wikibase\Client\Usage\EntityUsage;
+use Wikibase\DataModel\Entity\BasicEntityIdParser;
+use Wikibase\DataModel\Entity\ItemId;
+
+/**
+ * @covers Wikibase\Client\Store\AddUsagesForPageJob
+ *
+ * @group Wikibase
+ * @group WikibaseClient
+ * @group WikibaseUsageTracking
+ *
+ * @licence GNU GPL v2+
+ * @author Daniel Kinzler
+ */
+class AddUsagesForPageJobTest extends \PHPUnit_Framework_TestCase {
+
+       public function provideConstructor_failure() {
+               $pageId = 17;
+               $usageQ5X = new EntityUsage( new ItemId( 'Q5' ), 'X' );
+               $usages = array( $usageQ5X->asArray() );
+               $touched = '20150101000000';
+
+               return array(
+                       'empty' => array( array() ),
+
+                       '$pageId is missing' => array( array(
+                               'usages' => $usages,
+                               'touched' => $touched,
+                       ) ),
+                       '$pageId is not an int' => array( array(
+                               'pageId' => 'foo',
+                               'usages' => $usages,
+                               'touched' => $touched,
+                       ) ),
+                       '$pageId is zero' => array( array(
+                               'pageId' => 0,
+                               'usages' => $usages,
+                               'touched' => $touched,
+                       ) ),
+
+                       '$usages is missing' => array( array(
+                               'pageId' => $pageId,
+                               'touched' => $touched,
+                       ) ),
+                       '$usages is not an array' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => 'xxx',
+                               'touched' => $touched,
+                       ) ),
+                       '$usages is empty' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => array(),
+                               'touched' => $touched,
+                       ) ),
+                       '$usages contains crap' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => array( 1, 2, 3 ),
+                               'touched' => $touched,
+                       ) ),
+
+                       '$touched is missing' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => $usages,
+                       ) ),
+                       '$touched is not a string' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => $usages,
+                               'touched' => 23,
+                       ) ),
+                       '$touched is empty' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => $usages,
+                               'touched' => '',
+                       ) ),
+               );
+       }
+
+       /**
+        * @dataProvider provideConstructor_failure
+        * @param array $params
+        */
+       public function testConstructor_failure( $params ) {
+               $this->setExpectedException( 'InvalidArgumentException' );
+
+               $title = Title::makeTitle( NS_MAIN, 'Foo' );
+               new AddUsagesForPageJob( $title, $params );
+       }
+
+       public function testRun() {
+               $usageQ5X = new EntityUsage( new ItemId( 'Q5' ), 'X' );
+               $params = array(
+                       'pageId' => 17,
+                       'usages' => array( $usageQ5X->asArray() ),
+                       'touched' => '20150101000000',
+               );
+
+               $usageUpdater = $this->getMockBuilder( 
'Wikibase\Client\Store\UsageUpdater' )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $usageUpdater->expects( $this->once() )
+                       ->method( 'addUsagesForPage' )
+                       ->with(
+                               $params['pageId'],
+                               array( $usageQ5X ),
+                               $params['touched']
+                       );
+
+               $title = Title::makeTitle( NS_MAIN, 'Foo' );
+               $job = new AddUsagesForPageJob( $title, $params );
+               $job->overrideServices( $usageUpdater, new 
BasicEntityIdParser() );
+
+               $job->run();
+       }
+
+       public function testNewSpec() {
+               $usageQ5X = new EntityUsage( new ItemId( 'Q5' ), 'X' );
+
+               $title = Title::makeTitle( NS_MAIN, 'Foo' );
+               $title->resetArticleID( 17 );
+
+               $touched = '20150101000000';
+               $usages = array( $usageQ5X );
+
+               $spec = AddUsagesForPageJob::newSpec( $title, $usages, $touched 
);
+
+               $params = array(
+                       'pageId' => $title->getArticleID(),
+                       'usages' => array( $usageQ5X->asArray() ),
+                       'touched' => '20150101000000',
+               );
+
+               $this->assertEquals( 'wikibase-addUsagesForPage', 
$spec->getType() );
+               $this->assertEquals( $title->getFullText(), 
$spec->getTitle()->getFullText() );
+               $this->assertEquals( $params, $spec->getParams() );
+       }
+
+}
diff --git a/extensions/Wikibase/composer.json 
b/extensions/Wikibase/composer.json
index 87885c5..943f9fd 100644
--- a/extensions/Wikibase/composer.json
+++ b/extensions/Wikibase/composer.json
@@ -37,9 +37,9 @@
 
                "wikibase/data-model": "~3.0",
                "wikibase/data-model-javascript": "^1.0.2",
-               "wikibase/data-model-serialization": "~1.4",
+               "wikibase/data-model-serialization": "~1.4.0",
                "wikibase/javascript-api": "~1.0",
-               "wikibase/internal-serialization": "~1.4",
+               "wikibase/internal-serialization": "~1.4.0",
                "wikibase/serialization-javascript": "~2.0",
 
                "diff/diff": "~2.0|~1.0"
diff --git a/extensions/Wikibase/package.json b/extensions/Wikibase/package.json
index 2e22208..43022cd 100644
--- a/extensions/Wikibase/package.json
+++ b/extensions/Wikibase/package.json
@@ -11,7 +11,7 @@
        "author": "The Wikidata team",
        "license": "GPL-2.0+",
        "devDependencies": {
-               "jscs": "",
+               "jscs": ">=2.0",
                "jshint": ""
        }
 }
diff --git a/vendor/composer/autoload_classmap.php 
b/vendor/composer/autoload_classmap.php
index 9ac65da..d5d4c23 100644
--- a/vendor/composer/autoload_classmap.php
+++ b/vendor/composer/autoload_classmap.php
@@ -369,11 +369,13 @@
     'Wikibase\\Client\\RepoItemLinkGenerator' => $baseDir . 
'/extensions/Wikibase/client/includes/RepoItemLinkGenerator.php',
     'Wikibase\\Client\\RepoLinker' => $baseDir . 
'/extensions/Wikibase/client/includes/RepoLinker.php',
     'Wikibase\\Client\\Specials\\SpecialUnconnectedPages' => $baseDir . 
'/extensions/Wikibase/client/includes/specials/SpecialUnconnectedPages.php',
+    'Wikibase\\Client\\Store\\AddUsagesForPageJob' => $baseDir . 
'/extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php',
     'Wikibase\\Client\\Store\\Sql\\BulkSubscriptionUpdater' => $baseDir . 
'/extensions/Wikibase/client/includes/store/sql/BulkSubscriptionUpdater.php',
     'Wikibase\\Client\\Store\\Sql\\ConsistentReadConnectionManager' => 
$baseDir . 
'/extensions/Wikibase/client/includes/store/sql/ConsistentReadConnectionManager.php',
     'Wikibase\\Client\\Store\\Sql\\PagePropsEntityIdLookup' => $baseDir . 
'/extensions/Wikibase/client/includes/store/sql/PagePropsEntityIdLookup.php',
     'Wikibase\\Client\\Store\\TitleFactory' => $baseDir . 
'/extensions/Wikibase/client/includes/store/TitleFactory.php',
     'Wikibase\\Client\\Store\\UsageUpdater' => $baseDir . 
'/extensions/Wikibase/client/includes/store/UsageUpdater.php',
+    'Wikibase\\Client\\Test\\Store\\AddUsagesForPageJobTest' => $baseDir . 
'/extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php',
     'Wikibase\\Client\\Test\\Store\\UsageUpdaterTest' => $baseDir . 
'/extensions/Wikibase/client/tests/phpunit/includes/UsageUpdaterTest.php',
     'Wikibase\\Client\\Test\\Usage\\UsageTrackingIntegrationTest' => $baseDir 
. 
'/extensions/Wikibase/client/tests/phpunit/includes/Usage/UsageTrackingIntegrationTest.php',
     'Wikibase\\Client\\Tests\\Api\\ApiClientInfoTest' => $baseDir . 
'/extensions/Wikibase/client/tests/phpunit/includes/api/ApiClientInfoTest.php',
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 2669187..0876d75 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -1420,12 +1420,12 @@
         "source": {
             "type": "git",
             "url": 
"https://github.com/wikimedia/mediawiki-extensions-Wikibase.git";,
-            "reference": "2498f76188fe714f19fdd68ca89a6ac34ecd4e4c"
+            "reference": "7ed9b2a65f6ff6be7293d796b01e597dd9164c81"
         },
         "dist": {
             "type": "zip",
-            "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/2498f76188fe714f19fdd68ca89a6ac34ecd4e4c";,
-            "reference": "2498f76188fe714f19fdd68ca89a6ac34ecd4e4c",
+            "url": 
"https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/7ed9b2a65f6ff6be7293d796b01e597dd9164c81";,
+            "reference": "7ed9b2a65f6ff6be7293d796b01e597dd9164c81",
             "shasum": ""
         },
         "require": {
@@ -1444,8 +1444,8 @@
             "php": ">=5.3.2",
             "wikibase/data-model": "~3.0",
             "wikibase/data-model-javascript": "^1.0.2",
-            "wikibase/data-model-serialization": "~1.4",
-            "wikibase/internal-serialization": "~1.4",
+            "wikibase/data-model-serialization": "~1.4.0",
+            "wikibase/internal-serialization": "~1.4.0",
             "wikibase/javascript-api": "~1.0",
             "wikibase/serialization-javascript": "~2.0"
         },
@@ -1455,7 +1455,7 @@
         "require-dev": {
             "squizlabs/php_codesniffer": "~2.1"
         },
-        "time": "2015-07-23 01:52:42",
+        "time": "2015-07-29 02:42:33",
         "type": "mediawiki-extension",
         "installation-source": "dist",
         "autoload": {

-- 
To view, visit https://gerrit.wikimedia.org/r/227691
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I33a392262eb58778a01e0e05d6c9815429ab67f7
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikidata
Gerrit-Branch: wmf/1.26wmf13
Gerrit-Owner: Aude <aude.w...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to