selenium: invoke jobs to enforce eventual consistency
authorPablo Grass <pablo.grass@wikimedia.de>
Tue, 11 Sep 2018 14:57:48 +0000 (16:57 +0200)
committerPablo Grass <pablo.grass@wikimedia.de>
Thu, 20 Sep 2018 09:13:38 +0000 (11:13 +0200)
Many tests use the API during their setup phase, which does not
participate in clearing the job queue, but constantly adds new items.
Consequently the job count keeps mounting. In order to be able to assert
the state of the application once all jobs are processed we need a way
to invoke them.
This is a minimalistic alternative to Idd4924e16925cbf0cb9e42645670c3fd76b72353

Bug: T199446
Change-Id: Ifc49bc5c06eef71da8aff1b1837c32debc2c45dd

tests/selenium/specs/specialrecentchanges.js
tests/selenium/wdio-mediawiki/RunJobs.js [new file with mode: 0644]

index 4328d3f..a872d6e 100644 (file)
@@ -1,7 +1,8 @@
 const assert = require( 'assert' ),
-       EditPage = require( '../pageobjects/edit.page' ),
+       Api = require( 'wdio-mediawiki/Api' ),
        RecentChangesPage = require( '../pageobjects/recentchanges.page' ),
-       Util = require( 'wdio-mediawiki/Util' );
+       Util = require( 'wdio-mediawiki/Util' ),
+       RunJobs = require( 'wdio-mediawiki/RunJobs' );
 
 describe( 'Special:RecentChanges', function () {
        let content,
@@ -13,9 +14,11 @@ describe( 'Special:RecentChanges', function () {
                name = Util.getTestString();
        } );
 
-       // Skip due to failures on many repos (T199644)
-       it.skip( 'shows page creation', function () {
-               EditPage.edit( name, content );
+       it( 'shows page creation', function () {
+               browser.call( function () {
+                       return Api.edit( name, content );
+               } );
+               RunJobs.run();
 
                RecentChangesPage.open();
 
diff --git a/tests/selenium/wdio-mediawiki/RunJobs.js b/tests/selenium/wdio-mediawiki/RunJobs.js
new file mode 100644 (file)
index 0000000..9d02d4d
--- /dev/null
@@ -0,0 +1,73 @@
+const MWBot = require( 'mwbot' ),
+       Page = require( 'wdio-mediawiki/Page' ),
+       FRONTPAGE_REQUESTS_MAX_RUNS = 10; // (arbitrary) safe-guard against endless execution
+
+/**
+ * Trigger the execution of jobs
+ *
+ * @see https://www.mediawiki.org/wiki/Manual:Job_queue/For_developers#Execution_of_jobs
+ *
+ * Use RunJobs.run() to ensure that jobs are executed before making assertions that depend on it.
+ *
+ * Systems that are selenium-tested are usually provisioned for that purpose, see no organic
+ * traffic, consequently typical post-send job queue processing rarely happens. Additionally,
+ * test set-up is often done through the API, requests to which do not trigger job queue
+ * processing at all.
+ *
+ * This can lead to an accumulation of unprocessed jobs, which in turn would render certain
+ * assertions impossible - e.g. checking a page is listed on Special:RecentChanges right
+ * after creating it.
+ *
+ * This class will try to trigger job execution through
+ * repeated blunt requests against the wiki's home page to trigger them at a rate
+ * of $wgJobRunRate per request.
+ */
+class RunJobs {
+
+       static run() {
+               browser.call( () => {
+                       return this.runThroughFrontPageRequests();
+               } );
+       }
+
+       static getJobCount() {
+               let bot = new MWBot( {
+                       apiUrl: `${browser.options.baseUrl}/api.php`
+               } );
+               return new Promise( ( resolve ) => {
+                       return bot.request( {
+                               action: 'query',
+                               meta: 'siteinfo',
+                               siprop: 'statistics'
+                       } ).then( ( response ) => {
+                               resolve( response.query.statistics.jobs );
+                       } );
+               } );
+       }
+
+       static runThroughFrontPageRequests( runCount = 1 ) {
+               let page = new Page();
+               this.log( `through requests to the front page (run ${runCount}).` );
+
+               page.openTitle( '' );
+
+               return this.getJobCount().then( ( jobCount ) => {
+                       if ( jobCount === 0 ) {
+                               this.log( 'found no more queued jobs.' );
+                               return;
+                       }
+                       this.log( `detected ${jobCount} more queued job(s).` );
+                       if ( runCount >= FRONTPAGE_REQUESTS_MAX_RUNS ) {
+                               this.log( 'stopping requests to the front page due to reached limit.' );
+                               return;
+                       }
+                       return this.runThroughFrontPageRequests( ++runCount );
+               } );
+       }
+
+       static log( message ) {
+               process.stdout.write( `RunJobs ${message}\n` );
+       }
+}
+
+module.exports = RunJobs;