r85566 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r85565‎ | r85566 | r85567 >
Date:19:50, 6 April 2011
Author:mah
Status:resolved
Tags:
Comment:
Apply modification of mdale's patch from Bug #28420: “Re-factor upload tests to support extensions extending upload test case”
Modified paths:
  • /trunk/phase3/tests/phpunit/includes/api/ApiTestCase.php (added) (history)
  • /trunk/phase3/tests/phpunit/includes/api/ApiTestCaseUpload.php (added) (history)
  • /trunk/phase3/tests/phpunit/includes/api/ApiTestUser.php (added) (history)
  • /trunk/phase3/tests/phpunit/includes/api/ApiUploadTest.php (modified) (history)

Diff [purge]

Index: trunk/phase3/tests/phpunit/includes/api/ApiTestCaseUpload.php
@@ -0,0 +1,128 @@
 2+<?php
 3+
 4+/**
 5+ * * Abstract class to support upload tests
 6+ */
 7+require_once( 'ApiTestUser.php' );
 8+require_once( 'ApiTestCase.php' );
 9+
 10+abstract class ApiTestCaseUpload extends ApiTestCase {
 11+ /**
 12+ * Fixture -- run before every test
 13+ */
 14+ public function setUp() {
 15+ global $wgEnableUploads, $wgEnableAPI;
 16+ parent::setUp();
 17+
 18+ $wgEnableUploads = true;
 19+ $wgEnableAPI = true;
 20+ wfSetupSession();
 21+
 22+ ini_set( 'log_errors', 1 );
 23+ ini_set( 'error_reporting', 1 );
 24+ ini_set( 'display_errors', 1 );
 25+
 26+ $this->clearFakeUploads();
 27+ }
 28+
 29+ /**
 30+ * Fixture -- run after every test
 31+ * Clean up temporary files etc.
 32+ */
 33+ function tearDown() {
 34+ }
 35+
 36+
 37+ /**
 38+ * Helper function -- remove files and associated articles by Title
 39+ * @param $title Title: title to be removed
 40+ */
 41+ public function deleteFileByTitle( $title ) {
 42+ if ( $title->exists() ) {
 43+ $file = wfFindFile( $title, array( 'ignoreRedirect' => true ) );
 44+ $noOldArchive = ""; // yes this really needs to be set this way
 45+ $comment = "removing for test";
 46+ $restrictDeletedVersions = false;
 47+ $status = FileDeleteForm::doDelete( $title, $file, $noOldArchive, $comment, $restrictDeletedVersions );
 48+ if ( !$status->isGood() ) {
 49+ return false;
 50+ }
 51+ $article = new Article( $title );
 52+ $article->doDeleteArticle( "removing for test" );
 53+
 54+ // see if it now doesn't exist; reload
 55+ $title = Title::newFromText( $fileName, NS_FILE );
 56+ }
 57+ return ! ( $title && $title instanceof Title && $title->exists() );
 58+ }
 59+
 60+ /**
 61+ * Helper function -- remove files and associated articles with a particular filename
 62+ * @param $fileName String: filename to be removed
 63+ */
 64+ public function deleteFileByFileName( $fileName ) {
 65+ return $this->deleteFileByTitle( Title::newFromText( $fileName, NS_FILE ) );
 66+ }
 67+
 68+
 69+ /**
 70+ * Helper function -- given a file on the filesystem, find matching content in the db (and associated articles) and remove them.
 71+ * @param $filePath String: path to file on the filesystem
 72+ */
 73+ public function deleteFileByContent( $filePath ) {
 74+ $hash = File::sha1Base36( $filePath );
 75+ $dupes = RepoGroup::singleton()->findBySha1( $hash );
 76+ $success = true;
 77+ foreach ( $dupes as $dupe ) {
 78+ $success &= $this->deleteFileByTitle( $dupe->getTitle() );
 79+ }
 80+ return $success;
 81+ }
 82+
 83+ /**
 84+ * Fake an upload by dumping the file into temp space, and adding info to $_FILES.
 85+ * (This is what PHP would normally do).
 86+ * @param $fieldName String: name this would have in the upload form
 87+ * @param $fileName String: name to title this
 88+ * @param $type String: mime type
 89+ * @param $filePath String: path where to find file contents
 90+ */
 91+ function fakeUploadFile( $fieldName, $fileName, $type, $filePath ) {
 92+ $tmpName = tempnam( wfTempDir(), "" );
 93+ if ( !file_exists( $filePath ) ) {
 94+ throw new Exception( "$filePath doesn't exist!" );
 95+ };
 96+
 97+ if ( !copy( $filePath, $tmpName ) ) {
 98+ throw new Exception( "couldn't copy $filePath to $tmpName" );
 99+ }
 100+
 101+ clearstatcache();
 102+ $size = filesize( $tmpName );
 103+ if ( $size === false ) {
 104+ throw new Exception( "couldn't stat $tmpName" );
 105+ }
 106+
 107+ $_FILES[ $fieldName ] = array(
 108+ 'name' => $fileName,
 109+ 'type' => $type,
 110+ 'tmp_name' => $tmpName,
 111+ 'size' => $size,
 112+ 'error' => null
 113+ );
 114+
 115+ return true;
 116+
 117+ }
 118+
 119+ /**
 120+ * Remove traces of previous fake uploads
 121+ */
 122+ function clearFakeUploads() {
 123+ $_FILES = array();
 124+ }
 125+
 126+
 127+
 128+
 129+}
