3 namespace Drupal\Tests\system\Functional\Entity\Update;
5 use Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException;
6 use Drupal\entity_test\Entity\EntityTest;
7 use Drupal\Tests\BrowserTestBase;
8 use Drupal\Tests\system\Functional\Update\DbUpdatesTrait;
11 * Tests performing entity updates through the Update API.
15 class UpdateApiEntityDefinitionUpdateTest extends BrowserTestBase {
22 protected static $modules = ['entity_test'];
27 * @var \Drupal\Core\Entity\EntityManagerInterface
29 protected $entityManager;
32 * The entity definition update manager.
34 * @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
36 protected $updatesManager;
42 protected function setUp() {
45 $this->entityManager = $this->container->get('entity.manager');
46 $this->updatesManager = $this->container->get('entity.definition_update_manager');
48 $admin = $this->drupalCreateUser([], FALSE, TRUE);
49 $this->drupalLogin($admin);
53 * Tests that individual updates applied sequentially work as expected.
55 public function testSingleUpdates() {
56 // Create a test entity.
57 $user_ids = [mt_rand(), mt_rand()];
58 $entity = EntityTest::create(['name' => $this->randomString(), 'user_id' => $user_ids]);
61 // Check that only a single value is stored for 'user_id'.
62 $entity = $this->reloadEntity($entity);
63 $this->assertEqual(count($entity->user_id), 1);
64 $this->assertEqual($entity->user_id->target_id, $user_ids[0]);
66 // Make 'user_id' multiple by applying updates.
67 $this->enableUpdates('entity_test', 'entity_definition_updates', 8001);
68 $this->applyUpdates();
70 // Ensure the 'entity_test__user_id' table got created.
71 $this->assertTrue(\Drupal::database()->schema()->tableExists('entity_test__user_id'));
73 // Check that data was correctly migrated.
74 $entity = $this->reloadEntity($entity);
75 $this->assertEqual(count($entity->user_id), 1);
76 $this->assertEqual($entity->user_id->target_id, $user_ids[0]);
78 // Store multiple data and check it is correctly stored.
79 $entity->user_id = $user_ids;
81 $entity = $this->reloadEntity($entity);
82 $this->assertEqual(count($entity->user_id), 2);
83 $this->assertEqual($entity->user_id[0]->target_id, $user_ids[0]);
84 $this->assertEqual($entity->user_id[1]->target_id, $user_ids[1]);
86 // Make 'user_id' single again by applying updates.
87 $this->enableUpdates('entity_test', 'entity_definition_updates', 8002);
88 $this->applyUpdates();
90 // Check that data was correctly migrated/dropped.
91 $entity = $this->reloadEntity($entity);
92 $this->assertEqual(count($entity->user_id), 1);
93 $this->assertEqual($entity->user_id->target_id, $user_ids[0]);
95 // Check that only a single value is stored for 'user_id' again.
96 $entity->user_id = $user_ids;
98 $entity = $this->reloadEntity($entity);
99 $this->assertEqual(count($entity->user_id), 1);
100 $this->assertEqual($entity->user_id[0]->target_id, $user_ids[0]);
104 * Tests that multiple updates applied in bulk work as expected.
106 public function testMultipleUpdates() {
107 // Create a test entity.
108 $user_ids = [mt_rand(), mt_rand()];
109 $entity = EntityTest::create(['name' => $this->randomString(), 'user_id' => $user_ids]);
112 // Check that only a single value is stored for 'user_id'.
113 $entity = $this->reloadEntity($entity);
114 $this->assertEqual(count($entity->user_id), 1);
115 $this->assertEqual($entity->user_id->target_id, $user_ids[0]);
117 // Make 'user_id' multiple and then single again by applying updates.
118 $this->enableUpdates('entity_test', 'entity_definition_updates', 8002);
119 $this->applyUpdates();
121 // Check that data was correctly migrated back and forth.
122 $entity = $this->reloadEntity($entity);
123 $this->assertEqual(count($entity->user_id), 1);
124 $this->assertEqual($entity->user_id->target_id, $user_ids[0]);
126 // Check that only a single value is stored for 'user_id' again.
127 $entity->user_id = $user_ids;
129 $entity = $this->reloadEntity($entity);
130 $this->assertEqual(count($entity->user_id), 1);
131 $this->assertEqual($entity->user_id[0]->target_id, $user_ids[0]);
135 * Tests that entity updates are correctly reported in the status report page.
137 public function testStatusReport() {
138 // Create a test entity.
139 $entity = EntityTest::create(['name' => $this->randomString(), 'user_id' => mt_rand()]);
142 // Check that the status report initially displays no error.
143 $this->drupalGet('admin/reports/status');
144 $this->assertNoRaw('Out of date');
145 $this->assertNoRaw('Mismatched entity and/or field definitions');
147 // Enable an entity update and check that we have a dedicated status report
149 $this->container->get('state')->set('entity_test.remove_name_field', TRUE);
150 $this->drupalGet('admin/reports/status');
151 $this->assertNoRaw('Out of date');
152 $this->assertRaw('Mismatched entity and/or field definitions');
154 // Enable a db update and check that now the entity update status report
155 // item is no longer displayed. We assume an update function will fix the
157 $this->enableUpdates('entity_test', 'status_report', 8001);
158 $this->drupalGet('admin/reports/status');
159 $this->assertRaw('Out of date');
160 $this->assertRaw('Mismatched entity and/or field definitions');
162 // Apply db updates and check that entity updates were not applied.
163 $this->applyUpdates();
164 $this->drupalGet('admin/reports/status');
165 $this->assertNoRaw('Out of date');
166 $this->assertRaw('Mismatched entity and/or field definitions');
168 // Check that en exception would be triggered when trying to apply them with
170 $message = 'Entity updates cannot run if entity data exists.';
172 $this->updatesManager->applyUpdates();
173 $this->fail($message);
175 catch (FieldStorageDefinitionUpdateForbiddenException $e) {
176 $this->pass($message);
179 // Check the status report is the same after trying to apply updates.
180 $this->drupalGet('admin/reports/status');
181 $this->assertNoRaw('Out of date');
182 $this->assertRaw('Mismatched entity and/or field definitions');
184 // Delete entity data, enable a new update, run updates again and check that
185 // entity updates were not applied even when no data exists.
187 $this->enableUpdates('entity_test', 'status_report', 8002);
188 $this->applyUpdates();
189 $this->drupalGet('admin/reports/status');
190 $this->assertNoRaw('Out of date');
191 $this->assertRaw('Mismatched entity and/or field definitions');
195 * Reloads the specified entity.
197 * @param \Drupal\entity_test\Entity\EntityTest $entity
200 * @return \Drupal\entity_test\Entity\EntityTest
201 * The reloaded entity object.
203 protected function reloadEntity(EntityTest $entity) {
204 $this->entityManager->useCaches(FALSE);
205 $this->entityManager->getStorage('entity_test')->resetCache([$entity->id()]);
206 return EntityTest::load($entity->id());