<exclude name="MediaWiki.Files.ClassMatchesFilename.NotMatch" />
<exclude name="Generic.Files.OneObjectStructurePerFile.MultipleFound" />
<exclude name="MediaWiki.VariableAnalysis.ForbiddenGlobalVariables.ForbiddenGlobal$wgTitle" />
- <exclude name="MediaWiki.Usage.DeprecatedConstantUsage.NS_IMAGE" />
- <exclude name="MediaWiki.Usage.DeprecatedConstantUsage.NS_IMAGE_TALK" />
<exclude name="MediaWiki.Commenting.FunctionComment.SpacingDocStar" />
<exclude name="MediaWiki.Commenting.FunctionComment.SpacingDocTag" />
<exclude name="Squiz.Scope.MethodScope.Missing" />
"homepage": "https://www.mediawiki.org/wiki/Special:Version/Credits"
}
],
- "license": "GPL-2.0+",
+ "license": "GPL-2.0-or-later",
"support": {
"issues": "https://bugs.mediawiki.org/",
"irc": "irc://irc.freenode.net/mediawiki",
* 'version' => '1.9.0',
* 'url' => 'https://example.org/example-extension/',
* 'descriptionmsg' => 'exampleextension-desc',
- * 'license-name' => 'GPL-2.0+',
+ * 'license-name' => 'GPL-2.0-or-later',
* ];
* @endcode
*
* localizable message (omit in favour of 'descriptionmsg').
*
* - license-name: Short name of the license (used as label for the link), such
- * as "GPL-2.0+" or "MIT" (https://spdx.org/licenses/ for a list of identifiers).
+ * as "GPL-2.0-or-later" or "MIT" (https://spdx.org/licenses/ for a list of identifiers).
*/
$wgExtensionCredits = [];
*/
function wfDebug( $text, $dest = 'all', array $context = [] ) {
global $wgDebugRawPage, $wgDebugLogPrefix;
- global $wgDebugTimestamps, $wgRequestTime;
+ global $wgDebugTimestamps;
if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
return;
if ( $wgDebugTimestamps ) {
$context['seconds_elapsed'] = sprintf(
'%6.4f',
- microtime( true ) - $wgRequestTime
+ microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT']
);
$context['memory_used'] = sprintf(
'%5.1fM',
* @return string
*/
function wfReportTime() {
- global $wgRequestTime, $wgShowHostnames;
+ global $wgShowHostnames;
- $responseTime = round( ( microtime( true ) - $wgRequestTime ) * 1000 );
+ $elapsed = ( microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT'] );
+ // seconds to milliseconds
+ $responseTime = round( $elapsed * 1000 );
$reportVars = [ 'wgBackendResponseTime' => $responseTime ];
if ( $wgShowHostnames ) {
$reportVars['wgHostname'] = wfHostname();
* @return RevisionRecord|null
*/
public function getRevisionByTimestamp( $title, $timestamp ) {
+ $db = $this->getDBConnection( DB_REPLICA );
return $this->newRevisionFromConds(
[
- 'rev_timestamp' => $timestamp,
+ 'rev_timestamp' => $db->timestamp( $timestamp ),
'page_namespace' => $title->getNamespace(),
'page_title' => $title->getDBkey()
],
* @codeCoverageIgnore
*/
public function __construct() {
- $this->requestTime = isset( $_SERVER['REQUEST_TIME_FLOAT'] )
- ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime( true );
+ $this->requestTime = $_SERVER['REQUEST_TIME_FLOAT'];
// POST overrides GET data
// We don't use $_REQUEST here to avoid interference from cookies...
realpath( __DIR__ ) ?: __DIR__ => [
'path' => $IP,
'name' => 'MediaWiki',
- 'license-name' => 'GPL-2.0+',
+ 'license-name' => 'GPL-2.0-or-later',
],
realpath( "$IP/extensions" ) ?: "$IP/extensions" => null,
realpath( $extDir ) ?: $extDir => null,
if ( $this->getIsWrappedHtml() ) {
// This is a special output mode mainly intended for ApiSandbox use
- $time = microtime( true ) - $this->getConfig()->get( 'RequestTime' );
+ $time = $this->getMain()->getRequest()->getElapsedTime();
$json = FormatJson::encode(
[
'status' => (int)( $this->mHttpStatus ?: 200 ),
'host' => $showHostnames
? $lb->getServerName( $index )
: '',
- 'lag' => intval( $lag )
+ 'lag' => $lag
];
}
return [];
}
- global $wgVersion, $wgRequestTime;
+ global $wgVersion;
$request = $context->getRequest();
// HHVM's reported memory usage from memory_get_peak_usage()
'gitRevision' => GitInfo::headSHA1(),
'gitBranch' => $branch,
'gitViewUrl' => GitInfo::headViewUrl(),
- 'time' => microtime( true ) - $wgRequestTime,
+ 'time' => $request->getElapsedTime(),
'log' => self::$log,
'debugLog' => self::$debug,
'queries' => self::$query,
}
/**
- * @static
* @param string $msg
*
* @return mixed
"NS_PROJECT_TALK" => NS_PROJECT_TALK,
"NS_FILE" => NS_FILE,
"NS_FILE_TALK" => NS_FILE_TALK,
- "NS_IMAGE" => NS_IMAGE, // NS_IMAGE is an alias for NS_FILE
- "NS_IMAGE_TALK" => NS_IMAGE_TALK,
+ "NS_IMAGE" => NS_FILE, // NS_IMAGE is an alias for NS_FILE
+ "NS_IMAGE_TALK" => NS_FILE_TALK,
"NS_MEDIAWIKI" => NS_MEDIAWIKI,
"NS_MEDIAWIKI_TALK" => NS_MEDIAWIKI_TALK,
"NS_TEMPLATE" => NS_TEMPLATE,
* many rows where updated.
*/
protected function doDBUpdates() {
+ global $wgCommentTableSchemaMigrationStage;
+
$dbw = $this->db;
// Update current image
[ 'img_name' => $this->oldName ],
__METHOD__
);
+ if ( $wgCommentTableSchemaMigrationStage > MIGRATION_OLD ) {
+ $dbw->update(
+ 'image_comment_temp',
+ [ 'imgcomment_name' => $this->newName ],
+ [ 'imgcomment_name' => $this->oldName ],
+ __METHOD__
+ );
+ }
+
// Update old images
$dbw->update(
'oldimage',
/**
* Prepare form for submission.
*
- * @attention When doing method chaining, that should be the very last
+ * @warning When doing method chaining, that should be the very last
* method call before displayForm().
*
* @throws MWException
* Display the form (sending to the context's OutputPage object), with an
* appropriate error message or stack of messages, and any validation errors, etc.
*
- * @attention You should call prepareForm() before calling this function.
+ * @warning You should call prepareForm() before calling this function.
* Moreover, when doing method chaining this should be the very last method
* call just after prepareForm().
*
// phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
for ( $i = $this->maxPartitionsTry; $i > 0 && count( $jobsLeft ); --$i ) {
try {
- $partitionRing->getLiveRing();
+ $partitionRing->getLiveLocationWeights();
} catch ( UnexpectedValueException $e ) {
break; // all servers down; nothing to insert to
}
* @param string $item
* @return string Location
*/
- public function getLocation( $item ) {
+ final public function getLocation( $item ) {
$locations = $this->getLocations( $item, 1 );
return $locations[0];
return $this->sourceMap;
}
- /**
- * Get a new hash ring with a location removed from the ring
- *
- * @param string $location
- * @return HashRing|bool Returns false if no non-zero weighted spots are left
- */
- public function newWithoutLocation( $location ) {
- $map = $this->sourceMap;
- unset( $map[$location] );
-
- return count( $map ) ? new self( $map ) : false;
- }
-
/**
* Remove a location from the "live" hash ring
*
* @return HashRing
* @throws UnexpectedValueException
*/
- public function getLiveRing() {
+ protected function getLiveRing() {
$now = time();
if ( $this->liveRing === null || $this->ejectionNextExpiry <= $now ) {
$this->ejectionExpiries = array_filter(
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @license GPL-2.0+
+ * @license GPL-2.0-or-later
* @author Kunal Mehta <legoktm@member.fsf.org>
*/
'requestStart' => [
'name' => 'requestStart',
'entryType' => 'mark',
- 'startTime' => isset( $_SERVER['REQUEST_TIME_FLOAT'] )
- ? $_SERVER['REQUEST_TIME_FLOAT']
- : $_SERVER['REQUEST_TIME'],
+ 'startTime' => $_SERVER['REQUEST_TIME_FLOAT'],
'duration' => 0,
],
];
* To use this with a request header, first parse the header value into an array of weights
* using HttpAcceptParser, then call getBestSupportedKey.
*
- * @license GPL-2.0+
+ * @license GPL-2.0-or-later
* @author Daniel Kinzler
* @author Thiemo Kreuz
*/
* Utility for parsing a HTTP Accept header value into a weight map. May also be used with
* other, similar headers like Accept-Language, Accept-Encoding, etc.
*
- * @license GPL-2.0+
+ * @license GPL-2.0-or-later
* @author Daniel Kinzler
*/
public function estimateRowCount(
$table, $vars = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
) {
- $rows = 0;
$res = $this->select(
$table, [ 'rowcount' => 'COUNT(*)' ], $conds, $fname, $options, $join_conds
);
+ $row = $res ? $this->fetchRow( $res ) : [];
- if ( $res ) {
- $row = $this->fetchRow( $res );
- $rows = ( isset( $row['rowcount'] ) ) ? (int)$row['rowcount'] : 0;
- }
-
- return $rows;
+ return isset( $row['rowcount'] ) ? (int)$row['rowcount'] : 0;
}
public function selectRowCount(
if ( is_array( $table ) ) {
// A parenthesized group
if ( count( $table ) > 1 ) {
- $joinedTable = '('
- . $this->tableNamesWithIndexClauseOrJOIN( $table, $use_index, $ignore_index, $join_conds )
- . ')';
+ $joinedTable = '(' .
+ $this->tableNamesWithIndexClauseOrJOIN(
+ $table, $use_index, $ignore_index, $join_conds ) . ')';
} else {
// Degenerate case
$innerTable = reset( $table );
}
}
- return ' LIKE ' . $this->addQuotes( $s ) . ' ESCAPE ' . $this->addQuotes( $escapeChar ) . ' ';
+ return ' LIKE ' .
+ $this->addQuotes( $s ) . ' ESCAPE ' . $this->addQuotes( $escapeChar ) . ' ';
}
public function anyChar() {
/**
* Example virtual rest service for OpenStack Swift
- * @TODO: caching support (APC/memcached)
+ * @todo caching support (APC/memcached)
* @since 1.23
*/
class SwiftVirtualRESTService extends VirtualRESTService {
/**
* Get an array of parameters to pass to ParserOutput::setLimitReportData()
*
- * @unstable Should only be called by Parser
+ * @internal Should only be called by Parser
* @return array
*/
public function getLimitReport() {
* the same moment that the function to be profiled terminates.
*
* This is typically called like:
- * @code$section = new ProfileSection( __METHOD__ );@endcode
+ * @code $section = new ProfileSection( __METHOD__ ); @endcode
*
* @param string $name Name of the function to profile
*/
* 'https://example.org/image.png' => [ 'as' => 'image' ],
* ];
* }
- * @encode
+ * @endcode
*
* @par Example using HiDPI image variants
* @code
* ],
* ];
* }
- * @encode
+ * @endcode
*
* @see ResourceLoaderModule::getHeaders
* @since 1.30
* Do some sanity checking and basic setup
*/
public function setup() {
- global $IP, $wgCommandLineMode, $wgRequestTime;
+ global $IP, $wgCommandLineMode;
# Abort if called from a web server
# wfIsCLI() is not available yet
# But sometimes this doesn't seem to be the case.
ini_set( 'max_execution_time', 0 );
- $wgRequestTime = microtime( true );
-
# Define us as being in MediaWiki
define( 'MEDIAWIKI', true );
}
public function execute() {
- global $wgRequestTime;
-
if ( !$this->enabled ) {
$this->fatalError( "Nothing to do -- \$wgUseFileCache is disabled." );
}
$this->fatalError( "Nothing to do." );
}
- $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client
+ // Mock request (hack, no real client)
+ $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip';
# Do remaining chunk
$end += $batchSize - 1;
}
Wikimedia\suppressWarnings(); // header notices
- // Cache ?action=view
- $wgRequestTime = microtime( true ); # T24852
+
+ // 1. Cache ?action=view
+ // Be sure to reset the mocked request time (T24852)
+ $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
ob_start();
$article->view();
$context->getOutput()->output();
$context->getOutput()->clearHTML();
$viewHtml = ob_get_clean();
$viewCache->saveToFileCache( $viewHtml );
- // Cache ?action=history
- $wgRequestTime = microtime( true ); # T24852
+
+ // 2. Cache ?action=history
+ // Be sure to reset the mocked request time (T24852)
+ $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
ob_start();
Action::factory( 'history', $article, $context )->show();
$context->getOutput()->output();
$context->getOutput()->clearHTML();
$historyHtml = ob_get_clean();
$historyCache->saveToFileCache( $historyHtml );
+
Wikimedia\restoreWarnings();
if ( $rebuilt ) {
margin: 0 !important; /* stylelint-disable-line declaration-no-important */
}
-#toc,
.toc {
background-color: #f9f9f9;
border: 1pt solid #aaa;
border: 0;
}
-#toc,
.toc {
border: 1px solid #bba;
background-color: #f7f8ff;
}
/* CSS for backwards-compatibility with cached page renders and creative uses in wikitext */
-table#toc,
table.toc {
border-collapse: collapse;
}
/* Remove additional paddings inside table-cells that are not present in <div>s */
-table#toc td,
table.toc td {
padding: 0;
}
-#toc h2,
.toc h2 {
display: inline;
border: 0;
font-weight: bold;
}
-#toc ul,
.toc ul {
list-style-type: none;
list-style-image: none;
text-align: left;
}
-#toc ul ul,
.toc ul ul {
margin: 0 0 0 2em;
}
font-size: 100%;
}
-/* use this instead of #toc for page content */
+/* use this instead of .toc for page content */
.toccolours {
border: 1px solid #aaa;
background-color: #f9f9f9;
list-style-type: oriya;
}
-#toc ul,
.toc ul {
margin: 0.3em 0;
}
/* Correct directionality when page dir is different from site/user dir */
/* @noflip */ .mw-content-ltr .toc ul,
-.mw-content-ltr #toc ul,
-.mw-content-rtl .mw-content-ltr .toc ul,
-.mw-content-rtl .mw-content-ltr #toc ul {
+.mw-content-rtl .mw-content-ltr .toc ul {
text-align: left;
}
/* @noflip */ .mw-content-rtl .toc ul,
-.mw-content-rtl #toc ul,
-.mw-content-ltr .mw-content-rtl .toc ul,
-.mw-content-ltr .mw-content-rtl #toc ul {
+.mw-content-ltr .mw-content-rtl .toc ul {
text-align: right;
}
/* @noflip */ .mw-content-ltr .toc ul ul,
-.mw-content-ltr #toc ul ul,
-.mw-content-rtl .mw-content-ltr .toc ul ul,
-.mw-content-rtl .mw-content-ltr #toc ul ul {
+.mw-content-rtl .mw-content-ltr .toc ul ul {
margin: 0 0 0 2em;
}
/* @noflip */ .mw-content-rtl .toc ul ul,
-.mw-content-rtl #toc ul ul,
-.mw-content-ltr .mw-content-rtl .toc ul ul,
-.mw-content-ltr .mw-content-rtl #toc ul ul {
+.mw-content-ltr .mw-content-rtl .toc ul ul {
margin: 0 2em 0 0;
}
-#toc #toctitle,
-.toc #toctitle,
-#toc .toctitle,
.toc .toctitle {
direction: ltr;
}
*/
/* Table of Contents */
-#toc,
.toc,
.mw-warning,
.toccolours {
* inline elements. In practice inline elements surrounding the TOC are uncommon enough that
* this is an acceptable sacrifice.
*/
-#toc,
.toc {
display: inline-block;
display: table;
}
/* CSS for backwards-compatibility with cached page renders and creative uses in wikitext */
-table#toc,
table.toc {
border-collapse: collapse;
}
/* Remove additional paddings inside table-cells that are not present in <div>s */
-table#toc td,
table.toc td {
padding: 0;
}
-#toc h2,
.toc h2 {
display: inline;
border: 0;
font-weight: bold;
}
-#toc #toctitle,
-.toc #toctitle,
-#toc .toctitle,
.toc .toctitle {
text-align: center;
}
-#toc ul,
.toc ul {
list-style-type: none;
list-style-image: none;
text-align: left;
}
-#toc ul ul,
.toc ul ul {
margin: 0 0 0 2em;
}
-#toc.tochidden,
.toc.tochidden,
.toctoggle {
display: none;
* Note: borrows from IP::isIPv4
*
* @param {string} address
- * @param {boolean} allowBlock
+ * @param {boolean} [allowBlock=false]
* @return {boolean}
*/
isIPv4Address: function ( address, allowBlock ) {
* Note: borrows from IP::isIPv6
*
* @param {string} address
- * @param {boolean} allowBlock
+ * @param {boolean} [allowBlock=false]
* @return {boolean}
*/
isIPv6Address: function ( address, allowBlock ) {
*
* @since 1.25
* @param {string} address String to check
- * @param {boolean} allowBlock True if a block of IPs should be allowed
+ * @param {boolean} [allowBlock=false] If a block of IPs should be allowed
* @return {boolean}
*/
isIPAddress: function ( address, allowBlock ) {
'ApiTestCase' => "$testDir/phpunit/includes/api/ApiTestCase.php",
'ApiTestCaseUpload' => "$testDir/phpunit/includes/api/ApiTestCaseUpload.php",
'ApiTestContext' => "$testDir/phpunit/includes/api/ApiTestContext.php",
+ 'ApiUploadTestCase' => "$testDir/phpunit/includes/api/ApiUploadTestCase.php",
'MockApi' => "$testDir/phpunit/includes/api/MockApi.php",
'MockApiQueryBase' => "$testDir/phpunit/includes/api/MockApiQueryBase.php",
'UserWrapper' => "$testDir/phpunit/includes/api/UserWrapper.php",
/**
* Remove last character if it is a newline
- * @group utility
* @param string $s
* @return string
*/
"homepage": "https://www.mediawiki.org/wiki/Special:Version/Credits"
}
],
- "license": "GPL-2.0",
+ "license": "GPL-2.0-only",
"support": {
"issues": "https://bugzilla.wikimedia.org/",
"irc": "irc://irc.freenode.net/mediawiki",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT",
- "GPL-3.0"
+ "GPL-3.0-only"
],
"authors": [
{
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "GPL-2.0+"
+ "GPL-2.0-or-later"
],
"authors": [
{
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "GPL-2.0+",
+ "GPL-2.0-or-later",
"MIT"
],
"description": "The primary aim is to allow users to select a language and configure its support in an easy way. Main features are language selection, input methods and web fonts.",
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "GPL-2.0"
+ "GPL-2.0-only"
],
"authors": [
{
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT",
- "GPL-3.0"
+ "GPL-3.0-only"
],
"authors": [
{
"homepage": "https://www.mediawiki.org/wiki/Special:Version/Credits"
}
],
- "license": "GPL-2.0",
+ "license": "GPL-2.0-only",
"support": {
"issues": "https://bugzilla.wikimedia.org/",
"irc": "irc://irc.freenode.net/mediawiki",
public function testDetectServer( $expected, $input, $description ) {
$this->setMwGlobals( 'wgAssumeProxiesUseDefaultProtocolPorts', true );
- $_SERVER = $input;
+ $this->setServerVars( $input );
$result = WebRequest::detectServer();
$this->assertEquals( $expected, $result, $description );
}
* @covers WebRequest::getIP
*/
public function testGetIP( $expected, $input, $squid, $xffList, $private, $description ) {
- $_SERVER = $input;
+ $this->setServerVars( $input );
$this->setMwGlobals( [
'wgUsePrivateIPs' => $private,
'wgHooks' => [
* @covers WebRequest::getAcceptLang
*/
public function testAcceptLang( $acceptLanguageHeader, $expectedLanguages, $description ) {
- $_SERVER = [ 'HTTP_ACCEPT_LANGUAGE' => $acceptLanguageHeader ];
+ $this->setServerVars( [ 'HTTP_ACCEPT_LANGUAGE' => $acceptLanguageHeader ] );
$request = new WebRequest();
$this->assertSame( $request->getAcceptLang(), $expectedLanguages, $description );
}
+
+ protected function setServerVars( $vars ) {
+ // Don't remove vars which should be available in all SAPI.
+ if ( !isset( $vars['REQUEST_TIME_FLOAT'] ) ) {
+ $vars['REQUEST_TIME_FLOAT'] = $_SERVER['REQUEST_TIME_FLOAT'];
+ }
+ if ( !isset( $vars['REQUEST_TIME'] ) ) {
+ $vars['REQUEST_TIME'] = $_SERVER['REQUEST_TIME'];
+ }
+ $_SERVER = $vars;
+ }
}
<?php
/**
- * Abstract class to support upload tests
+ * For backward compatibility since 1.31
*/
-abstract class ApiTestCaseUpload extends ApiTestCase {
- /**
- * Fixture -- run before every test
- */
- protected function setUp() {
- parent::setUp();
+abstract class ApiTestCaseUpload extends ApiUploadTestCase {
- $this->setMwGlobals( [
- 'wgEnableUploads' => true,
- 'wgEnableAPI' => true,
- ] );
-
- $this->clearFakeUploads();
- }
-
- /**
- * Helper function -- remove files and associated articles by Title
- *
- * @param Title $title Title to be removed
- *
- * @return bool
- */
- public function deleteFileByTitle( $title ) {
- if ( $title->exists() ) {
- $file = wfFindFile( $title, [ 'ignoreRedirect' => true ] );
- $noOldArchive = ""; // yes this really needs to be set this way
- $comment = "removing for test";
- $restrictDeletedVersions = false;
- $status = FileDeleteForm::doDelete(
- $title,
- $file,
- $noOldArchive,
- $comment,
- $restrictDeletedVersions
- );
-
- if ( !$status->isGood() ) {
- return false;
- }
-
- $page = WikiPage::factory( $title );
- $page->doDeleteArticle( "removing for test" );
-
- // see if it now doesn't exist; reload
- $title = Title::newFromText( $title->getText(), NS_FILE );
- }
-
- return !( $title && $title instanceof Title && $title->exists() );
- }
-
- /**
- * Helper function -- remove files and associated articles with a particular filename
- *
- * @param string $fileName Filename to be removed
- *
- * @return bool
- */
- public function deleteFileByFileName( $fileName ) {
- return $this->deleteFileByTitle( Title::newFromText( $fileName, NS_FILE ) );
- }
-
- /**
- * Helper function -- given a file on the filesystem, find matching
- * content in the db (and associated articles) and remove them.
- *
- * @param string $filePath Path to file on the filesystem
- *
- * @return bool
- */
- public function deleteFileByContent( $filePath ) {
- $hash = FSFile::getSha1Base36FromPath( $filePath );
- $dupes = RepoGroup::singleton()->findBySha1( $hash );
- $success = true;
- foreach ( $dupes as $dupe ) {
- $success &= $this->deleteFileByTitle( $dupe->getTitle() );
- }
-
- return $success;
- }
-
- /**
- * Fake an upload by dumping the file into temp space, and adding info to $_FILES.
- * (This is what PHP would normally do).
- *
- * @param string $fieldName Name this would have in the upload form
- * @param string $fileName Name to title this
- * @param string $type MIME type
- * @param string $filePath Path where to find file contents
- *
- * @throws Exception
- * @return bool
- */
- function fakeUploadFile( $fieldName, $fileName, $type, $filePath ) {
- $tmpName = $this->getNewTempFile();
- if ( !file_exists( $filePath ) ) {
- throw new Exception( "$filePath doesn't exist!" );
- }
-
- if ( !copy( $filePath, $tmpName ) ) {
- throw new Exception( "couldn't copy $filePath to $tmpName" );
- }
-
- clearstatcache();
- $size = filesize( $tmpName );
- if ( $size === false ) {
- throw new Exception( "couldn't stat $tmpName" );
- }
-
- $_FILES[$fieldName] = [
- 'name' => $fileName,
- 'type' => $type,
- 'tmp_name' => $tmpName,
- 'size' => $size,
- 'error' => null
- ];
-
- return true;
- }
-
- function fakeUploadChunk( $fieldName, $fileName, $type, & $chunkData ) {
- $tmpName = $this->getNewTempFile();
- // copy the chunk data to temp location:
- if ( !file_put_contents( $tmpName, $chunkData ) ) {
- throw new Exception( "couldn't copy chunk data to $tmpName" );
- }
-
- clearstatcache();
- $size = filesize( $tmpName );
- if ( $size === false ) {
- throw new Exception( "couldn't stat $tmpName" );
- }
-
- $_FILES[$fieldName] = [
- 'name' => $fileName,
- 'type' => $type,
- 'tmp_name' => $tmpName,
- 'size' => $size,
- 'error' => null
- ];
- }
-
- /**
- * Remove traces of previous fake uploads
- */
- function clearFakeUploads() {
- $_FILES = [];
- }
}
*
* @covers ApiUpload
*/
-class ApiUploadTest extends ApiTestCaseUpload {
+class ApiUploadTest extends ApiUploadTestCase {
/**
* Testing login
* XXX this is a funny way of getting session context
--- /dev/null
+<?php
+
+/**
+ * Abstract class to support upload tests
+ */
+abstract class ApiUploadTestCase extends ApiTestCase {
+ /**
+ * Fixture -- run before every test
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ $this->setMwGlobals( [
+ 'wgEnableUploads' => true,
+ 'wgEnableAPI' => true,
+ ] );
+
+ $this->clearFakeUploads();
+ }
+
+ /**
+ * Helper function -- remove files and associated articles by Title
+ *
+ * @param Title $title Title to be removed
+ *
+ * @return bool
+ */
+ public function deleteFileByTitle( $title ) {
+ if ( $title->exists() ) {
+ $file = wfFindFile( $title, [ 'ignoreRedirect' => true ] );
+ $noOldArchive = ""; // yes this really needs to be set this way
+ $comment = "removing for test";
+ $restrictDeletedVersions = false;
+ $status = FileDeleteForm::doDelete(
+ $title,
+ $file,
+ $noOldArchive,
+ $comment,
+ $restrictDeletedVersions
+ );
+
+ if ( !$status->isGood() ) {
+ return false;
+ }
+
+ $page = WikiPage::factory( $title );
+ $page->doDeleteArticle( "removing for test" );
+
+ // see if it now doesn't exist; reload
+ $title = Title::newFromText( $title->getText(), NS_FILE );
+ }
+
+ return !( $title && $title instanceof Title && $title->exists() );
+ }
+
+ /**
+ * Helper function -- remove files and associated articles with a particular filename
+ *
+ * @param string $fileName Filename to be removed
+ *
+ * @return bool
+ */
+ public function deleteFileByFileName( $fileName ) {
+ return $this->deleteFileByTitle( Title::newFromText( $fileName, NS_FILE ) );
+ }
+
+ /**
+ * Helper function -- given a file on the filesystem, find matching
+ * content in the db (and associated articles) and remove them.
+ *
+ * @param string $filePath Path to file on the filesystem
+ *
+ * @return bool
+ */
+ public function deleteFileByContent( $filePath ) {
+ $hash = FSFile::getSha1Base36FromPath( $filePath );
+ $dupes = RepoGroup::singleton()->findBySha1( $hash );
+ $success = true;
+ foreach ( $dupes as $dupe ) {
+ $success &= $this->deleteFileByTitle( $dupe->getTitle() );
+ }
+
+ return $success;
+ }
+
+ /**
+ * Fake an upload by dumping the file into temp space, and adding info to $_FILES.
+ * (This is what PHP would normally do).
+ *
+ * @param string $fieldName Name this would have in the upload form
+ * @param string $fileName Name to title this
+ * @param string $type MIME type
+ * @param string $filePath Path where to find file contents
+ *
+ * @throws Exception
+ * @return bool
+ */
+ function fakeUploadFile( $fieldName, $fileName, $type, $filePath ) {
+ $tmpName = $this->getNewTempFile();
+ if ( !file_exists( $filePath ) ) {
+ throw new Exception( "$filePath doesn't exist!" );
+ }
+
+ if ( !copy( $filePath, $tmpName ) ) {
+ throw new Exception( "couldn't copy $filePath to $tmpName" );
+ }
+
+ clearstatcache();
+ $size = filesize( $tmpName );
+ if ( $size === false ) {
+ throw new Exception( "couldn't stat $tmpName" );
+ }
+
+ $_FILES[$fieldName] = [
+ 'name' => $fileName,
+ 'type' => $type,
+ 'tmp_name' => $tmpName,
+ 'size' => $size,
+ 'error' => null
+ ];
+
+ return true;
+ }
+
+ function fakeUploadChunk( $fieldName, $fileName, $type, & $chunkData ) {
+ $tmpName = $this->getNewTempFile();
+ // copy the chunk data to temp location:
+ if ( !file_put_contents( $tmpName, $chunkData ) ) {
+ throw new Exception( "couldn't copy chunk data to $tmpName" );
+ }
+
+ clearstatcache();
+ $size = filesize( $tmpName );
+ if ( $size === false ) {
+ throw new Exception( "couldn't stat $tmpName" );
+ }
+
+ $_FILES[$fieldName] = [
+ 'name' => $fileName,
+ 'type' => $type,
+ 'tmp_name' => $tmpName,
+ 'size' => $size,
+ 'error' => null
+ ];
+ }
+
+ /**
+ * Remove traces of previous fake uploads
+ */
+ function clearFakeUploads() {
+ $_FILES = [];
+ }
+}
/**
* @param array $groupDefinition Group definition
* @param string $input Value in URL
- *
- * @dataProvider provideModifyQuery
*/
protected function modifyQueryHelper( $groupDefinition, $input ) {
$ctx = $this->createMock( IContextSource::class );
* @since 1.20
*
* @param callable $function
- *
- * @covers GenericArrayObject::getObjectType
*/
protected function checkTypeChecks( $function ) {
$excption = null;
* @since 1.20
*
* @param array $elements
- *
+ * @covers GenericArrayObject::getObjectType
* @covers GenericArrayObject::offsetSet
*/
public function testOffsetSet( array $elements ) {
* @covers IP::isIPAddress
* @dataProvider provideInvalidIPs
*/
- public function isNotIPAddress( $val, $desc ) {
+ public function testIsNotIPAddress( $val, $desc ) {
$this->assertFalse( IP::isIPAddress( $val ), $desc );
}
'leafo/lessphp' => [
'version' => '0.5.0',
'type' => 'library',
- 'licenses' => [ 'MIT', 'GPL-3.0' ],
+ 'licenses' => [ 'MIT', 'GPL-3.0-only' ],
'authors' => [
[
'name' => 'Leaf Corcoran',
'wikimedia/cdb' => [
'version' => '1.0.1',
'type' => 'library',
- 'licenses' => [ 'GPL-2.0' ],
+ 'licenses' => [ 'GPL-2.0-only' ],
'authors' => [
[
'name' => 'Tim Starling',
'leafo/lessphp' => [
'version' => '0.5.0',
'type' => 'library',
- 'licenses' => [ 'MIT', 'GPL-3.0' ],
+ 'licenses' => [ 'MIT', 'GPL-3.0-only' ],
'authors' => [
[
'name' => 'Leaf Corcoran',
'mediawiki/translate' => [
'version' => '2014.12',
'type' => 'mediawiki-extension',
- 'licenses' => [ 'GPL-2.0+' ],
+ 'licenses' => [ 'GPL-2.0-or-later' ],
'authors' => [
[
'name' => 'Niklas Laxström',
'mediawiki/universal-language-selector' => [
'version' => '2014.12',
'type' => 'mediawiki-extension',
- 'licenses' => [ 'GPL-2.0+', 'MIT' ],
+ 'licenses' => [ 'GPL-2.0-or-later', 'MIT' ],
'authors' => [],
'description' => 'The primary aim is to allow users to select a language ' .
'and configure its support in an easy way. ' .
* @covers WikiPage::newFromID
*/
public function testNewFromId_returnsNullOnNonExistingId() {
- $this->assertNull( WikiPage::newFromID( 73574757437437743743 ) );
+ $this->assertNull( WikiPage::newFromID( 2147483647 ) );
}
public function provideTestInsertProtectNullRevision() {
--- /dev/null
+'use strict';
+const merge = require( 'deepmerge' ),
+ username = 'Selenium user',
+ wdioConf = require( './wdio.conf.js' );
+
+// Overwrite default settings
+exports.config = merge( wdioConf.config, {
+ username: process.env.MEDIAWIKI_USER === undefined ?
+ username :
+ process.env.MEDIAWIKI_USER,
+ password: process.env.MEDIAWIKI_PASSWORD,
+ baseUrl: (
+ process.env.MW_SERVER === undefined ?
+ 'https://en.wikipedia.beta.wmflabs.org:443' :
+ process.env.MW_SERVER
+ ) + (
+ process.env.MW_SCRIPT_PATH === undefined ?
+ '/w' :
+ process.env.MW_SCRIPT_PATH
+ )
+} );