1<?php 2 3use dokuwiki\ChangeLog\PageChangeLog; 4 5/** 6 * saveWikiText() stores files in pages/, attic/ and adds entries to changelog 7 */ 8class common_saveWikiText_test extends DokuWikiTest { 9 10 /** Delay writes of old revisions by a second. */ 11 public function handle_write(Doku_Event $event, $param) { 12 if ($event->data[3] !== false) { 13 $this->waitForTick(); 14 } 15 } 16 17 /** 18 * Execute a whole bunch of saves on the same page and check the results 19 * TEST 1 20 * 1.1 create a page 21 * 1.2 save with same content should be ignored 22 * 1.3 update the page with new text 23 * 1.4 add a minor edit (unauthenticated) 24 * 1.5 add a minor edit (authenticated) 25 * 1.6 delete 26 * 1.7 restore 27 * 1.8 external edit 28 * 1.9 save on top of external edit 29 */ 30 function test_savesequence1() { 31 global $REV; 32 33 $page = 'page'; 34 $file = wikiFN($page); 35 36 // 1.1 create a page 37 $this->assertFileNotExists($file); 38 saveWikiText($page, 'teststring', '1st save', false); 39 $this->assertFileExists($file); 40 $lastmod = filemtime($file); 41 $expect = array( 42 'date' => $lastmod, 43 'type' => DOKU_CHANGE_TYPE_CREATE, 44 'sum' => '1st save', 45 'sizechange' => 10, // = strlen('teststring') 46 ); 47 48 $pagelog = new PageChangeLog($page); 49 $revisions = $pagelog->getRevisions(-1, 200); 50 $this->assertCount(1, $revisions); 51 // last revision 52 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 53 $expect += $lastRevInfo; 54 $this->assertEquals($expect, $lastRevInfo); 55 // current revision 56 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 57 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 58 // attic 59 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 60 61 $this->waitForTick(true); // wait for new revision ID 62 63 // 1.2 save with same content should be ignored 64 saveWikiText($page, 'teststring', '2nd save', false); 65 clearstatcache(false, $file); 66 $this->assertEquals($lastmod, filemtime($file)); 67 68 $pagelog = new PageChangeLog($page); 69 $revisions = $pagelog->getRevisions(-1, 200); 70 $this->assertCount(1, $revisions); 71 72 // 1.3 update the page with new text 73 saveWikiText($page, 'teststring2long', '3rd save', false); 74 clearstatcache(false, $file); 75 $newmod = filemtime($file); 76 $this->assertNotEquals($lastmod, $newmod); 77 $lastmod = $newmod; 78 $expect = array( 79 'date' => $lastmod, 80 'type' => DOKU_CHANGE_TYPE_EDIT, 81 'sum' => '3rd save', 82 'sizechange' => 5, 83 ); 84 85 $pagelog = new PageChangeLog($page); 86 $revisions = $pagelog->getRevisions(-1, 200); 87 $this->assertCount(2, $revisions); 88 // last revision 89 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 90 $expect += $lastRevInfo; 91 $this->assertEquals($expect, $lastRevInfo); 92 // current revision 93 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 94 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 95 // attic 96 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 97 98 $this->waitForTick(); // wait for new revision ID 99 100 // 1.4 add a minor edit (unauthenticated) 101 saveWikiText($page, 'teststring3long', '4th save', true); 102 clearstatcache(false, $file); 103 $newmod = filemtime($file); 104 $this->assertNotEquals($lastmod, $newmod); 105 $lastmod = $newmod; 106 $expect = array( 107 'date' => $lastmod, 108 'type' => DOKU_CHANGE_TYPE_EDIT, 109 'sum' => '4th save', 110 'sizechange' => 0, 111 ); 112 113 $pagelog = new PageChangeLog($page); 114 $revisions = $pagelog->getRevisions(-1, 200); 115 $this->assertCount(3, $revisions); 116 // last revision 117 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 118 $expect += $lastRevInfo; 119 $this->assertEquals($expect, $lastRevInfo); 120 // current revision 121 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 122 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 123 // attic 124 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 125 126 $this->waitForTick(); // wait for new revision ID 127 128 // 1.5 add a minor edit (authenticated) 129 $_SERVER['REMOTE_USER'] = 'user'; 130 saveWikiText($page, 'teststring4', '5th save', true); 131 clearstatcache(false, $file); 132 $newmod = filemtime($file); 133 $this->assertNotEquals($lastmod, $newmod); 134 $lastmod = $newmod; 135 $expect = array( 136 'date' => $lastmod, 137 'type' => DOKU_CHANGE_TYPE_MINOR_EDIT, 138 'sum' => '5th save', 139 'sizechange' => -4, 140 ); 141 142 $pagelog = new PageChangeLog($page); 143 $revisions = $pagelog->getRevisions(-1, 200); 144 $this->assertCount(4, $revisions); 145 // last revision 146 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 147 $expect += $lastRevInfo; 148 $this->assertEquals($expect, $lastRevInfo); 149 // current revision 150 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 151 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 152 // attic 153 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 154 155 $this->waitForTick(); // wait for new revision ID 156 157 // 1.6 delete 158 saveWikiText($page, '', '6th save', false); 159 clearstatcache(false, $file); 160 $this->assertFileNotExists($file); 161 $expect = array( 162 //'date' => $lastmod, // ignore from lastRev assertion, but confirm attic file existence 163 'type' => DOKU_CHANGE_TYPE_DELETE, 164 'sum' => '6th save', 165 'sizechange' => -11, 166 ); 167 168 $pagelog = new PageChangeLog($page); 169 $revisions = $pagelog->getRevisions(-1, 200); 170 $this->assertCount(5, $revisions); 171 // last revision 172 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 173 $expect += $lastRevInfo; 174 $this->assertEquals($expect, $lastRevInfo); 175 // current revision 176 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 177 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 178 // attic 179 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 180 181 $this->waitForTick(); // wait for new revision ID 182 183 // 1.7 restore 184 $REV = $lastmod; 185 saveWikiText($page, 'teststring4', '7th save', true); 186 clearstatcache(false, $file); 187 $this->assertFileExists($file); 188 $newmod = filemtime($file); 189 $this->assertNotEquals($lastmod, $newmod); 190 $lastmod = $newmod; 191 $expect = array( 192 'date' => $lastmod, 193 'type' => DOKU_CHANGE_TYPE_REVERT, 194 'sum' => '7th save', 195 'sizechange' => 11, 196 ); 197 198 $pagelog = new PageChangeLog($page); 199 $revisions = $pagelog->getRevisions(-1, 200); 200 $this->assertCount(6, $revisions); 201 // last revision 202 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 203 $expect += $lastRevInfo; 204 $this->assertEquals($expect, $lastRevInfo); 205 // current revision 206 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 207 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 208 // attic 209 $this->assertFileExists(wikiFN($page, $lastRevInfo['date']), 'file missing in attic'); 210 $files = glob(dirname(wikiFN($page, $lastRevInfo['date'])).'/'.$page.'.*'); 211 $this->assertCount(6, $files, 'detectExternalEdit() should not add too often old revs'); 212 $REV = ''; 213 214 $this->waitForTick(); // wait for new revision ID 215 216 // 1.8 external edit 217 file_put_contents($file, 'teststring5 external edit'); 218 clearstatcache(false, $file); 219 $newmod = filemtime($file); 220 $this->assertNotEquals($lastmod, $newmod); 221 $lastmod = $newmod; 222 $expectExternal = array( 223 'date' => $lastmod, 224 'type' => DOKU_CHANGE_TYPE_EDIT, 225 'sum' => 'external edit', 226 'sizechange' => 14, 227 ); 228 229 $pagelog = new PageChangeLog($page); 230 $revisions = $pagelog->getRevisions(-1, 200); 231 $this->assertCount(6, $revisions); // external edit is not yet in changelog 232 // last revision 233 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 234 $this->assertEquals($expect, $lastRevInfo); 235 // current revision 236 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 237 $this->assertArrayHasKey('timestamp', $currentRevInfo, 'should be external revision'); 238 $expectExternal += $currentRevInfo; 239 $this->assertEquals($expectExternal, $currentRevInfo); 240 // attic 241 $this->assertFileExists(wikiFN($page, $lastRevInfo['date']), 'file missing in attic'); 242 $this->assertFileNotExists(wikiFN($page, $currentRevInfo['date']),'page does not yet exist in attic'); 243 244 $this->waitForTick(); // wait for new revision ID 245 246 // 1.9 save on top of external edit 247 saveWikiText($page, 'teststring6', '8th save', false); 248 clearstatcache(false, $file); 249 $newmod = filemtime($file); 250 $this->assertNotEquals($lastmod, $newmod); 251 $lastmod = $newmod; 252 $expect = array( 253 'date' => $lastmod, 254 'type' => DOKU_CHANGE_TYPE_EDIT, 255 'sum' => '8th save', 256 'sizechange' => -14, 257 ); 258 259 $pagelog = new PageChangeLog($page); 260 $revisions = $pagelog->getRevisions(-1, 200); 261 $this->assertCount(8, $revisions); // two more revisions now! 262 // last revision 263 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 264 $expect += $lastRevInfo; 265 $this->assertEquals($expect, $lastRevInfo); 266 // current revision 267 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 268 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 269 // attic 270 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 271 $files = glob(dirname(wikiFN($page, $lastRevInfo['date'])).'/'.$page.'.*'); 272 $this->assertCount(8, $files, 'detectExternalEdit() should not add too often old revs'); 273 274 } 275 276 /** 277 * Execute a whole bunch of saves on the same page and check the results 278 * using $this->handle_write() in event IO_WIKIPAGE_WRITE 279 * TEST 2 - create a page externally, while external edit in Test 1 280 * 2.1 create a page 281 * 2.2 delete 282 * 2.3 externally create the page 283 * 2.4 save on top of external edit 284 */ 285 function test_savesequence2() { 286 // add an additional delay when saving files to make sure 287 // nobody relies on the saving happening in the same second 288 /** @var $EVENT_HANDLER \dokuwiki\Extension\EventHandler */ 289 global $EVENT_HANDLER; 290 $EVENT_HANDLER->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'handle_write'); 291 292 $page = 'page2'; 293 $file = wikiFN($page); 294 295 // 2.1 create a page 296 $this->assertFileNotExists($file); 297 saveWikiText($page, 'teststring', 'Test 2, 1st save', false); 298 $this->assertFileExists($file); 299 $lastmod = filemtime($file); 300 $expect = array( 301 'date' => $lastmod, 302 'type' => DOKU_CHANGE_TYPE_CREATE, 303 'sum' => 'Test 2, 1st save', 304 'sizechange' => 10, // = strlen('teststring') 305 ); 306 307 $pagelog = new PageChangeLog($page); 308 $revisions = $pagelog->getRevisions(-1, 200); 309 $this->assertCount(1, $revisions); 310 // last revision 311 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 312 $expect += $lastRevInfo; 313 $this->assertEquals($expect, $lastRevInfo); 314 // current revision 315 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 316 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 317 // attic 318 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 319 320 $this->waitForTick(true); // wait for new revision ID 321 322 // 2.2 delete 323 saveWikiText($page, '', 'Test 2, 2nd save', false); 324 clearstatcache(false, $file); 325 $this->assertFileNotExists($file); 326 $expect = array( 327 //'date' => $lastmod, // ignore from lastRev assertion, but confirm attic file existence 328 'type' => DOKU_CHANGE_TYPE_DELETE, 329 'sum' => 'Test 2, 2nd save', 330 'sizechange' => -10, 331 ); 332 333 $pagelog = new PageChangeLog($page); 334 $revisions = $pagelog->getRevisions(-1, 200); 335 $this->assertCount(2, $revisions); 336 // last revision 337 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 338 $expect += $lastRevInfo; 339 $this->assertEquals($expect, $lastRevInfo); 340 // current revision 341 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 342 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 343 // attic 344 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 345 346 $this->waitForTick(); // wait for new revision ID 347 348 // 2.3 externally create the page 349 file_put_contents($file, 'teststring5'); 350 clearstatcache(false, $file); 351 $lastmod = filemtime($file); 352 $expectExternal = array( 353 'date' => $lastmod, 354 'type' => DOKU_CHANGE_TYPE_CREATE, 355 'sum' => 'created - external edit', 356 'sizechange' => 11, 357 ); 358 359 $pagelog = new PageChangeLog($page); 360 $revisions = $pagelog->getRevisions(-1, 200); 361 $this->assertCount(2, $revisions); // external edit is not yet in changelog 362 // last revision 363 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 364 $this->assertEquals($expect, $lastRevInfo); 365 // current revision 366 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 367 $this->assertArrayHasKey('timestamp', $currentRevInfo, 'should be external revision'); 368 $expectExternal += $currentRevInfo; 369 $this->assertEquals($expectExternal, $currentRevInfo); 370 // attic 371 $this->assertFileExists(wikiFN($page, $lastRevInfo['date']), 'file missing in attic'); 372 $this->assertFileNotExists(wikiFN($page, $currentRevInfo['date']),'page does not yet exist in attic'); 373 374 $this->waitForTick(); // wait for new revision ID 375 376 // 2.4 save on top of external edit 377 saveWikiText($page, 'teststring6', 'Test 2, 3rd save', false); 378 clearstatcache(false, $file); 379 $newmod = filemtime($file); 380 $this->assertNotEquals($lastmod, $newmod); 381 $lastmod = $newmod; 382 $expect = array( 383 'date' => $lastmod, 384 'type' => DOKU_CHANGE_TYPE_EDIT, 385 'sum' => 'Test 2, 3rd save', 386 'sizechange' => 0, 387 ); 388 389 $pagelog = new PageChangeLog($page); 390 $revisions = $pagelog->getRevisions(-1, 200); 391 $this->assertCount(4, $revisions); // two more revisions now! 392 // last revision 393 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 394 $expect += $lastRevInfo; 395 $this->assertEquals($expect, $lastRevInfo); 396 // current revision 397 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 398 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 399 // attic 400 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 401 $files = glob(dirname(wikiFN($page, $lastRevInfo['date'])).'/'.$page.'.*'); 402 $this->assertCount(4, $files, 'detectExternalEdit() should not add too often old revs'); 403 404 } 405 406 /** 407 * Execute a whole bunch of saves on the same page and check the results 408 * TEST 3 - typical page life of bundled page such as wiki/syntax 409 * 3.1 externally create a page 410 * 3.2 external edit 411 * 3.3 save on top of external edit 412 * 3.4 externally delete the page 413 */ 414 function test_savesequence3() { 415 $page = 'page3'; 416 $file = wikiFN($page); 417 418 // 3.1 externally create a page 419 $this->assertFileNotExists($file); 420 file_put_contents($file, 'teststring'); 421 clearstatcache(false, $file); 422 $lastmod = filemtime($file); 423 $expectExternal = array( 424 'date' => $lastmod, 425 'type' => DOKU_CHANGE_TYPE_CREATE, 426 'sum' => 'created - external edit', 427 'sizechange' => 10, 428 ); 429 430 $pagelog = new PageChangeLog($page); 431 $revisions = $pagelog->getRevisions(-1, 200); 432 $this->assertCount(0, $revisions); // external edit is not yet in changelog 433 // last revision 434 $this->assertFalse($pagelog->lastRevision(), 'changelog file does not yet exist'); 435 // current revision 436 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 437 $this->assertArrayHasKey('timestamp', $currentRevInfo, 'should be external revision'); 438 $expectExternal += $currentRevInfo; 439 $this->assertEquals($expectExternal, $currentRevInfo); 440 // attic 441 $this->assertFileNotExists(wikiFN($page, $currentRevInfo['date']),'page does not yet exist in attic'); 442 443 $this->waitForTick(true); // wait for new revision ID 444 445 // 3.2 external edit 446 file_put_contents($file, 'teststring external edit'); 447 clearstatcache(false, $file); 448 $newmod = filemtime($file); 449 $this->assertNotEquals($lastmod, $newmod); 450 $lastmod = $newmod; 451 $expectExternal = array( 452 'date' => $lastmod, 453 'type' => DOKU_CHANGE_TYPE_CREATE, 454 'sum' => 'created - external edit', 455 'sizechange' => 24, 456 ); 457 458 $pagelog = new PageChangeLog($page); 459 $revisions = $pagelog->getRevisions(-1, 200); 460 $this->assertCount(0, $revisions); // external edit is not yet in changelog 461 // last revision 462 $this->assertFalse($pagelog->lastRevision(), 'changelog file does not yet exist'); 463 // current revision 464 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 465 $this->assertArrayHasKey('timestamp', $currentRevInfo, 'should be external revision'); 466 $expectExternal += $currentRevInfo; 467 $this->assertEquals($expectExternal, $currentRevInfo); 468 // attic 469 $this->assertFileNotExists(wikiFN($page, $currentRevInfo['date']),'page does not yet exist in attic'); 470 471 $this->waitForTick(true); // wait for new revision ID 472 473 // 3.3 save on top of external edit 474 saveWikiText($page, 'teststring1', 'Test 3, first save', false); 475 clearstatcache(false, $file); 476 $newmod = filemtime($file); 477 $this->assertNotEquals($lastmod, $newmod); 478 $lastmod = $newmod; 479 $expect = array( 480 'date' => $lastmod, 481 'type' => DOKU_CHANGE_TYPE_EDIT, 482 'sum' => 'Test 3, first save', 483 'sizechange' => -13, 484 ); 485 486 $pagelog = new PageChangeLog($page); 487 $revisions = $pagelog->getRevisions(-1, 200); 488 $this->assertCount(2, $revisions); // two more revisions now! 489 // last revision 490 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 491 $expect += $lastRevInfo; 492 $this->assertEquals($expect, $lastRevInfo); 493 // current revision 494 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 495 $this->assertEquals($currentRevInfo, $lastRevInfo, 'current & last revs should be identical'); 496 // attic 497 $this->assertFileExists(wikiFN($page, $lastRevInfo['date'], 'file missing in attic')); 498 $files = glob(dirname(wikiFN($page, $lastRevInfo['date'])).'/'.$page.'.*'); 499 $this->assertCount(2, $files, 'detectExternalEdit() should not add too often old revs'); 500 501 $this->waitForTick(true); // wait for new revision ID 502 503 // 3.4 externally delete the page 504 unlink($file); 505 clearstatcache(false, $file); 506 $expectExternal = array( 507 //'date' => $lastmod, 508 'type' => DOKU_CHANGE_TYPE_DELETE, 509 'sum' => 'removed - external edit (Unknown date)', 510 'sizechange' => -11, 511 ); 512 513 $pagelog = new PageChangeLog($page); 514 $revisions = $pagelog->getRevisions(-1, 200); 515 $this->assertCount(2, $revisions); // two more revisions now! 516 // last revision 517 $lastRevInfo = $pagelog->getRevisionInfo($revisions[0]); 518 $this->assertEquals($expect, $lastRevInfo); 519 // current revision 520 $currentRevInfo = $pagelog->getCurrentRevisionInfo(); 521 $this->assertArrayHasKey('timestamp', $currentRevInfo, 'should be external revision'); 522 $expectExternal += $currentRevInfo; 523 $this->assertEquals($expectExternal, $currentRevInfo); 524 // attic 525 $this->assertFileNotExists(wikiFN($page, $currentRevInfo['date']),'page does not yet exist in attic'); 526 527 } 528 529} 530