* mediawiki/at-ease was replaced with wikimedia/at-ease.
=== Bug fixes in 1.31 ===
-* (T90902) Non-breaking space in header ID breaks anchor
+* (T90902) Non-breaking space in header ID breaks anchor.
+* (T189375) CSSMin now allows unquoted urls in `url()` syntax to start with a space.
=== Action API changes in 1.31 ===
* (T185058) The 'name' value to tgprop for action=query&list=tags has been
$dbw = wfGetDB( DB_MASTER );
# Avoid excess contention on the same category (T162121)
$name = __METHOD__ . ':' . md5( $this->mName );
- $scopedLock = $dbw->getScopedLockAndFlush( $name, __METHOD__, 1 );
+ $scopedLock = $dbw->getScopedLockAndFlush( $name, __METHOD__, 0 );
if ( !$scopedLock ) {
return false;
}
$class = MWLBFactory::getLBFactoryClass( $lbConf );
$instance = new $class( $lbConf );
- MWLBFactory::setSchemaAliases( $instance );
+ MWLBFactory::setSchemaAliases( $instance, $mainConfig );
return $instance;
},
return $class;
}
- public static function setSchemaAliases( LBFactory $lbFactory ) {
- $mainLB = $lbFactory->getMainLB();
- $masterType = $mainLB->getServerType( $mainLB->getWriterIndex() );
- if ( $masterType === 'mysql' ) {
+ public static function setSchemaAliases( LBFactory $lbFactory, Config $config ) {
+ if ( $config->get( 'DBtype' ) === 'mysql' ) {
/**
* When SQLite indexes were introduced in r45764, it was noted that
* SQLite requires index names to be unique within the whole database,
// is only supported in PHP 5.6. Use a getter method for now.
$urlRegex = '(' .
// Unquoted url
- 'url\(\s*(?P<file0>[^\'"][^\?\)]+?)(?P<query0>\?[^\)]*?|)\s*\)' .
+ 'url\(\s*(?P<file0>[^\s\'"][^\?\)]+?)(?P<query0>\?[^\)]*?|)\s*\)' .
// Single quoted url
'|url\(\s*\'(?P<file1>[^\?\']+?)(?P<query1>\?[^\']*?|)\'\s*\)' .
// Double quoted url
use WANObjectCache;
use Exception;
use RuntimeException;
+use LogicException;
/**
* An interface for generating database load balancers
'hostname' => $this->hostname,
'cliMode' => $this->cliMode,
'agent' => $this->agent,
- 'chronologyProtector' => $this->getChronologyProtector()
+ 'chronologyCallback' => function ( ILoadBalancer $lb ) {
+ // Defer ChronologyProtector construction in case setRequestInfo() ends up
+ // being called later (but before the first connection attempt) (T192611)
+ $this->getChronologyProtector()->initLB( $lb );
+ }
];
}
}
public function setRequestInfo( array $info ) {
+ if ( $this->chronProt ) {
+ throw new LogicException( 'ChronologyProtector already initialized.' );
+ }
+
$this->requestInfo = $info + $this->requestInfo;
}
* - maxLag: Avoid replica DB servers with more lag than this [optional]
* - srvCache : BagOStuff object for server cache [optional]
* - wanCache : WANObjectCache object [optional]
- * - chronologyProtector: ChronologyProtector object [optional]
+ * - chronologyCallback: Callback to run before the first connection attempt [optional]
* - hostname : The name of the current server [optional]
* - cliMode: Whether the execution context is a CLI script. [optional]
* - profiler : Class name or instance with profileIn()/profileOut() methods. [optional]
/** @var ILoadMonitor */
private $loadMonitor;
- /** @var ChronologyProtector|null */
- private $chronProt;
+ /** @var callable|null Callback to run before the first connection attempt */
+ private $chronologyCallback;
/** @var BagOStuff */
private $srvCache;
/** @var WANObjectCache */
/** @var bool */
private $disabled = false;
- /** @var bool */
- private $chronProtInitialized = false;
+ /** @var bool Whether any connection has been attempted yet */
+ private $connectionAttempted = false;
/** @var int */
private $maxLag = self::MAX_LAG_DEFAULT;
: ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' );
$this->agent = isset( $params['agent'] ) ? $params['agent'] : '';
- if ( isset( $params['chronologyProtector'] ) ) {
- $this->chronProt = $params['chronologyProtector'];
+ if ( isset( $params['chronologyCallback'] ) ) {
+ $this->chronologyCallback = $params['chronologyCallback'];
}
}
} else {
$i = false;
if ( $this->waitForPos && $this->waitForPos->asOfTime() ) {
- // ChronologyProtecter sets "waitForPos" for session consistency.
+ // "chronologyCallback" sets "waitForPos" for session consistency.
// This triggers doWait() after connect, so it's especially good to
// avoid lagged servers so as to avoid excessive delay in that method.
$ago = microtime( true ) - $this->waitForPos->asOfTime();
$domain = false; // local connection requested
}
- if ( !$this->chronProtInitialized && $this->chronProt ) {
+ if ( !$this->connectionAttempted && $this->chronologyCallback ) {
$this->connLogger->debug( __METHOD__ . ': calling initLB() before first connection.' );
- // Load CP positions before connecting so that doWait() triggers later if needed
- $this->chronProtInitialized = true;
- $this->chronProt->initLB( $this );
+ // Load any "waitFor" positions before connecting so that doWait() is triggered
+ $this->connectionAttempted = true;
+ call_user_func( $this->chronologyCallback, $this );
}
// Check if an auto-commit connection is being requested. If so, it will not reuse the
"qunit": "grunt qunit",
"doc": "jsduck",
"postdoc": "grunt copy:jsduck",
- "selenium": "./tests/selenium/selenium.sh"
+ "selenium": "./tests/selenium/selenium.sh",
+ "selenium-test": "grunt webdriver:test"
},
"devDependencies": {
"bluebird": "3.5.1",
"karma-chrome-launcher": "2.2.0",
"karma-firefox-launcher": "1.0.1",
"karma-mocha-reporter": "2.2.5",
- "karma-qunit": "1.2.1",
+ "karma-qunit": "2.0.1",
"mwbot": "1.0.10",
"postcss-less": "1.1.5",
- "qunitjs": "2.4.1",
+ "qunit": "2.5.0",
"stylelint": "9.2.0",
"stylelint-config-wikimedia": "0.4.3",
"wdio-junit-reporter": "0.2.0",
public function testWithoutReplica() {
global $wgDBname;
+ $called = false;
$lb = new LoadBalancer( [
'servers' => [ $this->makeServerConfig() ],
'queryLogger' => MediaWiki\Logger\LoggerFactory::getInstance( 'DBQuery' ),
- 'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() )
+ 'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() ),
+ 'chronologyCallback' => function () use ( &$called ) {
+ $called = true;
+ }
] );
$ld = DatabaseDomain::newFromId( $lb->getLocalDomainID() );
$this->assertEquals( $wgDBname, $ld->getDatabase(), 'local domain DB set' );
$this->assertEquals( $this->dbPrefix(), $ld->getTablePrefix(), 'local domain prefix set' );
+ $this->assertFalse( $called );
$dbw = $lb->getConnection( DB_MASTER );
+ $this->assertTrue( $called );
$this->assertTrue( $dbw->getLBInfo( 'master' ), 'master shows as master' );
$this->assertTrue( $dbw->getFlag( $dbw::DBO_TRX ), "DBO_TRX set on master" );
$this->assertWriteAllowed( $dbw );
'foo { background: url(//localhost/styles.css?quoted=single) }',
],
[
- 'Background URL (containing parentheses; T60473)',
+ 'Background URL (double quoted, containing parentheses; T60473)',
'foo { background: url("//localhost/styles.css?query=(parens)") }',
'foo { background: url("//localhost/styles.css?query=(parens)") }',
],
'foo { background: url(\'//localhost/styles.css?quote="\') }',
'foo { background: url("//localhost/styles.css?quote=\"") }',
],
+ [
+ 'Background URL (double quoted with outer spacing)',
+ 'foo { background: url( "http://localhost/styles.css?quoted=double" ) }',
+ 'foo { background: url(http://localhost/styles.css?quoted=double) }',
+ ],
[
'Simple case with comments before url',
'foo { prop: /* some {funny;} comment */ url(bar.png); }',
$this->assertEquals( '{"foo":"Example"}', $blob, 'Generated blob' );
}
+ /**
+ * Seems to fail sometimes (T176097).
+ *
+ * @group Broken
+ */
public function testGetBlobCached() {
$module = $this->makeModule( [ 'example' ] );
$rl = new ResourceLoader();
killall chromedriver > /dev/null
}
trap kill_chromedriver EXIT
-./node_modules/.bin/grunt webdriver:test
+npm run selenium-test