UpdateRegistryTest.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <?php
  2. namespace Drupal\Tests\Core\Update;
  3. use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
  4. use Drupal\Core\Site\Settings;
  5. use Drupal\Core\Update\RemovedPostUpdateNameException;
  6. use Drupal\Core\Update\UpdateRegistry;
  7. use Drupal\Tests\UnitTestCase;
  8. use org\bovigo\vfs\vfsStream;
  9. /**
  10. * @coversDefaultClass \Drupal\Core\Update\UpdateRegistry
  11. * @group Update
  12. *
  13. * Note we load code, so isolate the tests.
  14. *
  15. * @runTestsInSeparateProcesses
  16. * @preserveGlobalState disabled
  17. */
  18. class UpdateRegistryTest extends UnitTestCase {
  19. /**
  20. * {@inheritdoc}
  21. */
  22. protected function setUp() {
  23. parent::setUp();
  24. $settings = [];
  25. $settings['extension_discovery_scan_tests'] = TRUE;
  26. new Settings($settings);
  27. }
  28. /**
  29. * Sets up some modules with some update functions.
  30. */
  31. protected function setupBasicModules() {
  32. $info_a = <<<'EOS'
  33. type: module
  34. name: Module A
  35. core_version_requirement: '*'
  36. EOS;
  37. $info_b = <<<'EOS'
  38. type: module
  39. name: Module B
  40. core_version_requirement: '*'
  41. EOS;
  42. $info_c = <<<'EOS'
  43. type: module
  44. name: Module C
  45. core_version_requirement: '*'
  46. EOS;
  47. $module_a = <<<'EOS'
  48. <?php
  49. /**
  50. * Module A update B.
  51. */
  52. function module_a_post_update_b() {
  53. }
  54. /**
  55. * Module A update A.
  56. */
  57. function module_a_post_update_a() {
  58. }
  59. EOS;
  60. $module_b = <<<'EOS'
  61. <?php
  62. /**
  63. * Module B update A.
  64. */
  65. function module_b_post_update_a() {
  66. }
  67. /**
  68. * Implements hook_removed_post_updates().
  69. */
  70. function module_b_removed_post_updates() {
  71. return [
  72. 'module_b_post_update_b' => '8.9.0',
  73. 'module_b_post_update_c' => '8.9.0',
  74. ];
  75. }
  76. EOS;
  77. $module_c = <<<'EOS'
  78. <?php
  79. /**
  80. * Module C update A.
  81. */
  82. function module_c_post_update_a() {
  83. }
  84. /**
  85. * Module C update B.
  86. */
  87. function module_c_post_update_b() {
  88. }
  89. /**
  90. * Implements hook_removed_post_updates().
  91. */
  92. function module_c_removed_post_updates() {
  93. return [
  94. 'module_c_post_update_b' => '8.9.0',
  95. 'module_c_post_update_c' => '8.9.0',
  96. ];
  97. }
  98. EOS;
  99. vfsStream::setup('drupal');
  100. vfsStream::create([
  101. 'sites' => [
  102. 'default' => [
  103. 'modules' => [
  104. 'module_a' => [
  105. 'module_a.post_update.php' => $module_a,
  106. 'module_a.info.yml' => $info_a,
  107. ],
  108. 'module_b' => [
  109. 'module_b.post_update.php' => $module_b,
  110. 'module_b.info.yml' => $info_b,
  111. ],
  112. 'module_c' => [
  113. 'module_c.post_update.php' => $module_c,
  114. 'module_c.info.yml' => $info_c,
  115. ],
  116. ],
  117. ],
  118. ],
  119. ]);
  120. }
  121. /**
  122. * @covers ::getPendingUpdateFunctions
  123. */
  124. public function testGetPendingUpdateFunctionsNoExistingUpdates() {
  125. $this->setupBasicModules();
  126. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  127. $key_value->get('existing_updates', [])->willReturn([]);
  128. $key_value = $key_value->reveal();
  129. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  130. 'module_a',
  131. 'module_b',
  132. ], $key_value, FALSE);
  133. $this->assertEquals([
  134. 'module_a_post_update_a',
  135. 'module_a_post_update_b',
  136. 'module_b_post_update_a',
  137. ], $update_registry->getPendingUpdateFunctions());
  138. }
  139. /**
  140. * @covers ::getPendingUpdateFunctions
  141. */
  142. public function testGetPendingUpdateFunctionsWithLoadedModulesButNotEnabled() {
  143. $this->setupBasicModules();
  144. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  145. $key_value->get('existing_updates', [])->willReturn([]);
  146. $key_value = $key_value->reveal();
  147. // Preload modules to ensure that ::getAvailableUpdateFunctions filters out
  148. // not enabled modules.
  149. include_once 'vfs://drupal/sites/default/modules/module_a/module_a.post_update.php';
  150. include_once 'vfs://drupal/sites/default/modules/module_b/module_b.post_update.php';
  151. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  152. 'module_a',
  153. ], $key_value, FALSE);
  154. $this->assertEquals([
  155. 'module_a_post_update_a',
  156. 'module_a_post_update_b',
  157. ], $update_registry->getPendingUpdateFunctions());
  158. }
  159. /**
  160. * @covers ::getPendingUpdateFunctions
  161. */
  162. public function testGetPendingUpdateFunctionsExistingUpdates() {
  163. $this->setupBasicModules();
  164. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  165. $key_value->get('existing_updates', [])->willReturn(['module_a_post_update_a']);
  166. $key_value = $key_value->reveal();
  167. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  168. 'module_a',
  169. 'module_b',
  170. ], $key_value, FALSE);
  171. $this->assertEquals(array_values([
  172. 'module_a_post_update_b',
  173. 'module_b_post_update_a',
  174. ]), array_values($update_registry->getPendingUpdateFunctions()));
  175. }
  176. /**
  177. * @covers ::getPendingUpdateInformation
  178. */
  179. public function testGetPendingUpdateInformation() {
  180. $this->setupBasicModules();
  181. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  182. $key_value->get('existing_updates', [])->willReturn([]);
  183. $key_value = $key_value->reveal();
  184. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  185. 'module_a',
  186. 'module_b',
  187. ], $key_value, FALSE);
  188. $expected = [];
  189. $expected['module_a']['pending']['a'] = 'Module A update A.';
  190. $expected['module_a']['pending']['b'] = 'Module A update B.';
  191. $expected['module_a']['start'] = 'a';
  192. $expected['module_b']['pending']['a'] = 'Module B update A.';
  193. $expected['module_b']['start'] = 'a';
  194. $this->assertEquals($expected, $update_registry->getPendingUpdateInformation());
  195. }
  196. /**
  197. * @covers ::getPendingUpdateInformation
  198. */
  199. public function testGetPendingUpdateInformationWithExistingUpdates() {
  200. $this->setupBasicModules();
  201. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  202. $key_value->get('existing_updates', [])->willReturn(['module_a_post_update_a']);
  203. $key_value = $key_value->reveal();
  204. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  205. 'module_a',
  206. 'module_b',
  207. ], $key_value, FALSE);
  208. $expected = [];
  209. $expected['module_a']['pending']['b'] = 'Module A update B.';
  210. $expected['module_a']['start'] = 'b';
  211. $expected['module_b']['pending']['a'] = 'Module B update A.';
  212. $expected['module_b']['start'] = 'a';
  213. $this->assertEquals($expected, $update_registry->getPendingUpdateInformation());
  214. }
  215. /**
  216. * @covers ::getPendingUpdateInformation
  217. */
  218. public function testGetPendingUpdateInformationWithRemovedUpdates() {
  219. $this->setupBasicModules();
  220. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  221. $key_value->get('existing_updates', [])->willReturn(['module_a_post_update_a']);
  222. $key_value = $key_value->reveal();
  223. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  224. 'module_c',
  225. ], $key_value, FALSE);
  226. $this->expectException(RemovedPostUpdateNameException::class);
  227. $update_registry->getPendingUpdateInformation();
  228. }
  229. /**
  230. * @covers ::getModuleUpdateFunctions
  231. */
  232. public function testGetModuleUpdateFunctions() {
  233. $this->setupBasicModules();
  234. $key_value = $this->prophesize(KeyValueStoreInterface::class)->reveal();
  235. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  236. 'module_a',
  237. 'module_b',
  238. ], $key_value, FALSE);
  239. $this->assertEquals(['module_a_post_update_a', 'module_a_post_update_b'], array_values($update_registry->getModuleUpdateFunctions('module_a')));
  240. $this->assertEquals(['module_b_post_update_a'], array_values($update_registry->getModuleUpdateFunctions('module_b')));
  241. }
  242. /**
  243. * @covers ::registerInvokedUpdates
  244. */
  245. public function testRegisterInvokedUpdatesWithoutExistingUpdates() {
  246. $this->setupBasicModules();
  247. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  248. $key_value->get('existing_updates', [])
  249. ->willReturn([])
  250. ->shouldBeCalledTimes(1);
  251. $key_value->set('existing_updates', ['module_a_post_update_a'])
  252. ->willReturn(NULL)
  253. ->shouldBeCalledTimes(1);
  254. $key_value = $key_value->reveal();
  255. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  256. 'module_a',
  257. 'module_b',
  258. ], $key_value, FALSE);
  259. $update_registry->registerInvokedUpdates(['module_a_post_update_a']);
  260. }
  261. /**
  262. * @covers ::registerInvokedUpdates
  263. */
  264. public function testRegisterInvokedUpdatesWithMultiple() {
  265. $this->setupBasicModules();
  266. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  267. $key_value->get('existing_updates', [])
  268. ->willReturn([])
  269. ->shouldBeCalledTimes(1);
  270. $key_value->set('existing_updates', ['module_a_post_update_a', 'module_a_post_update_b'])
  271. ->willReturn(NULL)
  272. ->shouldBeCalledTimes(1);
  273. $key_value = $key_value->reveal();
  274. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  275. 'module_a',
  276. 'module_b',
  277. ], $key_value, FALSE);
  278. $update_registry->registerInvokedUpdates(['module_a_post_update_a', 'module_a_post_update_b']);
  279. }
  280. /**
  281. * @covers ::registerInvokedUpdates
  282. */
  283. public function testRegisterInvokedUpdatesWithExistingUpdates() {
  284. $this->setupBasicModules();
  285. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  286. $key_value->get('existing_updates', [])
  287. ->willReturn(['module_a_post_update_b'])
  288. ->shouldBeCalledTimes(1);
  289. $key_value->set('existing_updates', ['module_a_post_update_b', 'module_a_post_update_a'])
  290. ->willReturn(NULL)
  291. ->shouldBeCalledTimes(1);
  292. $key_value = $key_value->reveal();
  293. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  294. 'module_a',
  295. 'module_b',
  296. ], $key_value, FALSE);
  297. $update_registry->registerInvokedUpdates(['module_a_post_update_a']);
  298. }
  299. /**
  300. * @covers ::filterOutInvokedUpdatesByModule
  301. */
  302. public function testFilterOutInvokedUpdatesByModule() {
  303. $this->setupBasicModules();
  304. $key_value = $this->prophesize(KeyValueStoreInterface::class);
  305. $key_value->get('existing_updates', [])
  306. ->willReturn(['module_a_post_update_b', 'module_a_post_update_a', 'module_b_post_update_a'])
  307. ->shouldBeCalledTimes(1);
  308. $key_value->set('existing_updates', ['module_b_post_update_a'])
  309. ->willReturn(NULL)
  310. ->shouldBeCalledTimes(1);
  311. $key_value = $key_value->reveal();
  312. $update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
  313. 'module_a',
  314. 'module_b',
  315. ], $key_value, FALSE);
  316. $update_registry->filterOutInvokedUpdatesByModule('module_a');
  317. }
  318. }