From 04b2413aacfd5fef9d17f7ffd5ef6597436b440e Mon Sep 17 00:00:00 2001 From: "Mark A. Hershberger" Date: Thu, 25 Feb 2010 04:37:21 +0000 Subject: [PATCH] * Make tests work better together. Tests are now skipped or marked incomplete. * Make it possible to call deleteArchived{Revisions,Files} from within tests to do cleanup. --- maintenance/deleteArchivedFiles.inc | 62 +++++++++++ maintenance/deleteArchivedFiles.php | 42 +------ maintenance/deleteArchivedRevisions.inc | 49 ++++++++ maintenance/deleteArchivedRevisions.php | 27 ++--- maintenance/tests/ApiTest.php | 18 ++- maintenance/tests/MediaWikiParserTest.php | 37 +++++-- maintenance/tests/SearchMySQLTest.php | 3 + maintenance/tests/UploadFromChunksTest.php | 123 ++++++++++++--------- maintenance/tests/phpunit.xml | 13 +++ 9 files changed, 246 insertions(+), 128 deletions(-) create mode 100644 maintenance/deleteArchivedFiles.inc create mode 100644 maintenance/deleteArchivedRevisions.inc diff --git a/maintenance/deleteArchivedFiles.inc b/maintenance/deleteArchivedFiles.inc new file mode 100644 index 0000000000..efe969fe89 --- /dev/null +++ b/maintenance/deleteArchivedFiles.inc @@ -0,0 +1,62 @@ +begin(); + $tbl_arch = $dbw->tableName( 'filearchive' ); + $repo = RepoGroup::singleton()->getLocalRepo(); + # Get "active" revisions from the filearchive table + $output->handleOutput( "Searching for and deleting archived files...\n" ); + $res = $dbw->query( "SELECT fa_id,fa_storage_group,fa_storage_key FROM $tbl_arch" ); + $count = 0; + foreach( $res as $row ) { + $key = $row->fa_storage_key; + $group = $row->fa_storage_group; + $id = $row->fa_id; + $path = $repo->getZonePath( 'deleted' ).'/'.$repo->getDeletedHashPath($key).$key; + $sha1 = substr( $key, 0, strcspn( $key, '.' ) ); + // Check if the file is used anywhere... + $inuse = $dbw->selectField( 'oldimage', '1', + array( 'oi_sha1' => $sha1, + 'oi_deleted & '.File::DELETED_FILE => File::DELETED_FILE ), + __METHOD__, + array( 'FOR UPDATE' ) + ); + if ( $path && file_exists($path) && !$inuse ) { + unlink($path); // delete + $count++; + $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" ); + } else { + $output->handleOutput( "Notice - file '$key' not found in group '$group'\n" ); + if ( $force ) { + $outpu->handleOutput( "Got --force, deleting DB entry\n" ); + $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" ); + } + } + } + $dbw->commit(); + $output->handleOutput( "Done! [$count file(s)]\n" ); + } +} \ No newline at end of file diff --git a/maintenance/deleteArchivedFiles.php b/maintenance/deleteArchivedFiles.php index af4bbb7483..36046c56b6 100644 --- a/maintenance/deleteArchivedFiles.php +++ b/maintenance/deleteArchivedFiles.php @@ -24,6 +24,7 @@ */ require_once( dirname(__FILE__) . '/Maintenance.php' ); +require_once( dirname(__FILE__) . '/deleteArchivedFiles.inc' ); class DeleteArchivedFiles extends Maintenance { public function __construct() { @@ -33,48 +34,17 @@ class DeleteArchivedFiles extends Maintenance { $this->addOption( 'force', 'Force deletion of rows from filearchive' ); } + public function handleOutput($str) { + return $this->output($str); + } + public function execute() { if( !$this->hasOption('delete') ) { $this->output( "Use --delete to actually confirm this script\n" ); return; } $force = $this->hasOption( 'force' ); - # Data should come off the master, wrapped in a transaction - $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); - $tbl_arch = $dbw->tableName( 'filearchive' ); - $repo = RepoGroup::singleton()->getLocalRepo(); - # Get "active" revisions from the filearchive table - $this->output( "Searching for and deleting archived files...\n" ); - $res = $dbw->query( "SELECT fa_id,fa_storage_group,fa_storage_key FROM $tbl_arch" ); - $count = 0; - foreach( $res as $row ) { - $key = $row->fa_storage_key; - $group = $row->fa_storage_group; - $id = $row->fa_id; - $path = $repo->getZonePath( 'deleted' ).'/'.$repo->getDeletedHashPath($key).$key; - $sha1 = substr( $key, 0, strcspn( $key, '.' ) ); - // Check if the file is used anywhere... - $inuse = $dbw->selectField( 'oldimage', '1', - array( 'oi_sha1' => $sha1, - 'oi_deleted & '.File::DELETED_FILE => File::DELETED_FILE ), - __METHOD__, - array( 'FOR UPDATE' ) - ); - if ( $path && file_exists($path) && !$inuse ) { - unlink($path); // delete - $count++; - $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" ); - } else { - $this->output( "Notice - file '$key' not found in group '$group'\n" ); - if ( $force ) { - $this->output( "Got --force, deleting DB entry\n" ); - $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" ); - } - } - } - $dbw->commit(); - $this->output( "Done! [$count file(s)]\n" ); + DeleteArchivedFilesImplementation::doDelete($this, $force); } } diff --git a/maintenance/deleteArchivedRevisions.inc b/maintenance/deleteArchivedRevisions.inc new file mode 100644 index 0000000000..36e05fe926 --- /dev/null +++ b/maintenance/deleteArchivedRevisions.inc @@ -0,0 +1,49 @@ +begin(); + + $tbl_arch = $dbw->tableName( 'archive' ); + + # Delete as appropriate + $output->handleOutput( "Deleting archived revisions... " ); + $dbw->query( "TRUNCATE TABLE $tbl_arch" ); + + $count = $dbw->affectedRows(); + $deletedRows = $count != 0; + + $output->handleOutput( "done. $count revisions deleted.\n" ); + + # This bit's done + # Purge redundant text records + $dbw->commit(); + if( $deletedRows ) { + $output->purgeRedundantText( true ); + } + } +} \ No newline at end of file diff --git a/maintenance/deleteArchivedRevisions.php b/maintenance/deleteArchivedRevisions.php index c3f8bf11e1..2d24001e34 100644 --- a/maintenance/deleteArchivedRevisions.php +++ b/maintenance/deleteArchivedRevisions.php @@ -24,6 +24,7 @@ */ require_once( dirname(__FILE__) . '/Maintenance.php' ); +require_once( dirname(__FILE__) . '/deleteArchivedRevisions.inc' ); class DeleteArchivedRevisions extends Maintenance { public function __construct() { @@ -32,31 +33,17 @@ class DeleteArchivedRevisions extends Maintenance { $this->addOption( 'delete', 'Performs the deletion' ); } + public function handleOutput($str) { + $this->output($str); + } + public function execute() { $this->output( "Delete archived revisions\n\n" ); # Data should come off the master, wrapped in a transaction - $dbw = wfGetDB( DB_MASTER ); if( $this->hasOption('delete') ) { - $dbw->begin(); - - $tbl_arch = $dbw->tableName( 'archive' ); - - # Delete as appropriate - $this->output( "Deleting archived revisions... " ); - $dbw->query( "TRUNCATE TABLE $tbl_arch" ); - - $count = $dbw->affectedRows(); - $deletedRows = $count != 0; - - $this->output( "done. $count revisions deleted.\n" ); - - # This bit's done - # Purge redundant text records - $dbw->commit(); - if( $deletedRows ) { - $this->purgeRedundantText( true ); - } + DeleteArchivedRevisionsImplementation::doDelete($this); } else { + $dbw = wfGetDB( DB_MASTER ); $res = $dbw->selectRow( 'archive', 'COUNT(*) as count', array(), __FUNCTION__ ); $this->output( "Found {$res->count} revisions to delete.\n" ); $this->output( "Please run the script again with the --delete option to really delete the revisions.\n" ); diff --git a/maintenance/tests/ApiTest.php b/maintenance/tests/ApiTest.php index dcdb8db66a..2dbe55c671 100644 --- a/maintenance/tests/ApiTest.php +++ b/maintenance/tests/ApiTest.php @@ -57,8 +57,9 @@ class ApiTest extends ApiSetup { } function testApi() { - global $wgServerName, $wgServer; + global $wgServerName, $wgServer, $wgDBprefix; + if($wgDBprefix === "parsertest_") $this->markTestSkipped("This test can't (yet?) be run with the parser tests"); if(!isset($wgServerName) || !isset($wgServer)) { $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '. 'be set in LocalSettings.php'); @@ -73,8 +74,9 @@ class ApiTest extends ApiSetup { } function testApiLoginNoName() { - global $wgServerName, $wgServer; + global $wgServerName, $wgServer, $wgDBprefix; + if($wgDBprefix === "parsertest_") $this->markTestSkipped("This test can't (yet?) be run with the parser tests"); if(!isset($wgServerName) || !isset($wgServer)) { $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '. 'be set in LocalSettings.php'); @@ -92,8 +94,9 @@ class ApiTest extends ApiSetup { } function testApiLoginBadPass() { - global $wgServerName, $wgServer; + global $wgServerName, $wgServer, $wgDBprefix; + if($wgDBprefix === "parsertest_") $this->markTestSkipped("This test can't (yet?) be run with the parser tests"); if(!isset($wgServerName) || !isset($wgServer)) { $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '. 'be set in LocalSettings.php'); @@ -111,8 +114,9 @@ class ApiTest extends ApiSetup { } function testApiLoginGoodPass() { - global $wgServerName, $wgServer; + global $wgServerName, $wgServer, $wgDBprefix; + if($wgDBprefix === "parsertest_") $this->markTestSkipped("This test can't (yet?) be run with the parser tests"); if(!isset($wgServerName) || !isset($wgServer)) { $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '. 'be set in LocalSettings.php'); @@ -130,8 +134,9 @@ class ApiTest extends ApiSetup { } function testApiGotCookie() { - global $wgServerName, $wgServer, $wgScriptPath; + global $wgServerName, $wgServer, $wgScriptPath, $wgDBprefix; + if($wgDBprefix === "parsertest_") $this->markTestSkipped("This test can't (yet?) be run with the parser tests"); if(!isset($wgServerName) || !isset($wgServer)) { $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '. 'be set in LocalSettings.php'); @@ -154,8 +159,9 @@ class ApiTest extends ApiSetup { */ function testApiListPages(CookieJar $cj) { $this->markTestIncomplete("Not done with this yet"); - global $wgServerName, $wgServer; + global $wgServerName, $wgServer, $wgDBprefix; + if($wgDBprefix === "parsertest_") $this->markTestSkipped("This test can't (yet?) be run with the parser tests"); if($wgServerName == "localhost" || $wgServer == "http://localhost") { $this->markTestIncomplete('This test needs $wgServerName and $wgServer to '. 'be set in LocalSettings.php'); diff --git a/maintenance/tests/MediaWikiParserTest.php b/maintenance/tests/MediaWikiParserTest.php index aebe019428..b8154ed4a4 100644 --- a/maintenance/tests/MediaWikiParserTest.php +++ b/maintenance/tests/MediaWikiParserTest.php @@ -18,14 +18,23 @@ class PHPUnitTestRecorder extends TestRecorder { } class MediaWikiParserTestSuite extends PHPUnit_Framework_TestSuite { -#implements PHPUnit_Framework_SelfDescribing { static private $count; static public $parser; static public $iter; + public static function addTables(&$tables) { + $tables[] = 'user_properties'; + $tables[] = 'filearchive'; + $tables[] = 'logging'; + return true; + } + public static function suite() { $suite = new PHPUnit_Framework_TestSuite(); + global $wgHooks; + $wgHooks['ParserTestTables'][] = "MediaWikiParserTestSuite::addTables"; + self::$iter = new TestFileIterator( PARSER_TESTS ); foreach(self::$iter as $i => $test) { @@ -57,12 +66,12 @@ class MediaWikiParserTestSuite extends PHPUnit_Framework_TestSuite { $wgLocalFileRepo = array( 'class' => 'LocalRepo', 'name' => 'local', - 'directory' => '', + 'directory' => 'test-repo', 'url' => 'http://example.com/images', 'hashLevels' => 2, 'transformVia404' => false, ); - $wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface'; + $wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface'; $wgNamespaceAliases['Image'] = NS_FILE; $wgNamespaceAliases['Image_talk'] = NS_FILE_TALK; @@ -88,12 +97,12 @@ class MediaWikiParserTestSuite extends PHPUnit_Framework_TestSuite { return $suite; } - public function tearDown() { - $this->teardownDatabase(); - $this->recorder->report(); - $this->recorder->end(); - $this->teardownUploadDir($this->uploadDir); - } + /* public function tearDown() { */ + /* $this->teardownDatabase(); */ + /* $this->recorder->report(); */ + /* $this->recorder->end(); */ + /* $this->teardownUploadDir($this->uploadDir); */ + /* } */ public function count() {return self::$count;} @@ -102,7 +111,6 @@ class MediaWikiParserTestSuite extends PHPUnit_Framework_TestSuite { } - private $db; private $uploadDir; private $keepUploads; /** @@ -198,11 +206,18 @@ class MediaWikiParserTestSuite extends PHPUnit_Framework_TestSuite { } } +/** + * @group Stub + */ class ParserUnitTest extends PHPUnit_Framework_TestCase { private $number = 0; private $test = ""; - public function __construct($number, $test) { + public function testBogus() { + $this->markTestSkipped("This is a stub"); + } + + public function __construct($number = null, $test = null) { $this->number = $number; $this->test = $test; } diff --git a/maintenance/tests/SearchMySQLTest.php b/maintenance/tests/SearchMySQLTest.php index 526f621635..ee5de0b84a 100644 --- a/maintenance/tests/SearchMySQLTest.php +++ b/maintenance/tests/SearchMySQLTest.php @@ -5,6 +5,9 @@ class SearchMySQLTest extends SearchEngineTest { var $db; function setUp() { + global $wgDBprefix; + if($wgDBprefix === "parsertest_") $this->markTestSkipped("This test can't (yet?) be run with the parser tests"); + $GLOBALS['wgContLang'] = new Language; $this->db = $this->buildTestDatabase( array( 'page', 'revision', 'text', 'searchindex', 'user' ) ); diff --git a/maintenance/tests/UploadFromChunksTest.php b/maintenance/tests/UploadFromChunksTest.php index e72fa68b71..bda9dedd78 100644 --- a/maintenance/tests/UploadFromChunksTest.php +++ b/maintenance/tests/UploadFromChunksTest.php @@ -1,6 +1,10 @@ 'LocalRepo', + 'name' => 'local', + 'directory' => 'test-repo', + 'url' => 'http://example.com/images', + 'hashLevels' => 2, + 'transformVia404' => false, + ); ini_set( 'file_loads', 1 ); ini_set( 'log_errors', 1 ); @@ -64,6 +76,7 @@ class UploadFromChunksTest extends ApiSetup { 'action' => 'login', 'lgname' => self::$userName, 'lgpassword' => self::$passWord ) ); + $this->assertArrayHasKey( "login", $data[0] ); $this->assertArrayHasKey( "result", $data[0]['login'] ); $this->assertEquals( "Success", $data[0]['login']['result'] ); @@ -202,15 +215,35 @@ class UploadFromChunksTest extends ApiSetup { /** * @depends testLogin */ - function testUploadChunkDoneDuplicate( $data ) { + function testUploadChunkDoneGood( $data ) { global $wgUser, $wgVerifyMimeType; - $wgVerifyMimeType = false; + + DeleteArchivedFilesImplementation::doDelete(new nullClass, true); + DeleteArchivedRevisionsImplementation::doDelete(new nullClass); + + $id = Title::newFromText( "Twar.png", NS_FILE )->getArticleID(); + $oldFile = Article::newFromID( $id ); + if ( $oldFile ) { + $oldFile->doDeleteArticle(); + $oldFile->doPurge(); + } + + $oldFile = wfFindFile( "Twar.png" ); + if ( $oldFile ) { + $oldFile->delete(); + } + $id = Title::newFromText( "Twar.png", NS_FILE )->getArticleID(); + $this->assertEquals(0, $id); + + $oldFile = Article::newFromID( $id ); + $this->assertEquals(null, $oldFile); + $wgUser = User::newFromName( self::$userName ); $data[2]['wsEditToken'] = $data[2]['wsToken']; $token = md5( $data[2]['wsToken'] ) . EDIT_TOKEN_SUFFIX; $data = $this->doApiRequest( array( - 'filename' => 'tmp.png', + 'filename' => 'twar.png', 'action' => 'upload', 'enablechunks' => true, 'token' => $token ), $data ); @@ -218,7 +251,7 @@ class UploadFromChunksTest extends ApiSetup { $url = $data[0]['uploadUrl']; $params = wfCgiToArray( substr( $url, strpos( $url, "?" ) ) ); $size = 0; - for ( $i = 0; $i < 4; $i++ ) { + for ( $i = 0; $i < 5; $i++ ) { $this->makeChunk( "123" ); $size += $_FILES['chunk']['size']; @@ -234,41 +267,29 @@ class UploadFromChunksTest extends ApiSetup { $params['done'] = true; - $this->makeChunk( "123" ); + $this->makeChunk( "456" ); $data = $this->doApiRequest( $params, $data ); - $this->cleanChunk(); - $this->assertArrayHasKey( 'upload', $data[0] ); - $this->assertArrayHasKey( 'result', $data[0]['upload'] ); - $this->assertEquals( 'Warning', $data[0]['upload']['result'] ); + $this->cleanChunk(); + $this->assertArrayHasKey( 'result', $data[0] ); + $this->assertEquals( 1, $data[0]['result'] ); - $this->assertArrayHasKey( 'warnings', $data[0]['upload'] ); - $this->assertArrayHasKey( 'exists', - $data[0]['upload']['warnings'] ); - $this->assertEquals( 'Tmp.png', - $data[0]['upload']['warnings']['exists'] ); + $this->assertArrayHasKey( 'done', $data[0] ); + $this->assertEquals( 1, $data[0]['done'] ); + $this->assertArrayHasKey( 'resultUrl', $data[0] ); + $this->assertRegExp( '/File:Twar.png/', $data[0]['resultUrl'] ); } /** * @depends testLogin */ - function testUploadChunkDoneGood( $data ) { + function testUploadChunkDoneDuplicate( $data ) { global $wgUser, $wgVerifyMimeType; - $wgVerifyMimeType = false; - - $id = Title::newFromText( "Twar.png", NS_FILE )->getArticleID(); - $oldFile = Article::newFromID( $id ); - if ( $oldFile ) { - $oldFile->doDeleteArticle(); - $oldFile->doPurge(); - } - $oldFile = wfFindFile( "Twar.png" ); - if ( $oldFile ) { - $oldFile->delete(); - } + $this->markTestIncomplete("Not working yet"); + $wgVerifyMimeType = false; $wgUser = User::newFromName( self::$userName ); $data[2]['wsEditToken'] = $data[2]['wsToken']; $token = md5( $data[2]['wsToken'] ) . EDIT_TOKEN_SUFFIX; @@ -281,38 +302,30 @@ class UploadFromChunksTest extends ApiSetup { $url = $data[0]['uploadUrl']; $params = wfCgiToArray( substr( $url, strpos( $url, "?" ) ) ); $size = 0; - for ( $i = 0; $i < 5; $i++ ) { + $gotException = false; + for ( $i = 0; $i < 30; $i++ ) { $this->makeChunk( "123" ); $size += $_FILES['chunk']['size']; - - $data = $this->doApiRequest( $params, $data ); - $this->assertArrayHasKey( "result", $data[0] ); - $this->assertTrue( (bool)$data[0]["result"] ); - - $this->assertArrayHasKey( "filesize", $data[0] ); - $this->assertEquals( $size, $data[0]['filesize'] ); - - $this->cleanChunk(); + try { + $data = $this->doApiRequest( $params, $data ); + } catch (UsageException $e) { + $arr = $e->getMessageArray(); + $this->assertArrayHasKey( "code", $arr ); + $this->assertEquals( "internal-error", $arr['code'] ); + + $this->assertEquals( "fileexistserror", $arr[0][0] ); + $gotException = true; + } } - - $params['done'] = true; - - $this->makeChunk( "456" ); - $data = $this->doApiRequest( $params, $data ); - $this->cleanChunk(); + $this->assertTrue($gotException); + } - if ( isset( $data[0]['upload'] ) ) { - $this->markTestSkipped( "Please run 'php maintenance/deleteArchivedFiles.php --delete --force' and 'php maintenance/deleteArchivedRevisions.php --delete'" ); - } - - $this->assertArrayHasKey( 'result', $data[0] ); - $this->assertEquals( 1, $data[0]['result'] ); - - $this->assertArrayHasKey( 'done', $data[0] ); - $this->assertEquals( 1, $data[0]['done'] ); - - $this->assertArrayHasKey( 'resultUrl', $data[0] ); - $this->assertRegExp( '/File:Twar.png/', $data[0]['resultUrl'] ); + function testCleanup() { + $dbw = wfGetDB( DB_MASTER ); + $dbw->begin(); + $dbw->delete("image", array('img_user_text' => self::$userName )); + $dbw->commit(); + $this->assertTrue(true); } } diff --git a/maintenance/tests/phpunit.xml b/maintenance/tests/phpunit.xml index ce7d44f551..ac081ff7e7 100644 --- a/maintenance/tests/phpunit.xml +++ b/maintenance/tests/phpunit.xml @@ -7,6 +7,19 @@ . + + + + + + + + + + + + + -- 2.20.1