Property changes on: trunk/phase3/tests/phpunit/includes/api/ApiTestCaseUpload.php
___________________________________________________________________
Added: svn:eol-syle
1130 + native
Index: trunk/phase3/tests/phpunit/includes/api/ApiUploadTest.php
@@ -14,164 +14,19 @@
1515 // This framework works better IMO and has less strangeness (such as test cases inheriting from "ApiSetup"...)
1616 // (and in the case of the other Upload tests, this flat out just actually works... )
1717
18 -// TODO: refactor into several files
1918 // TODO: port the other Upload tests, and other API tests to this framework
2019
21 -/* Wraps the user object, so we can also retain full access to properties like password if we log in via the API */
22 -class ApiTestUser {
23 - public $username;
24 - public $password;
25 - public $email;
26 - public $groups;
27 - public $user;
 20+require_once( 'ApiTestCaseUpload.php' );
2821
29 - function __construct( $username, $realname = 'Real Name', $email = 'sample@sample.com', $groups = array() ) {
30 - $this->username = $username;
31 - $this->realname = $realname;
32 - $this->email = $email;
33 - $this->groups = $groups;
34 -
35 - // don't allow user to hardcode or select passwords -- people sometimes run tests
36 - // on live wikis. Sometimes we create sysop users in these tests. A sysop user with
37 - // a known password would be a Bad Thing.
38 - $this->password = User::randomPassword();
39 -
40 - $this->user = User::newFromName( $this->username );
41 - $this->user->load();
42 -
43 - // In an ideal world we'd have a new wiki (or mock data store) for every single test.
44 - // But for now, we just need to create or update the user with the desired properties.
45 - // we particularly need the new password, since we just generated it randomly.
46 - // In core MediaWiki, there is no functionality to delete users, so this is the best we can do.
47 - if ( !$this->user->getID() ) {
48 - // create the user
49 - $this->user = User::createNew(
50 - $this->username, array(
51 - "email" => $this->email,
52 - "real_name" => $this->realname
53 - )
54 - );
55 - if ( !$this->user ) {
56 - throw new Exception( "error creating user" );
57 - }
58 - }
59 -
60 - // update the user to use the new random password and other details
61 - $this->user->setPassword( $this->password );
62 - $this->user->setEmail( $this->email );
63 - $this->user->setRealName( $this->realname );
64 - // remove all groups, replace with any groups specified
65 - foreach ( $this->user->getGroups() as $group ) {
66 - $this->user->removeGroup( $group );
67 - }
68 - if ( count( $this->groups ) ) {
69 - foreach ( $this->groups as $group ) {
70 - $this->user->addGroup( $group );
71 - }
72 - }
73 - $this->user->saveSettings();
74 -
75 - }
76 -
77 -}
78 -
79 -abstract class ApiTestCase extends MediaWikiTestCase {
80 - public static $users;
81 -
82 - function setUp() {
83 - global $wgContLang, $wgAuth, $wgMemc, $wgRequest, $wgUser;
84 -
85 - $wgMemc = new EmptyBagOStuff();
86 - $wgContLang = Language::factory( 'en' );
87 - $wgAuth = new StubObject( 'wgAuth', 'AuthPlugin' );
88 - $wgRequest = new FauxRequest( array() );
89 -
90 - self::$users = array(
91 - 'sysop' => new ApiTestUser(
92 - 'Apitestsysop',
93 - 'Api Test Sysop',
94 - 'api_test_sysop@sample.com',
95 - array( 'sysop' )
96 - ),
97 - 'uploader' => new ApiTestUser(
98 - 'Apitestuser',
99 - 'Api Test User',
100 - 'api_test_user@sample.com',
101 - array()
102 - )
103 - );
104 -
105 - $wgUser = self::$users['sysop']->user;
106 -
107 - }
108 -
109 - protected function doApiRequest( $params, $session = null, $appendModule = false ) {
110 - if ( is_null( $session ) ) {
111 - $session = array();
112 - }
113 -
114 - $request = new FauxRequest( $params, true, $session );
115 - $module = new ApiMain( $request, true );
116 - $module->execute();
117 -
118 - return array( $module->getResultData(), $request, $request->getSessionArray() );
119 - }
120 -
121 - /**
122 - * Add an edit token to the API request
123 - * This is cheating a bit -- we grab a token in the correct format and then add it to the pseudo-session and to the
124 - * request, without actually requesting a "real" edit token
125 - * @param $params: key-value API params
126 - * @param $session: session array
127 - */
128 - protected function doApiRequestWithToken( $params, $session ) {
129 - if ( $session['wsToken'] ) {
130 - // add edit token to fake session
131 - $session['wsEditToken'] = $session['wsToken'];
132 - // add token to request parameters
133 - $params['token'] = md5( $session['wsToken'] ) . User::EDIT_TOKEN_SUFFIX;
134 - return $this->doApiRequest( $params, $session );
135 - } else {
136 - throw new Exception( "request data not in right format" );
137 - }
138 - }
139 -
140 -}
141 -
14222 /**
14323 * @group Database
14424 * @group Destructive
14525 *
14626 * This is pretty sucky... needs to be prettified.
14727 */
148 -class ApiUploadTest extends ApiTestCase {
149 - /**
150 - * Fixture -- run before every test
151 - */
152 - public function setUp() {
153 - global $wgEnableUploads, $wgEnableAPI;
154 - parent::setUp();
 28+class ApiUploadTest extends ApiTestCaseUpload {
15529
156 - $wgEnableUploads = true;
157 - $wgEnableAPI = true;
158 - wfSetupSession();
159 -
160 - ini_set( 'log_errors', 1 );
161 - ini_set( 'error_reporting', 1 );
162 - ini_set( 'display_errors', 1 );
163 -
164 - $this->clearFakeUploads();
165 - }
166 -
16730 /**
168 - * Fixture -- run after every test
169 - * Clean up temporary files etc.
170 - */
171 - function tearDown() {
172 - }
173 -
174 -
175 - /**
17631 * Testing login
17732 * XXX this is a funny way of getting session context
17833 */
@@ -575,98 +430,5 @@
576431 $this->deleteFileByFilename( $fileName );
577432 unlink( $filePath );
578433 }
579 -
580 -
581 -
582 - /**
583 - * Helper function -- remove files and associated articles by Title
584 - * @param $title Title: title to be removed
585 - */
586 - public function deleteFileByTitle( $title ) {
587 - if ( $title->exists() ) {
588 - $file = wfFindFile( $title, array( 'ignoreRedirect' => true ) );
589 - $noOldArchive = ""; // yes this really needs to be set this way
590 - $comment = "removing for test";
591 - $restrictDeletedVersions = false;
592 - $status = FileDeleteForm::doDelete( $title, $file, $noOldArchive, $comment, $restrictDeletedVersions );
593 - if ( !$status->isGood() ) {
594 - return false;
595 - }
596 - $article = new Article( $title );
597 - $article->doDeleteArticle( "removing for test" );
598 -
599 - // see if it now doesn't exist; reload
600 - $title = Title::newFromText( $fileName, NS_FILE );
601 - }
602 - return ! ( $title && $title instanceof Title && $title->exists() );
603 - }
604 -
605 - /**
606 - * Helper function -- remove files and associated articles with a particular filename
607 - * @param $fileName String: filename to be removed
608 - */
609 - public function deleteFileByFileName( $fileName ) {
610 - return $this->deleteFileByTitle( Title::newFromText( $fileName, NS_FILE ) );
611 - }
612 -
613 -
614 - /**
615 - * Helper function -- given a file on the filesystem, find matching content in the db (and associated articles) and remove them.
616 - * @param $filePath String: path to file on the filesystem
617 - */
618 - public function deleteFileByContent( $filePath ) {
619 - $hash = File::sha1Base36( $filePath );
620 - $dupes = RepoGroup::singleton()->findBySha1( $hash );
621 - $success = true;
622 - foreach ( $dupes as $dupe ) {
623 - $success &= $this->deleteFileByTitle( $dupe->getTitle() );
624 - }
625 - return $success;
626 - }
627 -
628 - /**
629 - * Fake an upload by dumping the file into temp space, and adding info to $_FILES.
630 - * (This is what PHP would normally do).
631 - * @param $fieldName String: name this would have in the upload form
632 - * @param $fileName String: name to title this
633 - * @param $type String: mime type
634 - * @param $filePath String: path where to find file contents
635 - */
636 - function fakeUploadFile( $fieldName, $fileName, $type, $filePath ) {
637 - $tmpName = tempnam( wfTempDir(), "" );
638 - if ( !file_exists( $filePath ) ) {
639 - throw new Exception( "$filePath doesn't exist!" );
640 - };
641 -
642 - if ( !copy( $filePath, $tmpName ) ) {
643 - throw new Exception( "couldn't copy $filePath to $tmpName" );
644 - }
645 -
646 - clearstatcache();
647 - $size = filesize( $tmpName );
648 - if ( $size === false ) {
649 - throw new Exception( "couldn't stat $tmpName" );
650 - }
651 -
652 - $_FILES[ $fieldName ] = array(
653 - 'name' => $fileName,
654 - 'type' => $type,
655 - 'tmp_name' => $tmpName,
656 - 'size' => $size,
657 - 'error' => null
658 - );
659 -
660 - return true;
661 -
662 - }
663 -
664 - /**
665 - * Remove traces of previous fake uploads
666 - */
667 - function clearFakeUploads() {
668 - $_FILES = array();
669 - }
670 -
671 -
672434 }
673435
Index: trunk/phase3/tests/phpunit/includes/api/ApiTestCase.php
@@ -0,0 +1,64 @@
 2+<?php
 3+
 4+abstract class ApiTestCase extends MediaWikiTestCase {
 5+ public static $users;
 6+
 7+ function setUp() {
 8+ global $wgContLang, $wgAuth, $wgMemc, $wgRequest, $wgUser;
 9+
 10+ $wgMemc = new EmptyBagOStuff();
 11+ $wgContLang = Language::factory( 'en' );
 12+ $wgAuth = new StubObject( 'wgAuth', 'AuthPlugin' );
 13+ $wgRequest = new FauxRequest( array() );
 14+
 15+ self::$users = array(
 16+ 'sysop' => new ApiTestUser(
 17+ 'Apitestsysop',
 18+ 'Api Test Sysop',
 19+ 'api_test_sysop@sample.com',
 20+ array( 'sysop' )
 21+ ),
 22+ 'uploader' => new ApiTestUser(
 23+ 'Apitestuser',
 24+ 'Api Test User',
 25+ 'api_test_user@sample.com',
 26+ array()
 27+ )
 28+ );
 29+
 30+ $wgUser = self::$users['sysop']->user;
 31+
 32+ }
 33+
 34+ protected function doApiRequest( $params, $session = null, $appendModule = false ) {
 35+ if ( is_null( $session ) ) {
 36+ $session = array();
 37+ }
 38+
 39+ $request = new FauxRequest( $params, true, $session );
 40+ $module = new ApiMain( $request, true );
 41+ $module->execute();
 42+
 43+ return array( $module->getResultData(), $request, $request->getSessionArray() );
 44+ }
 45+
 46+ /**
 47+ * Add an edit token to the API request
 48+ * This is cheating a bit -- we grab a token in the correct format and then add it to the pseudo-session and to the
 49+ * request, without actually requesting a "real" edit token
 50+ * @param $params: key-value API params
 51+ * @param $session: session array
 52+ */
 53+ protected function doApiRequestWithToken( $params, $session ) {
 54+ if ( $session['wsToken'] ) {
 55+ // add edit token to fake session
 56+ $session['wsEditToken'] = $session['wsToken'];
 57+ // add token to request parameters
 58+ $params['token'] = md5( $session['wsToken'] ) . User::EDIT_TOKEN_SUFFIX;
 59+ return $this->doApiRequest( $params, $session );
 60+ } else {
 61+ throw new Exception( "request data not in right format" );
 62+ }
 63+ }
 64+
 65+}
