MediaWiki  REL1_22
ApiEditPageTest.php
Go to the documentation of this file.
00001 <?php
00002 
00012 class ApiEditPageTest extends ApiTestCase {
00013 
00014     public function setUp() {
00015         global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
00016 
00017         parent::setUp();
00018 
00019         $wgExtraNamespaces[12312] = 'Dummy';
00020         $wgExtraNamespaces[12313] = 'Dummy_talk';
00021 
00022         $wgNamespaceContentModels[12312] = "testing";
00023         $wgContentHandlers["testing"] = 'DummyContentHandlerForTesting';
00024 
00025         MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
00026         $wgContLang->resetNamespaces(); # reset namespace cache
00027 
00028         $this->doLogin();
00029     }
00030 
00031     public function tearDown() {
00032         global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
00033 
00034         unset( $wgExtraNamespaces[12312] );
00035         unset( $wgExtraNamespaces[12313] );
00036 
00037         unset( $wgNamespaceContentModels[12312] );
00038         unset( $wgContentHandlers["testing"] );
00039 
00040         MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
00041         $wgContLang->resetNamespaces(); # reset namespace cache
00042 
00043         parent::tearDown();
00044     }
00045 
00046     public function testEdit() {
00047         $name = 'Help:ApiEditPageTest_testEdit'; // assume Help namespace to default to wikitext
00048 
00049         // -- test new page --------------------------------------------
00050         $apiResult = $this->doApiRequestWithToken( array(
00051             'action' => 'edit',
00052             'title' => $name,
00053             'text' => 'some text',
00054         ) );
00055         $apiResult = $apiResult[0];
00056 
00057         // Validate API result data
00058         $this->assertArrayHasKey( 'edit', $apiResult );
00059         $this->assertArrayHasKey( 'result', $apiResult['edit'] );
00060         $this->assertEquals( 'Success', $apiResult['edit']['result'] );
00061 
00062         $this->assertArrayHasKey( 'new', $apiResult['edit'] );
00063         $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
00064 
00065         $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
00066 
00067         // -- test existing page, no change ----------------------------
00068         $data = $this->doApiRequestWithToken( array(
00069             'action' => 'edit',
00070             'title' => $name,
00071             'text' => 'some text',
00072         ) );
00073 
00074         $this->assertEquals( 'Success', $data[0]['edit']['result'] );
00075 
00076         $this->assertArrayNotHasKey( 'new', $data[0]['edit'] );
00077         $this->assertArrayHasKey( 'nochange', $data[0]['edit'] );
00078 
00079         // -- test existing page, with change --------------------------
00080         $data = $this->doApiRequestWithToken( array(
00081             'action' => 'edit',
00082             'title' => $name,
00083             'text' => 'different text'
00084         ) );
00085 
00086         $this->assertEquals( 'Success', $data[0]['edit']['result'] );
00087 
00088         $this->assertArrayNotHasKey( 'new', $data[0]['edit'] );
00089         $this->assertArrayNotHasKey( 'nochange', $data[0]['edit'] );
00090 
00091         $this->assertArrayHasKey( 'oldrevid', $data[0]['edit'] );
00092         $this->assertArrayHasKey( 'newrevid', $data[0]['edit'] );
00093         $this->assertNotEquals(
00094             $data[0]['edit']['newrevid'],
00095             $data[0]['edit']['oldrevid'],
00096             "revision id should change after edit"
00097         );
00098     }
00099 
00100     public function testNonTextEdit() {
00101         $name = 'Dummy:ApiEditPageTest_testNonTextEdit';
00102         $data = serialize( 'some bla bla text' );
00103 
00104         // -- test new page --------------------------------------------
00105         $apiResult = $this->doApiRequestWithToken( array(
00106             'action' => 'edit',
00107             'title' => $name,
00108             'text' => $data, ) );
00109         $apiResult = $apiResult[0];
00110 
00111         // Validate API result data
00112         $this->assertArrayHasKey( 'edit', $apiResult );
00113         $this->assertArrayHasKey( 'result', $apiResult['edit'] );
00114         $this->assertEquals( 'Success', $apiResult['edit']['result'] );
00115 
00116         $this->assertArrayHasKey( 'new', $apiResult['edit'] );
00117         $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
00118 
00119         $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
00120 
00121         // validate resulting revision
00122         $page = WikiPage::factory( Title::newFromText( $name ) );
00123         $this->assertEquals( "testing", $page->getContentModel() );
00124         $this->assertEquals( $data, $page->getContent()->serialize() );
00125     }
00126 
00127     public static function provideEditAppend() {
00128         return array(
00129             array( #0: append
00130                 'foo', 'append', 'bar', "foobar"
00131             ),
00132             array( #1: prepend
00133                 'foo', 'prepend', 'bar', "barfoo"
00134             ),
00135             array( #2: append to empty page
00136                 '', 'append', 'foo', "foo"
00137             ),
00138             array( #3: prepend to empty page
00139                 '', 'prepend', 'foo', "foo"
00140             ),
00141             array( #4: append to non-existing page
00142                 null, 'append', 'foo', "foo"
00143             ),
00144             array( #5: prepend to non-existing page
00145                 null, 'prepend', 'foo', "foo"
00146             ),
00147         );
00148     }
00149 
00153     public function testEditAppend( $text, $op, $append, $expected ) {
00154         static $count = 0;
00155         $count++;
00156 
00157         // assume NS_HELP defaults to wikitext
00158         $name = "Help:ApiEditPageTest_testEditAppend_$count";
00159 
00160         // -- create page (or not) -----------------------------------------
00161         if ( $text !== null ) {
00162             if ( $text === '' ) {
00163                 // can't create an empty page, so create it with some content
00164                 $this->doApiRequestWithToken( array(
00165                     'action' => 'edit',
00166                     'title' => $name,
00167                     'text' => '(dummy)', ) );
00168             }
00169 
00170             list( $re ) = $this->doApiRequestWithToken( array(
00171                 'action' => 'edit',
00172                 'title' => $name,
00173                 'text' => $text, ) );
00174 
00175             $this->assertEquals( 'Success', $re['edit']['result'] ); // sanity
00176         }
00177 
00178         // -- try append/prepend --------------------------------------------
00179         list( $re ) = $this->doApiRequestWithToken( array(
00180             'action' => 'edit',
00181             'title' => $name,
00182             $op . 'text' => $append, ) );
00183 
00184         $this->assertEquals( 'Success', $re['edit']['result'] );
00185 
00186         // -- validate -----------------------------------------------------
00187         $page = new WikiPage( Title::newFromText( $name ) );
00188         $content = $page->getContent();
00189         $this->assertNotNull( $content, 'Page should have been created' );
00190 
00191         $text = $content->getNativeData();
00192 
00193         $this->assertEquals( $expected, $text );
00194     }
00195 
00199     public function testEditSection() {
00200         $name = 'Help:ApiEditPageTest_testEditSection';
00201         $page = WikiPage::factory( Title::newFromText( $name ) );
00202         $text = "==section 1==\ncontent 1\n==section 2==\ncontent2";
00203         // Preload the page with some text
00204         $page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), 'summary' );
00205 
00206         list( $re ) = $this->doApiRequestWithToken( array(
00207             'action' => 'edit',
00208             'title' => $name,
00209             'section' => '1',
00210             'text' => "==section 1==\nnew content 1",
00211         ) );
00212         $this->assertEquals( 'Success', $re['edit']['result'] );
00213         $newtext = WikiPage::factory( Title::newFromText( $name) )->getContent( Revision::RAW )->getNativeData();
00214         $this->assertEquals( $newtext, "==section 1==\nnew content 1\n\n==section 2==\ncontent2" );
00215 
00216         // Test that we raise a 'nosuchsection' error
00217         try {
00218             $this->doApiRequestWithToken( array(
00219                 'action' => 'edit',
00220                 'title' => $name,
00221                 'section' => '9999',
00222                 'text' => 'text',
00223             ) );
00224             $this->fail( "Should have raised a UsageException" );
00225         } catch ( UsageException $e ) {
00226             $this->assertEquals( $e->getCodeString(), 'nosuchsection' );
00227         }
00228     }
00229 
00236     public function testEditNewSection() {
00237         $name = 'Help:ApiEditPageTest_testEditNewSection';
00238 
00239         // Test on a page that does not already exist
00240         $this->assertFalse( Title::newFromText( $name )->exists() );
00241         list( $re ) = $this->doApiRequestWithToken( array(
00242             'action' => 'edit',
00243             'title' => $name,
00244             'section' => 'new',
00245             'text' => 'test',
00246             'summary' => 'header',
00247         ));
00248 
00249         $this->assertEquals( 'Success', $re['edit']['result'] );
00250         // Check the page text is correct
00251         $text = WikiPage::factory( Title::newFromText( $name ) )->getContent( Revision::RAW )->getNativeData();
00252         $this->assertEquals( $text, "== header ==\n\ntest" );
00253 
00254         // Now on one that does
00255         $this->assertTrue( Title::newFromText( $name )->exists() );
00256         list( $re2 ) = $this->doApiRequestWithToken( array(
00257             'action' => 'edit',
00258             'title' => $name,
00259             'section' => 'new',
00260             'text' => 'test',
00261             'summary' => 'header',
00262         ));
00263 
00264         $this->assertEquals( 'Success', $re2['edit']['result'] );
00265         $text = WikiPage::factory( Title::newFromText( $name ) )->getContent( Revision::RAW )->getNativeData();
00266         $this->assertEquals( $text, "== header ==\n\ntest\n\n== header ==\n\ntest" );
00267     }
00268 
00269     public function testEditConflict() {
00270         static $count = 0;
00271         $count++;
00272 
00273         // assume NS_HELP defaults to wikitext
00274         $name = "Help:ApiEditPageTest_testEditConflict_$count";
00275         $title = Title::newFromText( $name );
00276 
00277         $page = WikiPage::factory( $title );
00278 
00279         // base edit
00280         $page->doEditContent( new WikitextContent( "Foo" ),
00281             "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
00282         $this->forceRevisionDate( $page, '20120101000000' );
00283         $baseTime = $page->getRevision()->getTimestamp();
00284 
00285         // conflicting edit
00286         $page->doEditContent( new WikitextContent( "Foo bar" ),
00287             "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
00288         $this->forceRevisionDate( $page, '20120101020202' );
00289 
00290         // try to save edit, expect conflict
00291         try {
00292             $this->doApiRequestWithToken( array(
00293                 'action' => 'edit',
00294                 'title' => $name,
00295                 'text' => 'nix bar!',
00296                 'basetimestamp' => $baseTime,
00297             ), null, self::$users['sysop']->user );
00298 
00299             $this->fail( 'edit conflict expected' );
00300         } catch ( UsageException $ex ) {
00301             $this->assertEquals( 'editconflict', $ex->getCodeString() );
00302         }
00303     }
00304 
00305     public function testEditConflict_redirect() {
00306         static $count = 0;
00307         $count++;
00308 
00309         // assume NS_HELP defaults to wikitext
00310         $name = "Help:ApiEditPageTest_testEditConflict_redirect_$count";
00311         $title = Title::newFromText( $name );
00312         $page = WikiPage::factory( $title );
00313 
00314         $rname = "Help:ApiEditPageTest_testEditConflict_redirect_r$count";
00315         $rtitle = Title::newFromText( $rname );
00316         $rpage = WikiPage::factory( $rtitle );
00317 
00318         // base edit for content
00319         $page->doEditContent( new WikitextContent( "Foo" ),
00320             "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
00321         $this->forceRevisionDate( $page, '20120101000000' );
00322         $baseTime = $page->getRevision()->getTimestamp();
00323 
00324         // base edit for redirect
00325         $rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
00326             "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
00327         $this->forceRevisionDate( $rpage, '20120101000000' );
00328 
00329         // conflicting edit to redirect
00330         $rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]\n\n[[Category:Test]]" ),
00331             "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
00332         $this->forceRevisionDate( $rpage, '20120101020202' );
00333 
00334         // try to save edit; should work, because we follow the redirect
00335         list( $re, , ) = $this->doApiRequestWithToken( array(
00336             'action' => 'edit',
00337             'title' => $rname,
00338             'text' => 'nix bar!',
00339             'basetimestamp' => $baseTime,
00340             'redirect' => true,
00341         ), null, self::$users['sysop']->user );
00342 
00343         $this->assertEquals( 'Success', $re['edit']['result'],
00344             "no edit conflict expected when following redirect" );
00345 
00346         // try again, without following the redirect. Should fail.
00347         try {
00348             $this->doApiRequestWithToken( array(
00349                 'action' => 'edit',
00350                 'title' => $rname,
00351                 'text' => 'nix bar!',
00352                 'basetimestamp' => $baseTime,
00353             ), null, self::$users['sysop']->user );
00354 
00355             $this->fail( 'edit conflict expected' );
00356         } catch ( UsageException $ex ) {
00357             $this->assertEquals( 'editconflict', $ex->getCodeString() );
00358         }
00359     }
00360 
00361     public function testEditConflict_bug41990() {
00362         static $count = 0;
00363         $count++;
00364 
00365         /*
00366         * bug 41990: if the target page has a newer revision than the redirect, then editing the
00367         * redirect while specifying 'redirect' and *not* specifying 'basetimestamp' erroneously
00368         * caused an edit conflict to be detected.
00369         */
00370 
00371         // assume NS_HELP defaults to wikitext
00372         $name = "Help:ApiEditPageTest_testEditConflict_redirect_bug41990_$count";
00373         $title = Title::newFromText( $name );
00374         $page = WikiPage::factory( $title );
00375 
00376         $rname = "Help:ApiEditPageTest_testEditConflict_redirect_bug41990_r$count";
00377         $rtitle = Title::newFromText( $rname );
00378         $rpage = WikiPage::factory( $rtitle );
00379 
00380         // base edit for content
00381         $page->doEditContent( new WikitextContent( "Foo" ),
00382             "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
00383         $this->forceRevisionDate( $page, '20120101000000' );
00384 
00385         // base edit for redirect
00386         $rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
00387             "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
00388         $this->forceRevisionDate( $rpage, '20120101000000' );
00389         $baseTime = $rpage->getRevision()->getTimestamp();
00390 
00391         // new edit to content
00392         $page->doEditContent( new WikitextContent( "Foo bar" ),
00393             "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
00394         $this->forceRevisionDate( $rpage, '20120101020202' );
00395 
00396         // try to save edit; should work, following the redirect.
00397         list( $re, , ) = $this->doApiRequestWithToken( array(
00398             'action' => 'edit',
00399             'title' => $rname,
00400             'text' => 'nix bar!',
00401             'redirect' => true,
00402         ), null, self::$users['sysop']->user );
00403 
00404         $this->assertEquals( 'Success', $re['edit']['result'],
00405             "no edit conflict expected here" );
00406     }
00407 
00408     protected function forceRevisionDate( WikiPage $page, $timestamp ) {
00409         $dbw = wfGetDB( DB_MASTER );
00410 
00411         $dbw->update( 'revision',
00412             array( 'rev_timestamp' => $dbw->timestamp( $timestamp ) ),
00413             array( 'rev_id' => $page->getLatest() ) );
00414 
00415         $page->clear();
00416     }
00417 }