From 9441dde8bfb95277df073717ed7817dced40f948 Mon Sep 17 00:00:00 2001
From: Pierre Schmitz <pierre@archlinux.de>
Date: Fri, 28 Mar 2014 05:41:12 +0100
Subject: Update to MediaWiki 1.22.5

---
 tests/phpunit/includes/upload/UploadBaseTest.php   | 147 +++++++++
 .../phpunit/includes/upload/UploadFromUrlTest.php  | 350 +++++++++++++++++++++
 tests/phpunit/includes/upload/UploadStashTest.php  |  76 +++++
 3 files changed, 573 insertions(+)
 create mode 100644 tests/phpunit/includes/upload/UploadBaseTest.php
 create mode 100644 tests/phpunit/includes/upload/UploadFromUrlTest.php
 create mode 100644 tests/phpunit/includes/upload/UploadStashTest.php

(limited to 'tests/phpunit/includes/upload')

diff --git a/tests/phpunit/includes/upload/UploadBaseTest.php b/tests/phpunit/includes/upload/UploadBaseTest.php
new file mode 100644
index 00000000..982b46b2
--- /dev/null
+++ b/tests/phpunit/includes/upload/UploadBaseTest.php
@@ -0,0 +1,147 @@
+<?php
+
+/**
+ * @group Upload
+ */
+class UploadBaseTest extends MediaWikiTestCase {
+
+	/** @var UploadTestHandler */
+	protected $upload;
+
+	protected function setUp() {
+		global $wgHooks;
+		parent::setUp();
+
+		$this->upload = new UploadTestHandler;
+		$this->hooks = $wgHooks;
+		$wgHooks['InterwikiLoadPrefix'][] = function ( $prefix, &$data ) {
+			return false;
+		};
+	}
+
+	protected function tearDown() {
+		global $wgHooks;
+		$wgHooks = $this->hooks;
+
+		parent::tearDown();
+	}
+
+
+	/**
+	 * First checks the return code
+	 * of UploadBase::getTitle() and then the actual returned title
+	 *
+	 * @dataProvider provideTestTitleValidation
+	 * @covers UploadBase::getTitle
+	 */
+	public function testTitleValidation( $srcFilename, $dstFilename, $code, $msg ) {
+		/* Check the result code */
+		$this->assertEquals( $code,
+			$this->upload->testTitleValidation( $srcFilename ),
+			"$msg code" );
+
+		/* If we expect a valid title, check the title itself. */
+		if ( $code == UploadBase::OK ) {
+			$this->assertEquals( $dstFilename,
+				$this->upload->getTitle()->getText(),
+				"$msg text" );
+		}
+	}
+
+	/**
+	 * Test various forms of valid and invalid titles that can be supplied.
+	 */
+	public static function provideTestTitleValidation() {
+		return array(
+			/* Test a valid title */
+			array( 'ValidTitle.jpg', 'ValidTitle.jpg', UploadBase::OK,
+				'upload valid title' ),
+			/* A title with a slash */
+			array( 'A/B.jpg', 'B.jpg', UploadBase::OK,
+				'upload title with slash' ),
+			/* A title with illegal char */
+			array( 'A:B.jpg', 'A-B.jpg', UploadBase::OK,
+				'upload title with colon' ),
+			/* Stripping leading File: prefix */
+			array( 'File:C.jpg', 'C.jpg', UploadBase::OK,
+				'upload title with File prefix' ),
+			/* Test illegal suggested title (r94601) */
+			array( '%281%29.JPG', null, UploadBase::ILLEGAL_FILENAME,
+				'illegal title for upload' ),
+			/* A title without extension */
+			array( 'A', null, UploadBase::FILETYPE_MISSING,
+				'upload title without extension' ),
+			/* A title with no basename */
+			array( '.jpg', null, UploadBase::MIN_LENGTH_PARTNAME,
+				'upload title without basename' ),
+			/* A title that is longer than 255 bytes */
+			array( str_repeat( 'a', 255 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG,
+				'upload title longer than 255 bytes' ),
+			/* A title that is longer than 240 bytes */
+			array( str_repeat( 'a', 240 ) . '.jpg', null, UploadBase::FILENAME_TOO_LONG,
+				'upload title longer than 240 bytes' ),
+		);
+	}
+
+	/**
+	 * Test the upload verification functions
+	 * @covers UploadBase::verifyUpload
+	 */
+	public function testVerifyUpload() {
+		/* Setup with zero file size */
+		$this->upload->initializePathInfo( '', '', 0 );
+		$result = $this->upload->verifyUpload();
+		$this->assertEquals( UploadBase::EMPTY_FILE,
+			$result['status'],
+			'upload empty file' );
+	}
+
+	// Helper used to create an empty file of size $size.
+	private function createFileOfSize( $size ) {
+		$filename = tempnam( wfTempDir(), "mwuploadtest" );
+
+		$fh = fopen( $filename, 'w' );
+		ftruncate( $fh, $size );
+		fclose( $fh );
+
+		return $filename;
+	}
+
+	/**
+	 * test uploading a 100 bytes file with $wgMaxUploadSize = 100
+	 *
+	 * This method should be abstracted so we can test different settings.
+	 */
+	public function testMaxUploadSize() {
+		global $wgMaxUploadSize;
+		$savedGlobal = $wgMaxUploadSize; // save global
+		global $wgFileExtensions;
+		$wgFileExtensions[] = 'txt';
+
+		$wgMaxUploadSize = 100;
+
+		$filename = $this->createFileOfSize( $wgMaxUploadSize );
+		$this->upload->initializePathInfo( basename( $filename ) . '.txt', $filename, 100 );
+		$result = $this->upload->verifyUpload();
+		unlink( $filename );
+
+		$this->assertEquals(
+			array( 'status' => UploadBase::OK ), $result );
+
+		$wgMaxUploadSize = $savedGlobal; // restore global
+	}
+}
+
+class UploadTestHandler extends UploadBase {
+	public function initializeFromRequest( &$request ) {
+	}
+
+	public function testTitleValidation( $name ) {
+		$this->mTitle = false;
+		$this->mDesiredDestName = $name;
+		$this->mTitleError = UploadBase::OK;
+		$this->getTitle();
+
+		return $this->mTitleError;
+	}
+}
diff --git a/tests/phpunit/includes/upload/UploadFromUrlTest.php b/tests/phpunit/includes/upload/UploadFromUrlTest.php
new file mode 100644
index 00000000..a75fba69
--- /dev/null
+++ b/tests/phpunit/includes/upload/UploadFromUrlTest.php
@@ -0,0 +1,350 @@
+<?php
+
+/**
+ * @group Broken
+ * @group Upload
+ * @group Database
+ */
+class UploadFromUrlTest extends ApiTestCase {
+	protected function setUp() {
+		parent::setUp();
+
+		$this->setMwGlobals( array(
+			'wgEnableUploads' => true,
+			'wgAllowCopyUploads' => true,
+			'wgAllowAsyncCopyUploads' => true,
+		) );
+		wfSetupSession();
+
+		if ( wfLocalFile( 'UploadFromUrlTest.png' )->exists() ) {
+			$this->deleteFile( 'UploadFromUrlTest.png' );
+		}
+	}
+
+	protected function doApiRequest( array $params, array $unused = null, $appendModule = false, User $user = null ) {
+		$sessionId = session_id();
+		session_write_close();
+
+		$req = new FauxRequest( $params, true, $_SESSION );
+		$module = new ApiMain( $req, true );
+		$module->execute();
+
+		wfSetupSession( $sessionId );
+
+		return array( $module->getResultData(), $req );
+	}
+
+	/**
+	 * Ensure that the job queue is empty before continuing
+	 */
+	public function testClearQueue() {
+		$job = JobQueueGroup::singleton()->pop();
+		while ( $job ) {
+			$job = JobQueueGroup::singleton()->pop();
+		}
+		$this->assertFalse( $job );
+	}
+
+	/**
+	 * @todo Document why we test login, since the $wgUser hack used doesn't
+	 * require login
+	 */
+	public function testLogin() {
+		$data = $this->doApiRequest( array(
+			'action' => 'login',
+			'lgname' => $this->user->userName,
+			'lgpassword' => $this->user->passWord ) );
+		$this->assertArrayHasKey( "login", $data[0] );
+		$this->assertArrayHasKey( "result", $data[0]['login'] );
+		$this->assertEquals( "NeedToken", $data[0]['login']['result'] );
+		$token = $data[0]['login']['token'];
+
+		$data = $this->doApiRequest( array(
+			'action' => 'login',
+			"lgtoken" => $token,
+			'lgname' => $this->user->userName,
+			'lgpassword' => $this->user->passWord ) );
+
+		$this->assertArrayHasKey( "login", $data[0] );
+		$this->assertArrayHasKey( "result", $data[0]['login'] );
+		$this->assertEquals( "Success", $data[0]['login']['result'] );
+		$this->assertArrayHasKey( 'lgtoken', $data[0]['login'] );
+
+		return $data;
+	}
+
+	/**
+	 * @depends testLogin
+	 * @depends testClearQueue
+	 */
+	public function testSetupUrlDownload( $data ) {
+		$token = $this->user->getEditToken();
+		$exception = false;
+
+		try {
+			$this->doApiRequest( array(
+				'action' => 'upload',
+			) );
+		} catch ( UsageException $e ) {
+			$exception = true;
+			$this->assertEquals( "The token parameter must be set", $e->getMessage() );
+		}
+		$this->assertTrue( $exception, "Got exception" );
+
+		$exception = false;
+		try {
+			$this->doApiRequest( array(
+				'action' => 'upload',
+				'token' => $token,
+			), $data );
+		} catch ( UsageException $e ) {
+			$exception = true;
+			$this->assertEquals( "One of the parameters sessionkey, file, url, statuskey is required",
+				$e->getMessage() );
+		}
+		$this->assertTrue( $exception, "Got exception" );
+
+		$exception = false;
+		try {
+			$this->doApiRequest( array(
+				'action' => 'upload',
+				'url' => 'http://www.example.com/test.png',
+				'token' => $token,
+			), $data );
+		} catch ( UsageException $e ) {
+			$exception = true;
+			$this->assertEquals( "The filename parameter must be set", $e->getMessage() );
+		}
+		$this->assertTrue( $exception, "Got exception" );
+
+		$this->user->removeGroup( 'sysop' );
+		$exception = false;
+		try {
+			$this->doApiRequest( array(
+				'action' => 'upload',
+				'url' => 'http://www.example.com/test.png',
+				'filename' => 'UploadFromUrlTest.png',
+				'token' => $token,
+			), $data );
+		} catch ( UsageException $e ) {
+			$exception = true;
+			$this->assertEquals( "Permission denied", $e->getMessage() );
+		}
+		$this->assertTrue( $exception, "Got exception" );
+
+		$this->user->addGroup( 'sysop' );
+		$data = $this->doApiRequest( array(
+			'action' => 'upload',
+			'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png',
+			'asyncdownload' => 1,
+			'filename' => 'UploadFromUrlTest.png',
+			'token' => $token,
+		), $data );
+
+		$this->assertEquals( $data[0]['upload']['result'], 'Queued', 'Queued upload' );
+
+		$job = JobQueueGroup::singleton()->pop();
+		$this->assertThat( $job, $this->isInstanceOf( 'UploadFromUrlJob' ), 'Queued upload inserted' );
+	}
+
+	/**
+	 * @depends testLogin
+	 * @depends testClearQueue
+	 */
+	public function testAsyncUpload( $data ) {
+		$token = $this->user->getEditToken();
+
+		$this->user->addGroup( 'users' );
+
+		$data = $this->doAsyncUpload( $token, true );
+		$this->assertEquals( $data[0]['upload']['result'], 'Success' );
+		$this->assertEquals( $data[0]['upload']['filename'], 'UploadFromUrlTest.png' );
+		$this->assertTrue( wfLocalFile( $data[0]['upload']['filename'] )->exists() );
+
+		$this->deleteFile( 'UploadFromUrlTest.png' );
+
+		return $data;
+	}
+
+	/**
+	 * @depends testLogin
+	 * @depends testClearQueue
+	 */
+	public function testAsyncUploadWarning( $data ) {
+		$token = $this->user->getEditToken();
+
+		$this->user->addGroup( 'users' );
+
+		$data = $this->doAsyncUpload( $token );
+
+		$this->assertEquals( $data[0]['upload']['result'], 'Warning' );
+		$this->assertTrue( isset( $data[0]['upload']['sessionkey'] ) );
+
+		$data = $this->doApiRequest( array(
+			'action' => 'upload',
+			'sessionkey' => $data[0]['upload']['sessionkey'],
+			'filename' => 'UploadFromUrlTest.png',
+			'ignorewarnings' => 1,
+			'token' => $token,
+		) );
+		$this->assertEquals( $data[0]['upload']['result'], 'Success' );
+		$this->assertEquals( $data[0]['upload']['filename'], 'UploadFromUrlTest.png' );
+		$this->assertTrue( wfLocalFile( $data[0]['upload']['filename'] )->exists() );
+
+		$this->deleteFile( 'UploadFromUrlTest.png' );
+
+		return $data;
+	}
+
+	/**
+	 * @depends testLogin
+	 * @depends testClearQueue
+	 */
+	public function testSyncDownload( $data ) {
+		$token = $this->user->getEditToken();
+
+		$job = JobQueueGroup::singleton()->pop();
+		$this->assertFalse( $job, 'Starting with an empty jobqueue' );
+
+		$this->user->addGroup( 'users' );
+		$data = $this->doApiRequest( array(
+			'action' => 'upload',
+			'filename' => 'UploadFromUrlTest.png',
+			'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png',
+			'ignorewarnings' => true,
+			'token' => $token,
+		), $data );
+
+		$job = JobQueueGroup::singleton()->pop();
+		$this->assertFalse( $job );
+
+		$this->assertEquals( 'Success', $data[0]['upload']['result'] );
+		$this->deleteFile( 'UploadFromUrlTest.png' );
+
+		return $data;
+	}
+
+	public function testLeaveMessage() {
+		$token = $this->user->user->getEditToken();
+
+		$talk = $this->user->user->getTalkPage();
+		if ( $talk->exists() ) {
+			$page = WikiPage::factory( $talk );
+			$page->doDeleteArticle( '' );
+		}
+
+		$this->assertFalse( (bool)$talk->getArticleID( Title::GAID_FOR_UPDATE ), 'User talk does not exist' );
+
+		$this->doApiRequest( array(
+			'action' => 'upload',
+			'filename' => 'UploadFromUrlTest.png',
+			'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png',
+			'asyncdownload' => 1,
+			'token' => $token,
+			'leavemessage' => 1,
+			'ignorewarnings' => 1,
+		) );
+
+		$job = JobQueueGroup::singleton()->pop();
+		$this->assertEquals( 'UploadFromUrlJob', get_class( $job ) );
+		$job->run();
+
+		$this->assertTrue( wfLocalFile( 'UploadFromUrlTest.png' )->exists() );
+		$this->assertTrue( (bool)$talk->getArticleID( Title::GAID_FOR_UPDATE ), 'User talk exists' );
+
+		$this->deleteFile( 'UploadFromUrlTest.png' );
+
+		$talkRev = Revision::newFromTitle( $talk );
+		$talkSize = $talkRev->getSize();
+
+		$exception = false;
+		try {
+			$this->doApiRequest( array(
+				'action' => 'upload',
+				'filename' => 'UploadFromUrlTest.png',
+				'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png',
+				'asyncdownload' => 1,
+				'token' => $token,
+				'leavemessage' => 1,
+			) );
+		} catch ( UsageException $e ) {
+			$exception = true;
+			$this->assertEquals( 'Using leavemessage without ignorewarnings is not supported', $e->getMessage() );
+		}
+		$this->assertTrue( $exception );
+
+		$job = JobQueueGroup::singleton()->pop();
+		$this->assertFalse( $job );
+
+		return;
+		/*
+		// Broken until using leavemessage with ignorewarnings is supported
+		$job->run();
+
+		$this->assertFalse( wfLocalFile( 'UploadFromUrlTest.png' )->exists() );
+
+		$talkRev = Revision::newFromTitle( $talk );
+		$this->assertTrue( $talkRev->getSize() > $talkSize, 'New message left' );
+		*/
+	}
+
+	/**
+	 * Helper function to perform an async upload, execute the job and fetch
+	 * the status
+	 *
+	 * @return array The result of action=upload&statuskey=key
+	 */
+	private function doAsyncUpload( $token, $ignoreWarnings = false, $leaveMessage = false ) {
+		$params = array(
+			'action' => 'upload',
+			'filename' => 'UploadFromUrlTest.png',
+			'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png',
+			'asyncdownload' => 1,
+			'token' => $token,
+		);
+		if ( $ignoreWarnings ) {
+			$params['ignorewarnings'] = 1;
+		}
+		if ( $leaveMessage ) {
+			$params['leavemessage'] = 1;
+		}
+
+		$data = $this->doApiRequest( $params );
+		$this->assertEquals( $data[0]['upload']['result'], 'Queued' );
+		$this->assertTrue( isset( $data[0]['upload']['statuskey'] ) );
+		$statusKey = $data[0]['upload']['statuskey'];
+
+		$job = JobQueueGroup::singleton()->pop();
+		$this->assertEquals( 'UploadFromUrlJob', get_class( $job ) );
+
+		$status = $job->run();
+		$this->assertTrue( $status );
+
+		$data = $this->doApiRequest( array(
+			'action' => 'upload',
+			'statuskey' => $statusKey,
+			'token' => $token,
+		) );
+
+		return $data;
+	}
+
+	/**
+	 *
+	 */
+	protected function deleteFile( $name ) {
+		$t = Title::newFromText( $name, NS_FILE );
+		$this->assertTrue( $t->exists(), "File '$name' exists" );
+
+		if ( $t->exists() ) {
+			$file = wfFindFile( $name, array( 'ignoreRedirect' => true ) );
+			$empty = "";
+			FileDeleteForm::doDelete( $t, $file, $empty, "none", true );
+			$page = WikiPage::factory( $t );
+			$page->doDeleteArticle( "testing" );
+		}
+		$t = Title::newFromText( $name, NS_FILE );
+
+		$this->assertFalse( $t->exists(), "File '$name' was deleted" );
+	}
+}
diff --git a/tests/phpunit/includes/upload/UploadStashTest.php b/tests/phpunit/includes/upload/UploadStashTest.php
new file mode 100644
index 00000000..7a0fea48
--- /dev/null
+++ b/tests/phpunit/includes/upload/UploadStashTest.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @group Database
+ */
+class UploadStashTest extends MediaWikiTestCase {
+	/**
+	 * @var Array of UploadStashTestUser
+	 */
+	public static $users;
+
+	protected function setUp() {
+		parent::setUp();
+
+		// Setup a file for bug 29408
+		$this->bug29408File = __DIR__ . '/bug29408';
+		file_put_contents( $this->bug29408File, "\x00" );
+
+		self::$users = array(
+			'sysop' => new TestUser(
+				'Uploadstashtestsysop',
+				'Upload Stash Test Sysop',
+				'upload_stash_test_sysop@example.com',
+				array( 'sysop' )
+			),
+			'uploader' => new TestUser(
+				'Uploadstashtestuser',
+				'Upload Stash Test User',
+				'upload_stash_test_user@example.com',
+				array()
+			)
+		);
+	}
+
+	protected function tearDown() {
+		if ( file_exists( $this->bug29408File . "." ) ) {
+			unlink( $this->bug29408File . "." );
+		}
+
+		if ( file_exists( $this->bug29408File ) ) {
+			unlink( $this->bug29408File );
+		}
+
+		parent::tearDown();
+	}
+
+	public function testBug29408() {
+		$this->setMwGlobals( 'wgUser', self::$users['uploader']->user );
+
+		$repo = RepoGroup::singleton()->getLocalRepo();
+		$stash = new UploadStash( $repo );
+
+		// Throws exception caught by PHPUnit on failure
+		$file = $stash->stashFile( $this->bug29408File );
+		// We'll never reach this point if we hit bug 29408
+		$this->assertTrue( true, 'Unrecognized file without extension' );
+
+		$stash->removeFile( $file->getFileKey() );
+	}
+
+	public function testValidRequest() {
+		$request = new FauxRequest( array( 'wpFileKey' => 'foo' ) );
+		$this->assertFalse( UploadFromStash::isValidRequest( $request ), 'Check failure on bad wpFileKey' );
+
+		$request = new FauxRequest( array( 'wpSessionKey' => 'foo' ) );
+		$this->assertFalse( UploadFromStash::isValidRequest( $request ), 'Check failure on bad wpSessionKey' );
+
+		$request = new FauxRequest( array( 'wpFileKey' => 'testkey-test.test' ) );
+		$this->assertTrue( UploadFromStash::isValidRequest( $request ), 'Check good wpFileKey' );
+
+		$request = new FauxRequest( array( 'wpFileKey' => 'testkey-test.test' ) );
+		$this->assertTrue( UploadFromStash::isValidRequest( $request ), 'Check good wpSessionKey' );
+
+		$request = new FauxRequest( array( 'wpFileKey' => 'testkey-test.test', 'wpSessionKey' => 'foo' ) );
+		$this->assertTrue( UploadFromStash::isValidRequest( $request ), 'Check key precedence' );
+	}
+}
-- 
cgit v1.2.3-54-g00ecf