r78389 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r78388‎ | r78389 | r78390 >
Date:16:48, 14 December 2010
Author:demon
Status:resolved (Comments)
Tags:
Comment:
Fix a few more paths, restore a few files lost in the move
Modified paths:
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/tests/RunSeleniumTests.php (added) (history)
  • /trunk/phase3/tests/parserTests.php (added) (history)
  • /trunk/phase3/tests/testHelpers.inc (added) (history)

Diff [purge]

Index: trunk/phase3/tests/RunSeleniumTests.php
@@ -0,0 +1,220 @@
 2+#!/usr/bin/php
 3+<?php
 4+/**
 5+ * @file
 6+ * @ingroup Maintenance
 7+ * @copyright Copyright © Wikimedia Deuschland, 2009
 8+ * @author Hallo Welt! Medienwerkstatt GmbH
 9+ * @author Markus Glaser, Dan Nessett, Priyanka Dhanda
 10+ * initial idea by Daniel Kinzler
 11+ *
 12+ * This program is free software; you can redistribute it and/or modify
 13+ * it under the terms of the GNU General Public License as published by
 14+ * the Free Software Foundation; either version 2 of the License, or
 15+ * (at your option) any later version.
 16+ *
 17+ * This program is distributed in the hope that it will be useful,
 18+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 19+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 20+ * GNU General Public License for more details.
 21+ *
 22+ * You should have received a copy of the GNU General Public License along
 23+ * with this program; if not, write to the Free Software Foundation, Inc.,
 24+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 25+ * http://www.gnu.org/copyleft/gpl.html
 26+ */
 27+
 28+define( 'SELENIUMTEST', true );
 29+
 30+require_once( dirname( __FILE__ ) . '/../maintenance/commandLine.inc' );
 31+require_once( 'PHPUnit/Framework.php' );
 32+require_once( 'PHPUnit/Extensions/SeleniumTestCase.php' );
 33+include_once( 'PHPUnit/Util/Log/JUnit.php' );
 34+require_once( dirname( __FILE__ ) . "/selenium/SeleniumServerManager.php" );
 35+
 36+class SeleniumTester extends Maintenance {
 37+ protected $selenium;
 38+ protected $serverManager;
 39+ protected $seleniumServerExecPath;
 40+
 41+ public function __construct() {
 42+ parent::__construct();
 43+ $this->mDescription = "Selenium Test Runner. For documentation, visit http://www.mediawiki.org/wiki/SeleniumFramework";
 44+ $this->addOption( 'port', 'Port used by selenium server. Default: 4444', false, true );
 45+ $this->addOption( 'host', 'Host selenium server. Default: $wgServer . $wgScriptPath', false, true );
 46+ $this->addOption( 'testBrowser', 'The browser used during testing. Default: firefox', false, true );
 47+ $this->addOption( 'wikiUrl', 'The Mediawiki installation to point to. Default: http://localhost', false, true );
 48+ $this->addOption( 'username', 'The login username for sunning tests. Default: empty', false, true );
 49+ $this->addOption( 'userPassword', 'The login password for running tests. Default: empty', false, true );
 50+ $this->addOption( 'seleniumConfig', 'Location of the selenium config file. Default: empty', false, true );
 51+ $this->addOption( 'list-browsers', 'List the available browsers.' );
 52+ $this->addOption( 'verbose', 'Be noisier.' );
 53+ $this->addOption( 'startserver', 'Start Selenium Server (on localhost) before the run.' );
 54+ $this->addOption( 'stopserver', 'Stop Selenium Server (on localhost) after the run.' );
 55+ $this->addOption( 'jUnitLogFile', 'Log results in a specified JUnit log file. Default: empty', false, true );
 56+ $this->addOption( 'runAgainstGrid', 'The test will be run against a Selenium Grid. Default: false.', false, true );
 57+ $this->deleteOption( 'dbpass' );
 58+ $this->deleteOption( 'dbuser' );
 59+ $this->deleteOption( 'globals' );
 60+ $this->deleteOption( 'wiki' );
 61+ }
 62+
 63+ public function listBrowsers() {
 64+ $desc = "Available browsers:\n";
 65+
 66+ foreach ($this->selenium->getAvailableBrowsers() as $k => $v) {
 67+ $desc .= " $k => $v\n";
 68+ }
 69+
 70+ echo $desc;
 71+ }
 72+
 73+ protected function startServer() {
 74+ if ( $this->seleniumServerExecPath == '' ) {
 75+ die ( "The selenium server exec path is not set in " .
 76+ "selenium_settings.ini. Cannot start server \n" .
 77+ "as requested - terminating RunSeleniumTests\n" );
 78+ }
 79+ $this->serverManager = new SeleniumServerManager( 'true',
 80+ $this->selenium->getPort(),
 81+ $this->seleniumServerExecPath );
 82+ switch ( $this->serverManager->start() ) {
 83+ case 'started':
 84+ break;
 85+ case 'failed':
 86+ die ( "Unable to start the Selenium Server - " .
 87+ "terminating RunSeleniumTests\n" );
 88+ case 'running':
 89+ echo ( "Warning: The Selenium Server is " .
 90+ "already running\n" );
 91+ break;
 92+ }
 93+
 94+ return;
 95+ }
 96+
 97+ protected function stopServer() {
 98+ if ( !isset ( $this->serverManager ) ) {
 99+ echo ( "Warning: Request to stop Selenium Server, but it was " .
 100+ "not stared by RunSeleniumTests\n" .
 101+ "RunSeleniumTests cannot stop a Selenium Server it " .
 102+ "did not start\n" );
 103+ } else {
 104+ switch ( $this->serverManager->stop() ) {
 105+ case 'stopped':
 106+ break;
 107+ case 'failed':
 108+ echo ( "unable to stop the Selenium Server\n" );
 109+ }
 110+ }
 111+ return;
 112+ }
 113+
 114+ protected function runTests( $seleniumTestSuites = array() ) {
 115+ $result = new PHPUnit_Framework_TestResult;
 116+ $result->addListener( new SeleniumTestListener( $this->selenium->getLogger() ) );
 117+ if ( $this->selenium->getJUnitLogFile() ) {
 118+ $jUnitListener = new PHPUnit_Util_Log_JUnit( $this->selenium->getJUnitLogFile(), true );
 119+ $result->addListener( $jUnitListener );
 120+ }
 121+
 122+ foreach ( $seleniumTestSuites as $testSuiteName => $testSuiteFile ) {
 123+ require( $testSuiteFile );
 124+ $suite = new $testSuiteName();
 125+ $suite->setName( $testSuiteName );
 126+ $suite->addTests();
 127+
 128+ try {
 129+ $suite->run( $result );
 130+ } catch ( Testing_Selenium_Exception $e ) {
 131+ $suite->tearDown();
 132+ throw new MWException( $e->getMessage() );
 133+ }
 134+ }
 135+
 136+ if ( $this->selenium->getJUnitLogFile() ) {
 137+ $jUnitListener->flush();
 138+ }
 139+ }
 140+
 141+ public function execute() {
 142+ global $wgServer, $wgScriptPath, $wgHooks;
 143+
 144+ $seleniumSettings;
 145+ $seleniumBrowsers;
 146+ $seleniumTestSuites;
 147+
 148+ $configFile = $this->getOption( 'seleniumConfig', '' );
 149+ if ( strlen( $configFile ) > 0 ) {
 150+ $this->output("Using Selenium Configuration file: " . $configFile . "\n");
 151+ SeleniumConfig::getSeleniumSettings( $seleniumSettings,
 152+ $seleniumBrowsers,
 153+ $seleniumTestSuites,
 154+ $configFile );
 155+ } else if ( !isset( $wgHooks['SeleniumSettings'] ) ) {
 156+ $this->output("No command line configuration file or configuration hook found.\n");
 157+ SeleniumConfig::getSeleniumSettings( $seleniumSettings,
 158+ $seleniumBrowsers,
 159+ $seleniumTestSuites
 160+ );
 161+ } else {
 162+ $this->output("Using 'SeleniumSettings' hook for configuration.\n");
 163+ wfRunHooks('SeleniumSettings', array( $seleniumSettings,
 164+ $seleniumBrowsers,
 165+ $seleniumTestSuites ) );
 166+ }
 167+
 168+ // State for starting/stopping the Selenium server has nothing to do with the Selenium
 169+ // class. Keep this state local to SeleniumTester class. Using getOption() is clumsy, but
 170+ // the Maintenance class does not have a setOption()
 171+ if ( isset( $seleniumSettings['startserver'] ) ) $this->getOption( 'startserver', true );
 172+ if ( isset( $seleniumSettings['stopserver'] ) ) $this->getOption( 'stopserver', true );
 173+ if ( !isset( $seleniumSettings['seleniumserverexecpath'] ) ) $seleniumSettings['seleniumserverexecpath'] = '';
 174+ $this->seleniumServerExecPath = $seleniumSettings['seleniumserverexecpath'];
 175+
 176+ //set reasonable defaults if we did not find the settings
 177+ if ( !isset( $seleniumBrowsers ) ) $seleniumBrowsers = array ('firefox' => '*firefox');
 178+ if ( !isset( $seleniumSettings['host'] ) ) $seleniumSettings['host'] = $wgServer . $wgScriptPath;
 179+ if ( !isset( $seleniumSettings['port'] ) ) $seleniumSettings['port'] = '4444';
 180+ if ( !isset( $seleniumSettings['wikiUrl'] ) ) $seleniumSettings['wikiUrl'] = 'http://localhost';
 181+ if ( !isset( $seleniumSettings['username'] ) ) $seleniumSettings['username'] = '';
 182+ if ( !isset( $seleniumSettings['userPassword'] ) ) $seleniumSettings['userPassword'] = '';
 183+ if ( !isset( $seleniumSettings['testBrowser'] ) ) $seleniumSettings['testBrowser'] = 'firefox';
 184+ if ( !isset( $seleniumSettings['jUnitLogFile'] ) ) $seleniumSettings['jUnitLogFile'] = false;
 185+ if ( !isset( $seleniumSettings['runAgainstGrid'] ) ) $seleniumSettings['runAgainstGrid'] = false;
 186+
 187+ // Setup Selenium class
 188+ $this->selenium = new Selenium( );
 189+ $this->selenium->setAvailableBrowsers( $seleniumBrowsers );
 190+ $this->selenium->setRunAgainstGrid( $this->getOption( 'runAgainstGrid', $seleniumSettings['runAgainstGrid'] ) );
 191+ $this->selenium->setUrl( $this->getOption( 'wikiUrl', $seleniumSettings['wikiUrl'] ) );
 192+ $this->selenium->setBrowser( $this->getOption( 'testBrowser', $seleniumSettings['testBrowser'] ) );
 193+ $this->selenium->setPort( $this->getOption( 'port', $seleniumSettings['port'] ) );
 194+ $this->selenium->setHost( $this->getOption( 'host', $seleniumSettings['host'] ) );
 195+ $this->selenium->setUser( $this->getOption( 'username', $seleniumSettings['username'] ) );
 196+ $this->selenium->setPass( $this->getOption( 'userPassword', $seleniumSettings['userPassword'] ) );
 197+ $this->selenium->setVerbose( $this->hasOption( 'verbose' ) );
 198+ $this->selenium->setJUnitLogFile( $this->getOption( 'jUnitLogFile', $seleniumSettings['jUnitLogFile'] ) );
 199+
 200+ if( $this->hasOption( 'list-browsers' ) ) {
 201+ $this->listBrowsers();
 202+ exit(0);
 203+ }
 204+ if ( $this->hasOption( 'startserver' ) ) {
 205+ $this->startServer();
 206+ }
 207+
 208+ $logger = new SeleniumTestConsoleLogger;
 209+ $this->selenium->setLogger( $logger );
 210+
 211+ $this->runTests( $seleniumTestSuites );
 212+
 213+ if ( $this->hasOption( 'stopserver' ) ) {
 214+ $this->stopServer();
 215+ }
 216+ }
 217+}
 218+
 219+$maintClass = "SeleniumTester";
 220+
 221+require_once( DO_MAINTENANCE );
