3 namespace MediaWiki\Tests\Maintenance
;
8 use MediaWikiLangTestCase
;
15 * Base TestCase for dumps
17 abstract class DumpTestCase
extends MediaWikiLangTestCase
{
20 * exception to be rethrown once in sound PHPUnit surrounding
22 * As the current MediaWikiTestCase::run is not robust enough to recover
23 * from thrown exceptions directly, we cannot throw frow within
24 * self::addDBData, although it would be appropriate. Hence, we catch the
25 * exception and store it until we are in setUp and may finally rethrow
26 * the exception without crashing the test suite.
28 * @var \Exception|null
30 protected $exceptionFromAddDBData = null;
32 /** @var bool|null Whether the 'gzip' utility is available */
33 protected static $hasGzip = null;
36 * Skip the test if 'gzip' is not in $PATH.
40 protected function checkHasGzip() {
41 if ( self
::$hasGzip === null ) {
42 self
::$hasGzip = ( ExecutableFinder
::findInDefaultPaths( 'gzip' ) !== false );
45 if ( !self
::$hasGzip ) {
46 $this->markTestSkipped( "Skip test, requires the gzip utility in PATH" );
49 return self
::$hasGzip;
53 * Adds a revision to a page, while returning the resuting revision's id
55 * @param WikiPage $page Page to add the revision to
56 * @param string $text Revisions text
57 * @param string $summary Revisions summary
58 * @param string $model The model ID (defaults to wikitext)
63 protected function addRevision(
67 $model = CONTENT_MODEL_WIKITEXT
69 $status = $page->doEditContent(
70 ContentHandler
::makeContent( $text, $page->getTitle(), $model ),
71 $summary, 0, false, $this->getTestUser()->getUser()
74 if ( $status->isGood() ) {
75 $value = $status->getValue();
76 $revision = $value['revision'];
77 $revision_id = $revision->getId();
78 $text_id = $revision->getTextId();
80 if ( ( $revision_id > 0 ) && ( $text_id > 0 ) ) {
81 return [ $revision_id, $text_id ];
85 throw new MWException( "Could not determine revision id ("
86 . $status->getWikiText( false, false, 'en' ) . ")" );
90 * gunzips the given file and stores the result in the original file name
92 * @param string $fname Filename to read the gzipped data from and stored
93 * the gunzipped data into
95 protected function gunzip( $fname ) {
96 $gzipped_contents = file_get_contents( $fname );
97 if ( $gzipped_contents === false ) {
98 $this->fail( "Could not get contents of $fname" );
101 $contents = gzdecode( $gzipped_contents );
105 file_put_contents( $fname, $contents ),
110 public static function setUpBeforeClass() {
111 parent
::setUpBeforeClass();
113 if ( !function_exists( 'libxml_set_external_entity_loader' ) ) {
117 // The W3C is intentionally slow about returning schema files,
118 // see <https://www.w3.org/Help/Webmaster#slowdtd>.
119 // To work around that, we keep our own copies of the relevant schema files.
120 libxml_set_external_entity_loader(
121 function ( $public, $system, $context ) {
123 // if more schema files are needed, add them here.
124 case 'http://www.w3.org/2001/xml.xsd':
125 $file = __DIR__
. '/xml.xsd';
128 if ( is_file( $system ) ) {
141 * Default set up function.
143 * Clears $wgUser, and reports errors from addDBData to PHPUnit
145 protected function setUp() {
148 // Check if any Exception is stored for rethrowing from addDBData
149 // @see self::exceptionFromAddDBData
150 if ( $this->exceptionFromAddDBData
!== null ) {
151 throw $this->exceptionFromAddDBData
;
154 $this->setMwGlobals( 'wgUser', new User() );
158 * Returns the path to the XML schema file for the given schema version.
160 * @param string|null $schemaVersion
164 protected function getXmlSchemaPath( $schemaVersion = null ) {
165 global $IP, $wgXmlDumpSchemaVersion;
167 $schemaVersion = $schemaVersion ?
: $wgXmlDumpSchemaVersion;
169 return "$IP/docs/export-$schemaVersion.xsd";
173 * Checks for test output consisting only of lines containing ETA announcements
175 function expectETAOutput() {
176 // Newer PHPUnits require assertion about the output using PHPUnit's own
177 // expectOutput[...] functions. However, the PHPUnit shipped prediactes
178 // do not allow to check /each/ line of the output using /readable/ REs.
181 // 1. ... add a dummy output checking to make PHPUnit not complain
182 // about unchecked test output
183 $this->expectOutputRegex( '//' );
185 // 2. Do the real output checking on our own.
186 $lines = explode( "\n", $this->getActualOutput() );
187 $this->assertGreaterThan( 1, count( $lines ), "Minimal lines of produced output" );
188 $this->assertSame( '', array_pop( $lines ), "Output ends in LF" );
189 $timestamp_re = "[0-9]{4}-[01][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-6][0-9]";
190 foreach ( $lines as $line ) {
192 "/$timestamp_re: .* \(ID [0-9]+\) [0-9]* pages .*, [0-9]* revs .*, ETA/",
199 * @param null|string $schemaVersion
201 * @return DumpAsserter
203 protected function getDumpAsserter( $schemaVersion = null ) {
204 $schemaVersion = $schemaVersion ?
: WikiExporter
::schemaVersion();
205 return new DumpAsserter( $schemaVersion );
209 * Checks an XML file against an XSD schema.
211 protected function assertDumpSchema( $fname, $schemaFile ) {
212 if ( !function_exists( 'libxml_use_internal_errors' ) ) {
213 // Would be nice to leave a warning somehow.
214 // We don't want to skip all of the test case that calls this, though.
215 $this->markAsRisky();
218 if ( defined( 'HHVM_VERSION' ) ) {
219 // In HHVM, loading a schema from a file is disabled per default.
220 // This is controlled by hhvm.libxml.ext_entity_whitelist which
221 // cannot be read with ini_get(), see
222 // <https://docs.hhvm.com/hhvm/configuration/INI-settings#xml>.
223 // Would be nice to leave a warning somehow.
224 // We don't want to skip all of the test case that calls this, though.
225 $this->markAsRisky();
229 $xml = new DOMDocument();
230 $this->assertTrue( $xml->load( $fname ),
231 "Opening temporary file $fname via DOMDocument failed" );
234 $oldLibXmlInternalErrors = libxml_use_internal_errors( true );
236 // NOTE: if this reports "Invalid Schema", the schema may be referencing an external
237 // entity (typically, another schema) that needs to be mapped in the
238 // libxml_set_external_entity_loader callback defined in setUpBeforeClass() above!
239 // Or $schemaFile doesn't point to a schema file, or the schema is indeed just broken.
240 if ( !$xml->schemaValidate( $schemaFile ) ) {
243 foreach ( libxml_get_errors() as $error ) {
244 $errorText .= "\nline {$error->line}: {$error->message}";
247 libxml_clear_errors();
250 "Failed asserting that $fname conforms to the schema in $schemaFile:\n$errorText"
254 libxml_use_internal_errors( $oldLibXmlInternalErrors );