ActorMigrationTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. <?php
  2. use MediaWiki\User\UserIdentity;
  3. use MediaWiki\MediaWikiServices;
  4. use Wikimedia\TestingAccessWrapper;
  5. /**
  6. * @group Database
  7. * @covers ActorMigration
  8. */
  9. class ActorMigrationTest extends MediaWikiLangTestCase {
  10. protected $tablesUsed = [
  11. 'revision',
  12. 'revision_actor_temp',
  13. 'ipblocks',
  14. 'recentchanges',
  15. 'actor',
  16. ];
  17. /**
  18. * Create an ActorMigration for a particular stage
  19. * @param int $stage
  20. * @return ActorMigration
  21. */
  22. protected function makeMigration( $stage ) {
  23. return new ActorMigration( $stage );
  24. }
  25. /**
  26. * @dataProvider provideGetJoin
  27. * @param int $stage
  28. * @param string $key
  29. * @param array $expect
  30. */
  31. public function testGetJoin( $stage, $key, $expect ) {
  32. $m = $this->makeMigration( $stage );
  33. $result = $m->getJoin( $key );
  34. $this->assertEquals( $expect, $result );
  35. }
  36. public static function provideGetJoin() {
  37. return [
  38. 'Simple table, old' => [
  39. MIGRATION_OLD, 'rc_user', [
  40. 'tables' => [],
  41. 'fields' => [
  42. 'rc_user' => 'rc_user',
  43. 'rc_user_text' => 'rc_user_text',
  44. 'rc_actor' => 'NULL',
  45. ],
  46. 'joins' => [],
  47. ],
  48. ],
  49. 'Simple table, write-both' => [
  50. MIGRATION_WRITE_BOTH, 'rc_user', [
  51. 'tables' => [ 'actor_rc_user' => 'actor' ],
  52. 'fields' => [
  53. 'rc_user' => 'COALESCE( actor_rc_user.actor_user, rc_user )',
  54. 'rc_user_text' => 'COALESCE( actor_rc_user.actor_name, rc_user_text )',
  55. 'rc_actor' => 'rc_actor',
  56. ],
  57. 'joins' => [
  58. 'actor_rc_user' => [ 'LEFT JOIN', 'actor_rc_user.actor_id = rc_actor' ],
  59. ],
  60. ],
  61. ],
  62. 'Simple table, write-new' => [
  63. MIGRATION_WRITE_NEW, 'rc_user', [
  64. 'tables' => [ 'actor_rc_user' => 'actor' ],
  65. 'fields' => [
  66. 'rc_user' => 'COALESCE( actor_rc_user.actor_user, rc_user )',
  67. 'rc_user_text' => 'COALESCE( actor_rc_user.actor_name, rc_user_text )',
  68. 'rc_actor' => 'rc_actor',
  69. ],
  70. 'joins' => [
  71. 'actor_rc_user' => [ 'LEFT JOIN', 'actor_rc_user.actor_id = rc_actor' ],
  72. ],
  73. ],
  74. ],
  75. 'Simple table, new' => [
  76. MIGRATION_NEW, 'rc_user', [
  77. 'tables' => [ 'actor_rc_user' => 'actor' ],
  78. 'fields' => [
  79. 'rc_user' => 'actor_rc_user.actor_user',
  80. 'rc_user_text' => 'actor_rc_user.actor_name',
  81. 'rc_actor' => 'rc_actor',
  82. ],
  83. 'joins' => [
  84. 'actor_rc_user' => [ 'JOIN', 'actor_rc_user.actor_id = rc_actor' ],
  85. ],
  86. ],
  87. ],
  88. 'ipblocks, old' => [
  89. MIGRATION_OLD, 'ipb_by', [
  90. 'tables' => [],
  91. 'fields' => [
  92. 'ipb_by' => 'ipb_by',
  93. 'ipb_by_text' => 'ipb_by_text',
  94. 'ipb_by_actor' => 'NULL',
  95. ],
  96. 'joins' => [],
  97. ],
  98. ],
  99. 'ipblocks, write-both' => [
  100. MIGRATION_WRITE_BOTH, 'ipb_by', [
  101. 'tables' => [ 'actor_ipb_by' => 'actor' ],
  102. 'fields' => [
  103. 'ipb_by' => 'COALESCE( actor_ipb_by.actor_user, ipb_by )',
  104. 'ipb_by_text' => 'COALESCE( actor_ipb_by.actor_name, ipb_by_text )',
  105. 'ipb_by_actor' => 'ipb_by_actor',
  106. ],
  107. 'joins' => [
  108. 'actor_ipb_by' => [ 'LEFT JOIN', 'actor_ipb_by.actor_id = ipb_by_actor' ],
  109. ],
  110. ],
  111. ],
  112. 'ipblocks, write-new' => [
  113. MIGRATION_WRITE_NEW, 'ipb_by', [
  114. 'tables' => [ 'actor_ipb_by' => 'actor' ],
  115. 'fields' => [
  116. 'ipb_by' => 'COALESCE( actor_ipb_by.actor_user, ipb_by )',
  117. 'ipb_by_text' => 'COALESCE( actor_ipb_by.actor_name, ipb_by_text )',
  118. 'ipb_by_actor' => 'ipb_by_actor',
  119. ],
  120. 'joins' => [
  121. 'actor_ipb_by' => [ 'LEFT JOIN', 'actor_ipb_by.actor_id = ipb_by_actor' ],
  122. ],
  123. ],
  124. ],
  125. 'ipblocks, new' => [
  126. MIGRATION_NEW, 'ipb_by', [
  127. 'tables' => [ 'actor_ipb_by' => 'actor' ],
  128. 'fields' => [
  129. 'ipb_by' => 'actor_ipb_by.actor_user',
  130. 'ipb_by_text' => 'actor_ipb_by.actor_name',
  131. 'ipb_by_actor' => 'ipb_by_actor',
  132. ],
  133. 'joins' => [
  134. 'actor_ipb_by' => [ 'JOIN', 'actor_ipb_by.actor_id = ipb_by_actor' ],
  135. ],
  136. ],
  137. ],
  138. 'Revision, old' => [
  139. MIGRATION_OLD, 'rev_user', [
  140. 'tables' => [],
  141. 'fields' => [
  142. 'rev_user' => 'rev_user',
  143. 'rev_user_text' => 'rev_user_text',
  144. 'rev_actor' => 'NULL',
  145. ],
  146. 'joins' => [],
  147. ],
  148. ],
  149. 'Revision, write-both' => [
  150. MIGRATION_WRITE_BOTH, 'rev_user', [
  151. 'tables' => [
  152. 'temp_rev_user' => 'revision_actor_temp',
  153. 'actor_rev_user' => 'actor',
  154. ],
  155. 'fields' => [
  156. 'rev_user' => 'COALESCE( actor_rev_user.actor_user, rev_user )',
  157. 'rev_user_text' => 'COALESCE( actor_rev_user.actor_name, rev_user_text )',
  158. 'rev_actor' => 'temp_rev_user.revactor_actor',
  159. ],
  160. 'joins' => [
  161. 'temp_rev_user' => [ 'LEFT JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
  162. 'actor_rev_user' => [ 'LEFT JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ],
  163. ],
  164. ],
  165. ],
  166. 'Revision, write-new' => [
  167. MIGRATION_WRITE_NEW, 'rev_user', [
  168. 'tables' => [
  169. 'temp_rev_user' => 'revision_actor_temp',
  170. 'actor_rev_user' => 'actor',
  171. ],
  172. 'fields' => [
  173. 'rev_user' => 'COALESCE( actor_rev_user.actor_user, rev_user )',
  174. 'rev_user_text' => 'COALESCE( actor_rev_user.actor_name, rev_user_text )',
  175. 'rev_actor' => 'temp_rev_user.revactor_actor',
  176. ],
  177. 'joins' => [
  178. 'temp_rev_user' => [ 'LEFT JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
  179. 'actor_rev_user' => [ 'LEFT JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ],
  180. ],
  181. ],
  182. ],
  183. 'Revision, new' => [
  184. MIGRATION_NEW, 'rev_user', [
  185. 'tables' => [
  186. 'temp_rev_user' => 'revision_actor_temp',
  187. 'actor_rev_user' => 'actor',
  188. ],
  189. 'fields' => [
  190. 'rev_user' => 'actor_rev_user.actor_user',
  191. 'rev_user_text' => 'actor_rev_user.actor_name',
  192. 'rev_actor' => 'temp_rev_user.revactor_actor',
  193. ],
  194. 'joins' => [
  195. 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
  196. 'actor_rev_user' => [ 'JOIN', 'actor_rev_user.actor_id = temp_rev_user.revactor_actor' ],
  197. ],
  198. ],
  199. ],
  200. ];
  201. }
  202. /**
  203. * @dataProvider provideGetWhere
  204. * @param int $stage
  205. * @param string $key
  206. * @param UserIdentity[] $users
  207. * @param bool $useId
  208. * @param array $expect
  209. */
  210. public function testGetWhere( $stage, $key, $users, $useId, $expect ) {
  211. $expect['conds'] = '(' . implode( ') OR (', $expect['orconds'] ) . ')';
  212. if ( count( $users ) === 1 ) {
  213. $users = reset( $users );
  214. }
  215. $m = $this->makeMigration( $stage );
  216. $result = $m->getWhere( $this->db, $key, $users, $useId );
  217. $this->assertEquals( $expect, $result );
  218. }
  219. public function provideGetWhere() {
  220. $makeUserIdentity = function ( $id, $name, $actor ) {
  221. $u = $this->getMock( UserIdentity::class );
  222. $u->method( 'getId' )->willReturn( $id );
  223. $u->method( 'getName' )->willReturn( $name );
  224. $u->method( 'getActorId' )->willReturn( $actor );
  225. return $u;
  226. };
  227. $genericUser = [ $makeUserIdentity( 1, 'User1', 11 ) ];
  228. $complicatedUsers = [
  229. $makeUserIdentity( 1, 'User1', 11 ),
  230. $makeUserIdentity( 2, 'User2', 12 ),
  231. $makeUserIdentity( 3, 'User3', 0 ),
  232. $makeUserIdentity( 0, '192.168.12.34', 34 ),
  233. $makeUserIdentity( 0, '192.168.12.35', 0 ),
  234. ];
  235. return [
  236. 'Simple table, old' => [
  237. MIGRATION_OLD, 'rc_user', $genericUser, true, [
  238. 'tables' => [],
  239. 'orconds' => [ 'userid' => "rc_user = '1'" ],
  240. 'joins' => [],
  241. ],
  242. ],
  243. 'Simple table, write-both' => [
  244. MIGRATION_WRITE_BOTH, 'rc_user', $genericUser, true, [
  245. 'tables' => [],
  246. 'orconds' => [
  247. 'actor' => "rc_actor = '11'",
  248. 'userid' => "rc_actor = '0' AND rc_user = '1'"
  249. ],
  250. 'joins' => [],
  251. ],
  252. ],
  253. 'Simple table, write-new' => [
  254. MIGRATION_WRITE_NEW, 'rc_user', $genericUser, true, [
  255. 'tables' => [],
  256. 'orconds' => [
  257. 'actor' => "rc_actor = '11'",
  258. 'userid' => "rc_actor = '0' AND rc_user = '1'"
  259. ],
  260. 'joins' => [],
  261. ],
  262. ],
  263. 'Simple table, new' => [
  264. MIGRATION_NEW, 'rc_user', $genericUser, true, [
  265. 'tables' => [],
  266. 'orconds' => [ 'actor' => "rc_actor = '11'" ],
  267. 'joins' => [],
  268. ],
  269. ],
  270. 'ipblocks, old' => [
  271. MIGRATION_OLD, 'ipb_by', $genericUser, true, [
  272. 'tables' => [],
  273. 'orconds' => [ 'userid' => "ipb_by = '1'" ],
  274. 'joins' => [],
  275. ],
  276. ],
  277. 'ipblocks, write-both' => [
  278. MIGRATION_WRITE_BOTH, 'ipb_by', $genericUser, true, [
  279. 'tables' => [],
  280. 'orconds' => [
  281. 'actor' => "ipb_by_actor = '11'",
  282. 'userid' => "ipb_by_actor = '0' AND ipb_by = '1'"
  283. ],
  284. 'joins' => [],
  285. ],
  286. ],
  287. 'ipblocks, write-new' => [
  288. MIGRATION_WRITE_NEW, 'ipb_by', $genericUser, true, [
  289. 'tables' => [],
  290. 'orconds' => [
  291. 'actor' => "ipb_by_actor = '11'",
  292. 'userid' => "ipb_by_actor = '0' AND ipb_by = '1'"
  293. ],
  294. 'joins' => [],
  295. ],
  296. ],
  297. 'ipblocks, new' => [
  298. MIGRATION_NEW, 'ipb_by', $genericUser, true, [
  299. 'tables' => [],
  300. 'orconds' => [ 'actor' => "ipb_by_actor = '11'" ],
  301. 'joins' => [],
  302. ],
  303. ],
  304. 'Revision, old' => [
  305. MIGRATION_OLD, 'rev_user', $genericUser, true, [
  306. 'tables' => [],
  307. 'orconds' => [ 'userid' => "rev_user = '1'" ],
  308. 'joins' => [],
  309. ],
  310. ],
  311. 'Revision, write-both' => [
  312. MIGRATION_WRITE_BOTH, 'rev_user', $genericUser, true, [
  313. 'tables' => [
  314. 'temp_rev_user' => 'revision_actor_temp',
  315. ],
  316. 'orconds' => [
  317. 'actor' =>
  318. "(temp_rev_user.revactor_actor IS NOT NULL) AND temp_rev_user.revactor_actor = '11'",
  319. 'userid' => "temp_rev_user.revactor_actor IS NULL AND rev_user = '1'"
  320. ],
  321. 'joins' => [
  322. 'temp_rev_user' => [ 'LEFT JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
  323. ],
  324. ],
  325. ],
  326. 'Revision, write-new' => [
  327. MIGRATION_WRITE_NEW, 'rev_user', $genericUser, true, [
  328. 'tables' => [
  329. 'temp_rev_user' => 'revision_actor_temp',
  330. ],
  331. 'orconds' => [
  332. 'actor' =>
  333. "(temp_rev_user.revactor_actor IS NOT NULL) AND temp_rev_user.revactor_actor = '11'",
  334. 'userid' => "temp_rev_user.revactor_actor IS NULL AND rev_user = '1'"
  335. ],
  336. 'joins' => [
  337. 'temp_rev_user' => [ 'LEFT JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
  338. ],
  339. ],
  340. ],
  341. 'Revision, new' => [
  342. MIGRATION_NEW, 'rev_user', $genericUser, true, [
  343. 'tables' => [
  344. 'temp_rev_user' => 'revision_actor_temp',
  345. ],
  346. 'orconds' => [ 'actor' => "temp_rev_user.revactor_actor = '11'" ],
  347. 'joins' => [
  348. 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ],
  349. ],
  350. ],
  351. ],
  352. 'Multiple users, old' => [
  353. MIGRATION_OLD, 'rc_user', $complicatedUsers, true, [
  354. 'tables' => [],
  355. 'orconds' => [
  356. 'userid' => "rc_user IN ('1','2','3') ",
  357. 'username' => "rc_user_text IN ('192.168.12.34','192.168.12.35') "
  358. ],
  359. 'joins' => [],
  360. ],
  361. ],
  362. 'Multiple users, write-both' => [
  363. MIGRATION_WRITE_BOTH, 'rc_user', $complicatedUsers, true, [
  364. 'tables' => [],
  365. 'orconds' => [
  366. 'actor' => "rc_actor IN ('11','12','34') ",
  367. 'userid' => "rc_actor = '0' AND rc_user IN ('1','2','3') ",
  368. 'username' => "rc_actor = '0' AND rc_user_text IN ('192.168.12.34','192.168.12.35') "
  369. ],
  370. 'joins' => [],
  371. ],
  372. ],
  373. 'Multiple users, write-new' => [
  374. MIGRATION_WRITE_NEW, 'rc_user', $complicatedUsers, true, [
  375. 'tables' => [],
  376. 'orconds' => [
  377. 'actor' => "rc_actor IN ('11','12','34') ",
  378. 'userid' => "rc_actor = '0' AND rc_user IN ('1','2','3') ",
  379. 'username' => "rc_actor = '0' AND rc_user_text IN ('192.168.12.34','192.168.12.35') "
  380. ],
  381. 'joins' => [],
  382. ],
  383. ],
  384. 'Multiple users, new' => [
  385. MIGRATION_NEW, 'rc_user', $complicatedUsers, true, [
  386. 'tables' => [],
  387. 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ],
  388. 'joins' => [],
  389. ],
  390. ],
  391. 'Multiple users, no use ID, old' => [
  392. MIGRATION_OLD, 'rc_user', $complicatedUsers, false, [
  393. 'tables' => [],
  394. 'orconds' => [
  395. 'username' => "rc_user_text IN ('User1','User2','User3','192.168.12.34','192.168.12.35') "
  396. ],
  397. 'joins' => [],
  398. ],
  399. ],
  400. 'Multiple users, write-both' => [
  401. MIGRATION_WRITE_BOTH, 'rc_user', $complicatedUsers, false, [
  402. 'tables' => [],
  403. 'orconds' => [
  404. 'actor' => "rc_actor IN ('11','12','34') ",
  405. 'username' => "rc_actor = '0' AND "
  406. . "rc_user_text IN ('User1','User2','User3','192.168.12.34','192.168.12.35') "
  407. ],
  408. 'joins' => [],
  409. ],
  410. ],
  411. 'Multiple users, write-new' => [
  412. MIGRATION_WRITE_NEW, 'rc_user', $complicatedUsers, false, [
  413. 'tables' => [],
  414. 'orconds' => [
  415. 'actor' => "rc_actor IN ('11','12','34') ",
  416. 'username' => "rc_actor = '0' AND "
  417. . "rc_user_text IN ('User1','User2','User3','192.168.12.34','192.168.12.35') "
  418. ],
  419. 'joins' => [],
  420. ],
  421. ],
  422. 'Multiple users, new' => [
  423. MIGRATION_NEW, 'rc_user', $complicatedUsers, false, [
  424. 'tables' => [],
  425. 'orconds' => [ 'actor' => "rc_actor IN ('11','12','34') " ],
  426. 'joins' => [],
  427. ],
  428. ],
  429. ];
  430. }
  431. /**
  432. * @dataProvider provideInsertRoundTrip
  433. * @param string $table
  434. * @param string $key
  435. * @param string $pk
  436. * @param array $extraFields
  437. */
  438. public function testInsertRoundTrip( $table, $key, $pk, $extraFields ) {
  439. $u = $this->getTestUser()->getUser();
  440. $user = $this->getMock( UserIdentity::class );
  441. $user->method( 'getId' )->willReturn( $u->getId() );
  442. $user->method( 'getName' )->willReturn( $u->getName() );
  443. if ( $u->getActorId( $this->db ) ) {
  444. $user->method( 'getActorId' )->willReturn( $u->getActorId() );
  445. } else {
  446. $this->db->insert(
  447. 'actor',
  448. [ 'actor_user' => $u->getId(), 'actor_name' => $u->getName() ],
  449. __METHOD__
  450. );
  451. $user->method( 'getActorId' )->willReturn( $this->db->insertId() );
  452. }
  453. $stages = [
  454. MIGRATION_OLD => [ MIGRATION_OLD, MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW ],
  455. MIGRATION_WRITE_BOTH => [ MIGRATION_OLD, MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW,
  456. MIGRATION_NEW ],
  457. MIGRATION_WRITE_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
  458. MIGRATION_NEW => [ MIGRATION_WRITE_BOTH, MIGRATION_WRITE_NEW, MIGRATION_NEW ],
  459. ];
  460. $nameKey = $key . '_text';
  461. $actorKey = $key === 'ipb_by' ? 'ipb_by_actor' : substr( $key, 0, -5 ) . '_actor';
  462. foreach ( $stages as $writeStage => $possibleReadStages ) {
  463. if ( $key === 'ipb_by' ) {
  464. $extraFields['ipb_address'] = __CLASS__ . "#$writeStage";
  465. }
  466. $w = $this->makeMigration( $writeStage );
  467. $usesTemp = $key === 'rev_user';
  468. if ( $usesTemp ) {
  469. list( $fields, $callback ) = $w->getInsertValuesWithTempTable( $this->db, $key, $user );
  470. } else {
  471. $fields = $w->getInsertValues( $this->db, $key, $user );
  472. }
  473. if ( $writeStage <= MIGRATION_WRITE_BOTH ) {
  474. $this->assertSame( $user->getId(), $fields[$key], "old field, stage=$writeStage" );
  475. $this->assertSame( $user->getName(), $fields[$nameKey], "old field, stage=$writeStage" );
  476. } else {
  477. $this->assertArrayNotHasKey( $key, $fields, "old field, stage=$writeStage" );
  478. $this->assertArrayNotHasKey( $nameKey, $fields, "old field, stage=$writeStage" );
  479. }
  480. if ( $writeStage >= MIGRATION_WRITE_BOTH && !$usesTemp ) {
  481. $this->assertSame( $user->getActorId(), $fields[$actorKey], "new field, stage=$writeStage" );
  482. } else {
  483. $this->assertArrayNotHasKey( $actorKey, $fields, "new field, stage=$writeStage" );
  484. }
  485. $this->db->insert( $table, $extraFields + $fields, __METHOD__ );
  486. $id = $this->db->insertId();
  487. if ( $usesTemp ) {
  488. $callback( $id, $extraFields );
  489. }
  490. foreach ( $possibleReadStages as $readStage ) {
  491. $r = $this->makeMigration( $readStage );
  492. $queryInfo = $r->getJoin( $key );
  493. $row = $this->db->selectRow(
  494. [ $table ] + $queryInfo['tables'],
  495. $queryInfo['fields'],
  496. [ $pk => $id ],
  497. __METHOD__,
  498. [],
  499. $queryInfo['joins']
  500. );
  501. $this->assertSame( $user->getId(), (int)$row->$key, "w=$writeStage, r=$readStage, id" );
  502. $this->assertSame( $user->getName(), $row->$nameKey, "w=$writeStage, r=$readStage, name" );
  503. $this->assertSame(
  504. $readStage === MIGRATION_OLD || $writeStage === MIGRATION_OLD ? 0 : $user->getActorId(),
  505. (int)$row->$actorKey,
  506. "w=$writeStage, r=$readStage, actor"
  507. );
  508. }
  509. }
  510. }
  511. public static function provideInsertRoundTrip() {
  512. $db = wfGetDB( DB_REPLICA ); // for timestamps
  513. $ipbfields = [
  514. ];
  515. $revfields = [
  516. ];
  517. return [
  518. 'recentchanges' => [ 'recentchanges', 'rc_user', 'rc_id', [
  519. 'rc_timestamp' => $db->timestamp(),
  520. 'rc_namespace' => 0,
  521. 'rc_title' => 'Test',
  522. 'rc_this_oldid' => 42,
  523. 'rc_last_oldid' => 41,
  524. 'rc_source' => 'test',
  525. ] ],
  526. 'ipblocks' => [ 'ipblocks', 'ipb_by', 'ipb_id', [
  527. 'ipb_range_start' => '',
  528. 'ipb_range_end' => '',
  529. 'ipb_timestamp' => $db->timestamp(),
  530. 'ipb_expiry' => $db->getInfinity(),
  531. ] ],
  532. 'revision' => [ 'revision', 'rev_user', 'rev_id', [
  533. 'rev_page' => 42,
  534. 'rev_text_id' => 42,
  535. 'rev_len' => 0,
  536. 'rev_timestamp' => $db->timestamp(),
  537. ] ],
  538. ];
  539. }
  540. public static function provideStages() {
  541. return [
  542. 'MIGRATION_OLD' => [ MIGRATION_OLD ],
  543. 'MIGRATION_WRITE_BOTH' => [ MIGRATION_WRITE_BOTH ],
  544. 'MIGRATION_WRITE_NEW' => [ MIGRATION_WRITE_NEW ],
  545. 'MIGRATION_NEW' => [ MIGRATION_NEW ],
  546. ];
  547. }
  548. /**
  549. * @dataProvider provideStages
  550. * @param int $stage
  551. * @expectedException InvalidArgumentException
  552. * @expectedExceptionMessage Must use getInsertValuesWithTempTable() for rev_user
  553. */
  554. public function testInsertWrong( $stage ) {
  555. $m = $this->makeMigration( $stage );
  556. $m->getInsertValues( $this->db, 'rev_user', $this->getTestUser()->getUser() );
  557. }
  558. /**
  559. * @dataProvider provideStages
  560. * @param int $stage
  561. * @expectedException InvalidArgumentException
  562. * @expectedExceptionMessage Must use getInsertValues() for rc_user
  563. */
  564. public function testInsertWithTempTableWrong( $stage ) {
  565. $m = $this->makeMigration( $stage );
  566. $m->getInsertValuesWithTempTable( $this->db, 'rc_user', $this->getTestUser()->getUser() );
  567. }
  568. /**
  569. * @dataProvider provideStages
  570. * @param int $stage
  571. */
  572. public function testInsertWithTempTableDeprecated( $stage ) {
  573. $wrap = TestingAccessWrapper::newFromClass( ActorMigration::class );
  574. $wrap->formerTempTables += [ 'rc_user' => '1.30' ];
  575. $this->hideDeprecated( 'ActorMigration::getInsertValuesWithTempTable for rc_user' );
  576. $m = $this->makeMigration( $stage );
  577. list( $fields, $callback )
  578. = $m->getInsertValuesWithTempTable( $this->db, 'rc_user', $this->getTestUser()->getUser() );
  579. $this->assertTrue( is_callable( $callback ) );
  580. }
  581. /**
  582. * @dataProvider provideStages
  583. * @param int $stage
  584. * @expectedException InvalidArgumentException
  585. * @expectedExceptionMessage $extra[rev_timestamp] is not provided
  586. */
  587. public function testInsertWithTempTableCallbackMissingFields( $stage ) {
  588. $m = $this->makeMigration( $stage );
  589. list( $fields, $callback )
  590. = $m->getInsertValuesWithTempTable( $this->db, 'rev_user', $this->getTestUser()->getUser() );
  591. $callback( 1, [] );
  592. }
  593. public function testInsertUserIdentity() {
  594. $user = $this->getTestUser()->getUser();
  595. $userIdentity = $this->getMock( UserIdentity::class );
  596. $userIdentity->method( 'getId' )->willReturn( $user->getId() );
  597. $userIdentity->method( 'getName' )->willReturn( $user->getName() );
  598. $userIdentity->method( 'getActorId' )->willReturn( 0 );
  599. list( $cFields, $cCallback ) = MediaWikiServices::getInstance()->getCommentStore()
  600. ->insertWithTempTable( $this->db, 'rev_comment', '' );
  601. $m = $this->makeMigration( MIGRATION_WRITE_BOTH );
  602. list( $fields, $callback ) =
  603. $m->getInsertValuesWithTempTable( $this->db, 'rev_user', $userIdentity );
  604. $extraFields = [
  605. 'rev_page' => 42,
  606. 'rev_text_id' => 42,
  607. 'rev_len' => 0,
  608. 'rev_timestamp' => $this->db->timestamp(),
  609. ] + $cFields;
  610. $this->db->insert( 'revision', $extraFields + $fields, __METHOD__ );
  611. $id = $this->db->insertId();
  612. $callback( $id, $extraFields );
  613. $cCallback( $id );
  614. $qi = Revision::getQueryInfo();
  615. $row = $this->db->selectRow(
  616. $qi['tables'], $qi['fields'], [ 'rev_id' => $id ], __METHOD__, [], $qi['joins']
  617. );
  618. $this->assertSame( $user->getId(), (int)$row->rev_user );
  619. $this->assertSame( $user->getName(), $row->rev_user_text );
  620. $this->assertSame( $user->getActorId(), (int)$row->rev_actor );
  621. $m = $this->makeMigration( MIGRATION_WRITE_BOTH );
  622. $fields = $m->getInsertValues( $this->db, 'dummy_user', $userIdentity );
  623. $this->assertSame( $user->getId(), $fields['dummy_user'] );
  624. $this->assertSame( $user->getName(), $fields['dummy_user_text'] );
  625. $this->assertSame( $user->getActorId(), $fields['dummy_actor'] );
  626. }
  627. public function testConstructor() {
  628. $m = ActorMigration::newMigration();
  629. $this->assertInstanceOf( ActorMigration::class, $m );
  630. $this->assertSame( $m, ActorMigration::newMigration() );
  631. }
  632. /**
  633. * @dataProvider provideIsAnon
  634. * @param int $stage
  635. * @param string $isAnon
  636. * @param string $isNotAnon
  637. */
  638. public function testIsAnon( $stage, $isAnon, $isNotAnon ) {
  639. $m = $this->makeMigration( $stage );
  640. $this->assertSame( $isAnon, $m->isAnon( 'foo' ) );
  641. $this->assertSame( $isNotAnon, $m->isNotAnon( 'foo' ) );
  642. }
  643. public static function provideIsAnon() {
  644. return [
  645. 'MIGRATION_OLD' => [ MIGRATION_OLD, 'foo = 0', 'foo != 0' ],
  646. 'MIGRATION_WRITE_BOTH' => [ MIGRATION_WRITE_BOTH, 'foo = 0', 'foo != 0' ],
  647. 'MIGRATION_WRITE_NEW' => [ MIGRATION_WRITE_NEW, 'foo = 0', 'foo != 0' ],
  648. 'MIGRATION_NEW' => [ MIGRATION_NEW, 'foo IS NULL', 'foo IS NOT NULL' ],
  649. ];
  650. }
  651. }