Property changes on: trunk/phase3/tests/RunSeleniumTests.php
___________________________________________________________________
Added: svn:eol-style
1222 + native
Index: trunk/phase3/tests/parserTests.php
@@ -0,0 +1,92 @@
 2+<?php
 3+/**
 4+ * MediaWiki parser test suite
 5+ *
 6+ * Copyright © 2004 Brion Vibber <brion@pobox.com>
 7+ * http://www.mediawiki.org/
 8+ *
 9+ * This program is free software; you can redistribute it and/or modify
 10+ * it under the terms of the GNU General Public License as published by
 11+ * the Free Software Foundation; either version 2 of the License, or
 12+ * (at your option) any later version.
 13+ *
 14+ * This program is distributed in the hope that it will be useful,
 15+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 17+ * GNU General Public License for more details.
 18+ *
 19+ * You should have received a copy of the GNU General Public License along
 20+ * with this program; if not, write to the Free Software Foundation, Inc.,
 21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 22+ * http://www.gnu.org/copyleft/gpl.html
 23+ *
 24+ * @file
 25+ * @ingroup Testing
 26+ */
 27+
 28+$options = array( 'quick', 'color', 'quiet', 'help', 'show-output', 'record', 'run-disabled' );
 29+$optionsWithArgs = array( 'regex', 'seed', 'setversion' );
 30+
 31+require_once( dirname( __FILE__ ) . '/../maintenance/commandLine.inc' );
 32+
 33+if ( isset( $options['help'] ) ) {
 34+ echo <<<ENDS
 35+MediaWiki $wgVersion parser test suite
 36+Usage: php parserTests.php [options...]
 37+
 38+Options:
 39+ --quick Suppress diff output of failed tests
 40+ --quiet Suppress notification of passed tests (shows only failed tests)
 41+ --show-output Show expected and actual output
 42+ --color[=yes|no] Override terminal detection and force color output on or off
 43+ use wgCommandLineDarkBg = true; if your term is dark
 44+ --regex Only run tests whose descriptions which match given regex
 45+ --file=<testfile> Run test cases from a custom file instead of parserTests.txt
 46+ --record Record tests in database
 47+ --compare Compare with recorded results, without updating the database.
 48+ --setversion When using --record, set the version string to use (useful
 49+ with git-svn so that you can get the exact revision)
 50+ --keep-uploads Re-use the same upload directory for each test, don't delete it
 51+ --fuzz Do a fuzz test instead of a normal test
 52+ --seed <n> Start the fuzz test from the specified seed
 53+ --help Show this help message
 54+ --run-disabled run disabled tests
 55+ --upload Upload test results to remote wiki (per \$wgParserTestRemote)
 56+
 57+ENDS;
 58+ exit( 0 );
 59+}
 60+
 61+# Cases of weird db corruption were encountered when running tests on earlyish
 62+# versions of SQLite
 63+if ( $wgDBtype == 'sqlite' ) {
 64+ $db = wfGetDB( DB_MASTER );
 65+ $version = $db->getServerVersion();
 66+ if ( version_compare( $version, '3.6' ) < 0 ) {
 67+ die( "Parser tests require SQLite version 3.6 or later, you have $version\n" );
 68+ }
 69+}
 70+
 71+# There is a convention that the parser should never
 72+# refer to $wgTitle directly, but instead use the title
 73+# passed to it.
 74+$wgTitle = Title::newFromText( 'Parser test script do not use' );
 75+$tester = new ParserTest($options);
 76+
 77+if ( isset( $options['file'] ) ) {
 78+ $files = array( $options['file'] );
 79+} else {
 80+ // Default parser tests and any set from extensions or local config
 81+ $files = $wgParserTestFiles;
 82+}
 83+
 84+# Print out software version to assist with locating regressions
 85+$version = SpecialVersion::getVersion();
 86+echo( "This is MediaWiki version {$version}.\n\n" );
 87+
 88+if ( isset( $options['fuzz'] ) ) {
 89+ $tester->fuzzTest( $files );
 90+} else {
 91+ $ok = $tester->runTestsFromFiles( $files );
 92+ exit ( $ok ? 0 : 1 );
 93+}