Property changes on: trunk/phase3/tests/phpunit/includes/api/ApiTestCase.php
___________________________________________________________________
Added: svn:eol-syle
166 + native
Index: trunk/phase3/tests/phpunit/includes/api/ApiTestUser.php
@@ -0,0 +1,59 @@
 2+<?php
 3+
 4+/* Wraps the user object, so we can also retain full access to properties like password if we log in via the API */
 5+class ApiTestUser {
 6+ public $username;
 7+ public $password;
 8+ public $email;
 9+ public $groups;
 10+ public $user;
 11+
 12+ function __construct( $username, $realname = 'Real Name', $email = 'sample@sample.com', $groups = array() ) {
 13+ $this->username = $username;
 14+ $this->realname = $realname;
 15+ $this->email = $email;
 16+ $this->groups = $groups;
 17+
 18+ // don't allow user to hardcode or select passwords -- people sometimes run tests
 19+ // on live wikis. Sometimes we create sysop users in these tests. A sysop user with
 20+ // a known password would be a Bad Thing.
 21+ $this->password = User::randomPassword();
 22+
 23+ $this->user = User::newFromName( $this->username );
 24+ $this->user->load();
 25+
 26+ // In an ideal world we'd have a new wiki (or mock data store) for every single test.
 27+ // But for now, we just need to create or update the user with the desired properties.
 28+ // we particularly need the new password, since we just generated it randomly.
 29+ // In core MediaWiki, there is no functionality to delete users, so this is the best we can do.
 30+ if ( !$this->user->getID() ) {
 31+ // create the user
 32+ $this->user = User::createNew(
 33+ $this->username, array(
 34+ "email" => $this->email,
 35+ "real_name" => $this->realname
 36+ )
 37+ );
 38+ if ( !$this->user ) {
 39+ throw new Exception( "error creating user" );
 40+ }
 41+ }
 42+
 43+ // update the user to use the new random password and other details
 44+ $this->user->setPassword( $this->password );
 45+ $this->user->setEmail( $this->email );
 46+ $this->user->setRealName( $this->realname );
 47+ // remove all groups, replace with any groups specified
 48+ foreach ( $this->user->getGroups() as $group ) {
 49+ $this->user->removeGroup( $group );
 50+ }
 51+ if ( count( $this->groups ) ) {
 52+ foreach ( $this->groups as $group ) {
 53+ $this->user->addGroup( $group );
 54+ }
 55+ }
 56+ $this->user->saveSettings();
 57+
 58+ }
 59+
 60+}
Property changes on: trunk/phase3/tests/phpunit/includes/api/ApiTestUser.php
___________________________________________________________________
Added: svn:eol-syle
161 + native

Follow-up revisions

RevisionCommit summaryAuthorDate
r85762Follow up r85566. Add the helper classes to test autoloader.platonides16:42, 10 April 2011

Status & tagging log