Property changes on: trunk/phase3/tests/parserTests.php
___________________________________________________________________
Added: svn:eol-style
194 + native
Index: trunk/phase3/tests/testHelpers.inc
@@ -0,0 +1,652 @@
 2+<?php
 3+
 4+/**
 5+ * @ingroup Testing
 6+ *
 7+ * Set of classes to help with test output and such. Right now pretty specific
 8+ * to the parser tests but could be more useful one day :)
 9+ *
 10+ * @todo Fixme: Make this more generic
 11+ */
 12+
 13+class AnsiTermColorer {
 14+ function __construct() {
 15+ }
 16+
 17+ /**
 18+ * Return ANSI terminal escape code for changing text attribs/color
 19+ *
 20+ * @param $color String: semicolon-separated list of attribute/color codes
 21+ * @return String
 22+ */
 23+ public function color( $color ) {
 24+ global $wgCommandLineDarkBg;
 25+
 26+ $light = $wgCommandLineDarkBg ? "1;" : "0;";
 27+
 28+ return "\x1b[{$light}{$color}m";
 29+ }
 30+
 31+ /**
 32+ * Return ANSI terminal escape code for restoring default text attributes
 33+ *
 34+ * @return String
 35+ */
 36+ public function reset() {
 37+ return $this->color( 0 );
 38+ }
 39+}
 40+
 41+/* A colour-less terminal */
 42+class DummyTermColorer {
 43+ public function color( $color ) {
 44+ return '';
 45+ }
 46+
 47+ public function reset() {
 48+ return '';
 49+ }
 50+}
 51+
 52+class TestRecorder {
 53+ var $parent;
 54+ var $term;
 55+
 56+ function __construct( $parent ) {
 57+ $this->parent = $parent;
 58+ $this->term = $parent->term;
 59+ }
 60+
 61+ function start() {
 62+ $this->total = 0;
 63+ $this->success = 0;
 64+ }
 65+
 66+ function record( $test, $result ) {
 67+ $this->total++;
 68+ $this->success += ( $result ? 1 : 0 );
 69+ }
 70+
 71+ function end() {
 72+ // dummy
 73+ }
 74+
 75+ function report() {
 76+ if ( $this->total > 0 ) {
 77+ $this->reportPercentage( $this->success, $this->total );
 78+ } else {
 79+ wfDie( "No tests found.\n" );
 80+ }
 81+ }
 82+
 83+ function reportPercentage( $success, $total ) {
 84+ $ratio = wfPercent( 100 * $success / $total );
 85+ print $this->term->color( 1 ) . "Passed $success of $total tests ($ratio)... ";
 86+
 87+ if ( $success == $total ) {
 88+ print $this->term->color( 32 ) . "ALL TESTS PASSED!";
 89+ } else {
 90+ $failed = $total - $success ;
 91+ print $this->term->color( 31 ) . "$failed tests failed!";
 92+ }
 93+
 94+ print $this->term->reset() . "\n";
 95+
 96+ return ( $success == $total );
 97+ }
 98+}
 99+
 100+class DbTestPreviewer extends TestRecorder {
 101+ protected $lb; // /< Database load balancer
 102+ protected $db; // /< Database connection to the main DB
 103+ protected $curRun; // /< run ID number for the current run
 104+ protected $prevRun; // /< run ID number for the previous run, if any
 105+ protected $results; // /< Result array
 106+
 107+ /**
 108+ * This should be called before the table prefix is changed
 109+ */
 110+ function __construct( $parent ) {
 111+ parent::__construct( $parent );
 112+
 113+ $this->lb = wfGetLBFactory()->newMainLB();
 114+ // This connection will have the wiki's table prefix, not parsertest_
 115+ $this->db = $this->lb->getConnection( DB_MASTER );
 116+ }
 117+
 118+ /**
 119+ * Set up result recording; insert a record for the run with the date
 120+ * and all that fun stuff
 121+ */
 122+ function start() {
 123+ parent::start();
 124+
 125+ if ( ! $this->db->tableExists( 'testrun' )
 126+ or ! $this->db->tableExists( 'testitem' ) )
 127+ {
 128+ print "WARNING> `testrun` table not found in database.\n";
 129+ $this->prevRun = false;
 130+ } else {
 131+ // We'll make comparisons against the previous run later...
 132+ $this->prevRun = $this->db->selectField( 'testrun', 'MAX(tr_id)' );
 133+ }
 134+
 135+ $this->results = array();
 136+ }
 137+
 138+ function record( $test, $result ) {
 139+ parent::record( $test, $result );
 140+ $this->results[$test] = $result;
 141+ }
 142+
 143+ function report() {
 144+ if ( $this->prevRun ) {
 145+ // f = fail, p = pass, n = nonexistent
 146+ // codes show before then after
 147+ $table = array(
 148+ 'fp' => 'previously failing test(s) now PASSING! :)',
 149+ 'pn' => 'previously PASSING test(s) removed o_O',
 150+ 'np' => 'new PASSING test(s) :)',
 151+
 152+ 'pf' => 'previously passing test(s) now FAILING! :(',
 153+ 'fn' => 'previously FAILING test(s) removed O_o',
 154+ 'nf' => 'new FAILING test(s) :(',
 155+ 'ff' => 'still FAILING test(s) :(',
 156+ );
 157+
 158+ $prevResults = array();
 159+
 160+ $res = $this->db->select( 'testitem', array( 'ti_name', 'ti_success' ),
 161+ array( 'ti_run' => $this->prevRun ), __METHOD__ );
 162+
 163+ foreach ( $res as $row ) {
 164+ if ( !$this->parent->regex
 165+ || preg_match( "/{$this->parent->regex}/i", $row->ti_name ) )
 166+ {
 167+ $prevResults[$row->ti_name] = $row->ti_success;
 168+ }
 169+ }
 170+
 171+ $combined = array_keys( $this->results + $prevResults );
 172+
 173+ # Determine breakdown by change type
 174+ $breakdown = array();
 175+ foreach ( $combined as $test ) {
 176+ if ( !isset( $prevResults[$test] ) ) {
 177+ $before = 'n';
 178+ } elseif ( $prevResults[$test] == 1 ) {
 179+ $before = 'p';
 180+ } else /* if ( $prevResults[$test] == 0 )*/ {
 181+ $before = 'f';
 182+ }
 183+
 184+ if ( !isset( $this->results[$test] ) ) {
 185+ $after = 'n';
 186+ } elseif ( $this->results[$test] == 1 ) {
 187+ $after = 'p';
 188+ } else /*if ( $this->results[$test] == 0 ) */ {
 189+ $after = 'f';
 190+ }
 191+
 192+ $code = $before . $after;
 193+
 194+ if ( isset( $table[$code] ) ) {
 195+ $breakdown[$code][$test] = $this->getTestStatusInfo( $test, $after );
 196+ }
 197+ }
 198+
 199+ # Write out results
 200+ foreach ( $table as $code => $label ) {
 201+ if ( !empty( $breakdown[$code] ) ) {
 202+ $count = count( $breakdown[$code] );
 203+ printf( "\n%4d %s\n", $count, $label );
 204+
 205+ foreach ( $breakdown[$code] as $differing_test_name => $statusInfo ) {
 206+ print " * $differing_test_name [$statusInfo]\n";
 207+ }
 208+ }
 209+ }
 210+ } else {
 211+ print "No previous test runs to compare against.\n";
 212+ }
 213+
 214+ print "\n";
 215+ parent::report();
 216+ }
 217+
 218+ /**
 219+ * Returns a string giving information about when a test last had a status change.
 220+ * Could help to track down when regressions were introduced, as distinct from tests
 221+ * which have never passed (which are more change requests than regressions).
 222+ */
 223+ private function getTestStatusInfo( $testname, $after ) {
 224+ // If we're looking at a test that has just been removed, then say when it first appeared.
 225+ if ( $after == 'n' ) {
 226+ $changedRun = $this->db->selectField ( 'testitem',
 227+ 'MIN(ti_run)',
 228+ array( 'ti_name' => $testname ),
 229+ __METHOD__ );
 230+ $appear = $this->db->selectRow ( 'testrun',
 231+ array( 'tr_date', 'tr_mw_version' ),
 232+ array( 'tr_id' => $changedRun ),
 233+ __METHOD__ );
 234+
 235+ return "First recorded appearance: "
 236+ . date( "d-M-Y H:i:s", strtotime ( $appear->tr_date ) )
 237+ . ", " . $appear->tr_mw_version;
 238+ }
 239+
 240+ // Otherwise, this test has previous recorded results.
 241+ // See when this test last had a different result to what we're seeing now.
 242+ $conds = array(
 243+ 'ti_name' => $testname,
 244+ 'ti_success' => ( $after == 'f' ? "1" : "0" ) );
 245+
 246+ if ( $this->curRun ) {
 247+ $conds[] = "ti_run != " . $this->db->addQuotes ( $this->curRun );
 248+ }
 249+
 250+ $changedRun = $this->db->selectField ( 'testitem', 'MAX(ti_run)', $conds, __METHOD__ );
 251+
 252+ // If no record of ever having had a different result.
 253+ if ( is_null ( $changedRun ) ) {
 254+ if ( $after == "f" ) {
 255+ return "Has never passed";
 256+ } else {
 257+ return "Has never failed";
 258+ }
 259+ }
 260+
 261+ // Otherwise, we're looking at a test whose status has changed.
 262+ // (i.e. it used to work, but now doesn't; or used to fail, but is now fixed.)
 263+ // In this situation, give as much info as we can as to when it changed status.
 264+ $pre = $this->db->selectRow ( 'testrun',
 265+ array( 'tr_date', 'tr_mw_version' ),
 266+ array( 'tr_id' => $changedRun ),
 267+ __METHOD__ );
 268+ $post = $this->db->selectRow ( 'testrun',
 269+ array( 'tr_date', 'tr_mw_version' ),
 270+ array( "tr_id > " . $this->db->addQuotes ( $changedRun ) ),
 271+ __METHOD__,
 272+ array( "LIMIT" => 1, "ORDER BY" => 'tr_id' )
 273+ );
 274+
 275+ if ( $post ) {
 276+ $postDate = date( "d-M-Y H:i:s", strtotime ( $post->tr_date ) ) . ", {$post->tr_mw_version}";
 277+ } else {
 278+ $postDate = 'now';
 279+ }
 280+
 281+ return ( $after == "f" ? "Introduced" : "Fixed" ) . " between "
 282+ . date( "d-M-Y H:i:s", strtotime ( $pre->tr_date ) ) . ", " . $pre->tr_mw_version
 283+ . " and $postDate";
 284+
 285+ }
 286+
 287+ /**
 288+ * Commit transaction and clean up for result recording
 289+ */
 290+ function end() {
 291+ $this->lb->commitMasterChanges();
 292+ $this->lb->closeAll();
 293+ parent::end();
 294+ }
 295+
 296+}
 297+
 298+class DbTestRecorder extends DbTestPreviewer {
 299+ var $version;
 300+
 301+ /**
 302+ * Set up result recording; insert a record for the run with the date
 303+ * and all that fun stuff
 304+ */
 305+ function start() {
 306+ global $wgDBtype;
 307+ $this->db->begin();
 308+
 309+ if ( ! $this->db->tableExists( 'testrun' )
 310+ or ! $this->db->tableExists( 'testitem' ) )
 311+ {
 312+ print "WARNING> `testrun` table not found in database. Trying to create table.\n";
 313+ $this->db->sourceFile( $this->db->patchPath( 'patch-testrun.sql' ) );
 314+ echo "OK, resuming.\n";
 315+ }
 316+
 317+ parent::start();
 318+
 319+ $this->db->insert( 'testrun',
 320+ array(
 321+ 'tr_date' => $this->db->timestamp(),
 322+ 'tr_mw_version' => $this->version,
 323+ 'tr_php_version' => phpversion(),
 324+ 'tr_db_version' => $this->db->getServerVersion(),
 325+ 'tr_uname' => php_uname()
 326+ ),
 327+ __METHOD__ );
 328+ if ( $wgDBtype === 'postgres' ) {
 329+ $this->curRun = $this->db->currentSequenceValue( 'testrun_id_seq' );
 330+ } else {
 331+ $this->curRun = $this->db->insertId();
 332+ }
 333+ }
 334+
 335+ /**
 336+ * Record an individual test item's success or failure to the db
 337+ *
 338+ * @param $test String
 339+ * @param $result Boolean
 340+ */
 341+ function record( $test, $result ) {
 342+ parent::record( $test, $result );
 343+
 344+ $this->db->insert( 'testitem',
 345+ array(
 346+ 'ti_run' => $this->curRun,
 347+ 'ti_name' => $test,
 348+ 'ti_success' => $result ? 1 : 0,
 349+ ),
 350+ __METHOD__ );
 351+ }
 352+}
 353+
 354+class RemoteTestRecorder extends TestRecorder {
 355+ function start() {
 356+ parent::start();
 357+
 358+ $this->results = array();
 359+ $this->ping( 'running' );
 360+ }
 361+
 362+ function record( $test, $result ) {
 363+ parent::record( $test, $result );
 364+ $this->results[$test] = (bool)$result;
 365+ }
 366+
 367+ function end() {
 368+ $this->ping( 'complete', $this->results );
 369+ parent::end();
 370+ }
 371+
 372+ /**
 373+ * Inform a CodeReview instance that we've started or completed a test run...
 374+ *
 375+ * @param $status string: "running" - tell it we've started
 376+ * "complete" - provide test results array
 377+ * "abort" - something went horribly awry
 378+ * @param $results array of test name => true/false
 379+ */
 380+ function ping( $status, $results = false ) {
 381+ global $wgParserTestRemote, $IP;
 382+
 383+ $remote = $wgParserTestRemote;
 384+ $revId = SpecialVersion::getSvnRevision( $IP );
 385+ $jsonResults = FormatJson::encode( $results );
 386+
 387+ if ( !$remote ) {
 388+ print "Can't do remote upload without configuring \$wgParserTestRemote!\n";
 389+ exit( 1 );
 390+ }
 391+
 392+ // Generate a hash MAC to validate our credentials
 393+ $message = array(
 394+ $remote['repo'],
 395+ $remote['suite'],
 396+ $revId,
 397+ $status,
 398+ );
 399+
 400+ if ( $status == "complete" ) {
 401+ $message[] = $jsonResults;
 402+ }
 403+ $hmac = hash_hmac( "sha1", implode( "|", $message ), $remote['secret'] );
 404+
 405+ $postData = array(
 406+ 'action' => 'codetestupload',
 407+ 'format' => 'json',
 408+ 'repo' => $remote['repo'],
 409+ 'suite' => $remote['suite'],
 410+ 'rev' => $revId,
 411+ 'status' => $status,
 412+ 'hmac' => $hmac,
 413+ );
 414+
 415+ if ( $status == "complete" ) {
 416+ $postData['results'] = $jsonResults;
 417+ }
 418+
 419+ $response = $this->post( $remote['api-url'], $postData );
 420+
 421+ if ( $response === false ) {
 422+ print "CodeReview info upload failed to reach server.\n";
 423+ exit( 1 );
 424+ }
 425+
 426+ $responseData = FormatJson::decode( $response, true );
 427+
 428+ if ( !is_array( $responseData ) ) {
 429+ print "CodeReview API response not recognized...\n";
 430+ wfDebug( "Unrecognized CodeReview API response: $response\n" );
 431+ exit( 1 );
 432+ }
 433+
 434+ if ( isset( $responseData['error'] ) ) {
 435+ $code = $responseData['error']['code'];
 436+ $info = $responseData['error']['info'];
 437+ print "CodeReview info upload failed: $code $info\n";
 438+ exit( 1 );
 439+ }
 440+ }
 441+
 442+ function post( $url, $data ) {
 443+ return Http::post( $url, array( 'postData' => $data ) );
 444+ }
 445+}
 446+
 447+class TestFileIterator implements Iterator {
 448+ private $file;
 449+ private $fh;
 450+ private $parserTest; /* An instance of ParserTest (parserTests.php) or MediaWikiParserTest (phpunit) */
 451+ private $index = 0;
 452+ private $test;
 453+ private $lineNum;
 454+ private $eof;
 455+
 456+ function __construct( $file, $parserTest = null ) {
 457+ global $IP;
 458+
 459+ $this->file = $file;
 460+ $this->fh = fopen( $this->file, "rt" );
 461+
 462+ if ( !$this->fh ) {
 463+ wfDie( "Couldn't open file '$file'\n" );
 464+ }
 465+
 466+ $this->parserTest = $parserTest;
 467+
 468+ if ( $this->parserTest ) {
 469+ $this->parserTest->showRunFile( wfRelativePath( $this->file, $IP ) );
 470+ }
 471+
 472+ $this->lineNum = $this->index = 0;
 473+ }
 474+
 475+ function rewind() {
 476+ if ( fseek( $this->fh, 0 ) ) {
 477+ wfDie( "Couldn't fseek to the start of '$this->file'\n" );
 478+ }
 479+
 480+ $this->index = -1;
 481+ $this->lineNum = 0;
 482+ $this->eof = false;
 483+ $this->next();
 484+
 485+ return true;
 486+ }
 487+
 488+ function current() {
 489+ return $this->test;
 490+ }
 491+
 492+ function key() {
 493+ return $this->index;
 494+ }
 495+
 496+ function next() {
 497+ if ( $this->readNextTest() ) {
 498+ $this->index++;
 499+ return true;
 500+ } else {
 501+ $this->eof = true;
 502+ }
 503+ }
 504+
 505+ function valid() {
 506+ return $this->eof != true;
 507+ }
 508+
 509+ function readNextTest() {
 510+ $data = array();
 511+ $section = null;
 512+
 513+ while ( false !== ( $line = fgets( $this->fh ) ) ) {
 514+ $this->lineNum++;
 515+ $matches = array();
 516+
 517+ if ( preg_match( '/^!!\s*(\w+)/', $line, $matches ) ) {
 518+ $section = strtolower( $matches[1] );
 519+
 520+ if ( $section == 'endarticle' ) {
 521+ if ( !isset( $data['text'] ) ) {
 522+ wfDie( "'endarticle' without 'text' at line {$this->lineNum} of $this->file\n" );
 523+ }
 524+
 525+ if ( !isset( $data['article'] ) ) {
 526+ wfDie( "'endarticle' without 'article' at line {$this->lineNum} of $this->file\n" );
 527+ }
 528+
 529+ if ( $this->parserTest ) {
 530+ $this->parserTest->addArticle( ParserTest::chomp( $data['article'] ), $data['text'], $this->lineNum );
 531+ } else {wfDie("JAJA");
 532+ ParserTest::addArticle( $data['article'], $data['text'], $this->lineNum );
 533+ }
 534+ $data = array();
 535+ $section = null;
 536+
 537+ continue;
 538+ }
 539+
 540+ if ( $section == 'endhooks' ) {
 541+ if ( !isset( $data['hooks'] ) ) {
 542+ wfDie( "'endhooks' without 'hooks' at line {$this->lineNum} of $this->file\n" );
 543+ }
 544+
 545+ foreach ( explode( "\n", $data['hooks'] ) as $line ) {
 546+ $line = trim( $line );
 547+
 548+ if ( $line ) {
 549+ if ( $this->parserTest && !$this->parserTest->requireHook( $line ) ) {
 550+ return false;
 551+ }
 552+ }
 553+ }
 554+
 555+ $data = array();
 556+ $section = null;
 557+
 558+ continue;
 559+ }
 560+
 561+ if ( $section == 'endfunctionhooks' ) {
 562+ if ( !isset( $data['functionhooks'] ) ) {
 563+ wfDie( "'endfunctionhooks' without 'functionhooks' at line {$this->lineNum} of $this->file\n" );
 564+ }
 565+
 566+ foreach ( explode( "\n", $data['functionhooks'] ) as $line ) {
 567+ $line = trim( $line );
 568+
 569+ if ( $line ) {
 570+ if ( $this->parserTest && !$this->parserTest->requireFunctionHook( $line ) ) {
 571+ return false;
 572+ }
 573+ }
 574+ }
 575+
 576+ $data = array();
 577+ $section = null;
 578+
 579+ continue;
 580+ }
 581+
 582+ if ( $section == 'end' ) {
 583+ if ( !isset( $data['test'] ) ) {
 584+ wfDie( "'end' without 'test' at line {$this->lineNum} of $this->file\n" );
 585+ }
 586+
 587+ if ( !isset( $data['input'] ) ) {
 588+ wfDie( "'end' without 'input' at line {$this->lineNum} of $this->file\n" );
 589+ }
 590+
 591+ if ( !isset( $data['result'] ) ) {
 592+ wfDie( "'end' without 'result' at line {$this->lineNum} of $this->file\n" );
 593+ }
 594+
 595+ if ( !isset( $data['options'] ) ) {
 596+ $data['options'] = '';
 597+ }
 598+
 599+ if ( !isset( $data['config'] ) )
 600+ $data['config'] = '';
 601+
 602+ if ( $this->parserTest
 603+ && ( ( preg_match( '/\\bdisabled\\b/i', $data['options'] ) && !$this->parserTest->runDisabled )
 604+ || !preg_match( "/" . $this->parserTest->regex . "/i", $data['test'] ) ) ) {
 605+ # disabled test
 606+ $data = array();
 607+ $section = null;
 608+
 609+ continue;
 610+ }
 611+
 612+ global $wgUseTeX;
 613+
 614+ if ( $this->parserTest &&
 615+ preg_match( '/\\bmath\\b/i', $data['options'] ) && !$wgUseTeX ) {
 616+ # don't run math tests if $wgUseTeX is set to false in LocalSettings
 617+ $data = array();
 618+ $section = null;
 619+
 620+ continue;
 621+ }
 622+
 623+ if ( $this->parserTest ) {
 624+ $this->test = array(
 625+ 'test' => ParserTest::chomp( $data['test'] ),
 626+ 'input' => ParserTest::chomp( $data['input'] ),
 627+ 'result' => ParserTest::chomp( $data['result'] ),
 628+ 'options' => ParserTest::chomp( $data['options'] ),
 629+ 'config' => ParserTest::chomp( $data['config'] ) );
 630+ } else {
 631+ $this->test['test'] = $data['test'];
 632+ }
 633+
 634+ return true;
 635+ }
 636+
 637+ if ( isset ( $data[$section] ) ) {
 638+ wfDie( "duplicate section '$section' at line {$this->lineNum} of $this->file\n" );
 639+ }
 640+
 641+ $data[$section] = '';
 642+
 643+ continue;
 644+ }
 645+
 646+ if ( $section ) {
 647+ $data[$section] .= $line;
 648+ }
 649+ }
 650+
 651+ return false;
 652+ }
 653+}
Property changes on: trunk/phase3/tests/testHelpers.inc
___________________________________________________________________
Added: svn:eol-style
1654 + native
Index: trunk/phase3/includes/AutoLoader.php
@@ -698,45 +698,49 @@
699699 'LanguageConverter' => 'languages/LanguageConverter.php',
700700
701701 # maintenance
702 - 'AnsiTermColorer' => 'maintenance/tests/testHelpers.inc',
703702 'ConvertLinks' => 'maintenance/convertLinks.php',
704 - 'DbTestPreviewer' => 'maintenance/tests/testHelpers.inc',
705 - 'DbTestRecorder' => 'maintenance/tests/testHelpers.inc',
706703 'DeleteArchivedFilesImplementation' => 'maintenance/deleteArchivedFiles.inc',
707704 'DeleteArchivedRevisionsImplementation' => 'maintenance/deleteArchivedRevisions.inc',
708705 'DeleteDefaultMessages' => 'maintenance/deleteDefaultMessages.php',
709 - 'DummyTermColorer' => 'maintenance/tests/testHelpers.inc',
710 - 'ParserTest' => 'maintenance/tests/parser/parserTest.inc',
711 - 'ParserTestParserHook' => 'maintenance/tests/parser/parserTestsParserHook.php',
712 - 'ParserTestStaticParserHook' => 'maintenance/tests/parser/parserTestsStaticParserHook.php',
713706 'PopulateCategory' => 'maintenance/populateCategory.php',
714707 'PopulateLogSearch' => 'maintenance/populateLogSearch.php',
715708 'PopulateParentId' => 'maintenance/populateParentId.php',
716709 'PopulateRevisionLength' => 'maintenance/populateRevisionLength.php',
717 - 'RemoteTestRecorder' => 'maintenance/tests/testHelpers.inc',
718710 'SevenZipStream' => 'maintenance/7zip.inc',
719711 'Sqlite' => 'maintenance/sqlite.inc',
720 - 'TestFileIterator' => 'maintenance/tests/testHelpers.inc',
721 - 'TestRecorder' => 'maintenance/tests/testHelpers.inc',
722712 'UpdateCollation' => 'maintenance/updateCollation.php',
723713 'UpdateRestrictions' => 'maintenance/updateRestrictions.php',
724714 'UserDupes' => 'maintenance/userDupes.inc',
725715
726 - # maintenance/tests/selenium
727 - 'Selenium' => 'maintenance/tests/selenium/Selenium.php',
728 - 'SeleniumLoader' => 'maintenance/tests/selenium/SeleniumLoader.php',
729 - 'SeleniumTestCase' => 'maintenance/tests/selenium/SeleniumTestCase.php',
730 - 'SeleniumTestConsoleLogger' => 'maintenance/tests/selenium/SeleniumTestConsoleLogger.php',
731 - 'SeleniumTestHTMLLogger' => 'maintenance/tests/selenium/SeleniumTestHTMLLogger.php',
732 - 'SeleniumTestListener' => 'maintenance/tests/selenium/SeleniumTestListener.php',
733 - 'SeleniumTestSuite' => 'maintenance/tests/selenium/SeleniumTestSuite.php',
734 - 'SeleniumConfig' => 'maintenance/tests/selenium/SeleniumConfig.php',
735 -
736716 # maintenance/language
737717 'csvStatsOutput' => 'maintenance/language/StatOutputs.php',
738718 'statsOutput' => 'maintenance/language/StatOutputs.php',
739719 'textStatsOutput' => 'maintenance/language/StatOutputs.php',
740720 'wikiStatsOutput' => 'maintenance/language/StatOutputs.php',
 721+
 722+ # tests
 723+ 'AnsiTermColorer' => 'tests/testHelpers.inc',
 724+ 'DbTestPreviewer' => 'maintenance/tests/testHelpers.inc',
 725+ 'DbTestRecorder' => 'maintenance/tests/testHelpers.inc',
 726+ 'DummyTermColorer' => 'maintenance/tests/testHelpers.inc',
 727+ 'RemoteTestRecorder' => 'maintenance/tests/testHelpers.inc',
 728+ 'TestFileIterator' => 'maintenance/tests/testHelpers.inc',
 729+ 'TestRecorder' => 'maintenance/tests/testHelpers.inc',
 730+
 731+ # tests/parser
 732+ 'ParserTest' => 'tests/parser/parserTest.inc',
 733+ 'ParserTestParserHook' => 'tests/parser/parserTestsParserHook.php',
 734+ 'ParserTestStaticParserHook' => 'tests/parser/parserTestsStaticParserHook.php',
 735+
 736+ # tests/selenium
 737+ 'Selenium' => 'tests/selenium/Selenium.php',
 738+ 'SeleniumLoader' => 'tests/selenium/SeleniumLoader.php',
 739+ 'SeleniumTestCase' => 'tests/selenium/SeleniumTestCase.php',
 740+ 'SeleniumTestConsoleLogger' => 'tests/selenium/SeleniumTestConsoleLogger.php',
 741+ 'SeleniumTestHTMLLogger' => 'tests/selenium/SeleniumTestHTMLLogger.php',
 742+ 'SeleniumTestListener' => 'tests/selenium/SeleniumTestListener.php',
 743+ 'SeleniumTestSuite' => 'tests/selenium/SeleniumTestSuite.php',
 744+ 'SeleniumConfig' => 'tests/selenium/SeleniumConfig.php',
741745 );
742746
743747 class AutoLoader {
Index: trunk/phase3/includes/DefaultSettings.php
@@ -3870,8 +3870,8 @@
38713871 * Use full paths.
38723872 */
38733873 $wgParserTestFiles = array(
3874 - "$IP/maintenance/tests/parser/parserTests.txt",
3875 - "$IP/maintenance/tests/parser/extraParserTests.txt"
 3874+ "$IP/tests/parser/parserTests.txt",
 3875+ "$IP/tests/parser/extraParserTests.txt"
38763876 );
38773877
38783878 /**

Follow-up revisions

RevisionCommit summaryAuthorDate
r82873Remove testHelpers.{inc,php} for recommiting with history lost in r78389.platonides23:31, 26 February 2011
r82874Readding parserTests.php and testHelpers.inc with history back to r73884 when...platonides23:36, 26 February 2011
r82876Reapply the @ingroup change which was done in r78389 at the same time it was ...platonides23:44, 26 February 2011

Comments

#Comment by Platonides (talk | contribs)   23:13, 26 February 2011

Status & tagging log