You are here

public function FieldableEntityDefinitionUpdateTest::testFieldableEntityTypeUpdatesErrorHandling in Drupal 9

Same name and namespace in other branches
  1. 8 core/tests/Drupal/KernelTests/Core/Entity/FieldableEntityDefinitionUpdateTest.php \Drupal\KernelTests\Core\Entity\FieldableEntityDefinitionUpdateTest::testFieldableEntityTypeUpdatesErrorHandling()

Tests that a failed entity schema update preserves the existing data.

File

core/tests/Drupal/KernelTests/Core/Entity/FieldableEntityDefinitionUpdateTest.php, line 652

Class

FieldableEntityDefinitionUpdateTest
Tests EntityDefinitionUpdateManager's fieldable entity update functionality.

Namespace

Drupal\KernelTests\Core\Entity

Code

public function testFieldableEntityTypeUpdatesErrorHandling() {
  $schema = $this->database
    ->schema();

  // First, convert the entity type to be translatable for better coverage and
  // insert some initial data.
  $entity_type = $this
    ->getUpdatedEntityTypeDefinition(FALSE, TRUE);
  $field_storage_definitions = $this
    ->getUpdatedFieldStorageDefinitions(FALSE, TRUE);
  $this->entityDefinitionUpdateManager
    ->updateFieldableEntityType($entity_type, $field_storage_definitions);
  $this
    ->assertEntityTypeSchema(FALSE, TRUE);
  $this
    ->insertData(FALSE, TRUE);
  $tables = $schema
    ->findTables('old_%');
  $this
    ->assertCount(4, $tables);
  foreach ($tables as $table) {
    $schema
      ->dropTable($table);
  }
  $original_entity_type = $this->lastInstalledSchemaRepository
    ->getLastInstalledDefinition('entity_test_update');
  $original_storage_definitions = $this->lastInstalledSchemaRepository
    ->getLastInstalledFieldStorageDefinitions('entity_test_update');
  $original_entity_schema_data = $this->installedStorageSchema
    ->get('entity_test_update.entity_schema_data', []);
  $original_field_schema_data = [];
  foreach ($original_storage_definitions as $storage_definition) {
    $original_field_schema_data[$storage_definition
      ->getName()] = $this->installedStorageSchema
      ->get('entity_test_update.field_schema_data.' . $storage_definition
      ->getName(), []);
  }

  // Check that entity type is not revisionable prior to running the update
  // process.
  $this
    ->assertFalse($entity_type
    ->isRevisionable());

  // Make the update throw an exception during the entity save process.
  \Drupal::state()
    ->set('entity_test_update.throw_exception', TRUE);
  $this
    ->expectException(EntityStorageException::class);
  $this
    ->expectExceptionMessage('The entity update process failed while processing the entity type entity_test_update, ID: 1.');
  try {
    $updated_entity_type = $this
      ->getUpdatedEntityTypeDefinition(TRUE, TRUE);
    $updated_field_storage_definitions = $this
      ->getUpdatedFieldStorageDefinitions(TRUE, TRUE);

    // Simulate a batch run since we are converting the entities one by one.
    $sandbox = [];
    do {
      $this->entityDefinitionUpdateManager
        ->updateFieldableEntityType($updated_entity_type, $updated_field_storage_definitions, $sandbox);
    } while ($sandbox['#finished'] != 1);
  } catch (EntityStorageException $e) {
    throw $e;
  } finally {
    $this
      ->assertSame('Peekaboo!', $e
      ->getPrevious()
      ->getMessage());

    // Check that the last installed entity type definition is kept as
    // non-revisionable.
    $new_entity_type = $this->lastInstalledSchemaRepository
      ->getLastInstalledDefinition('entity_test_update');
    $this
      ->assertFalse($new_entity_type
      ->isRevisionable(), 'The entity type is kept unchanged.');

    // Check that the last installed field storage definitions did not change by
    // looking at the 'langcode' field, which is updated automatically.
    $new_storage_definitions = $this->lastInstalledSchemaRepository
      ->getLastInstalledFieldStorageDefinitions('entity_test_update');
    $langcode_key = $original_entity_type
      ->getKey('langcode');
    $this
      ->assertEquals($original_storage_definitions[$langcode_key]
      ->isRevisionable(), $new_storage_definitions[$langcode_key]
      ->isRevisionable(), "The 'langcode' field is kept unchanged.");

    /** @var \Drupal\Core\Entity\Sql\SqlEntityStorageInterface $storage */
    $storage = $this->entityTypeManager
      ->getStorage('entity_test_update');
    $table_mapping = $storage
      ->getTableMapping();

    // Check that installed storage schema did not change.
    $new_entity_schema_data = $this->installedStorageSchema
      ->get('entity_test_update.entity_schema_data', []);
    $this
      ->assertEquals($original_entity_schema_data, $new_entity_schema_data);
    foreach ($new_storage_definitions as $storage_definition) {
      $new_field_schema_data[$storage_definition
        ->getName()] = $this->installedStorageSchema
        ->get('entity_test_update.field_schema_data.' . $storage_definition
        ->getName(), []);
    }
    $this
      ->assertEquals($original_field_schema_data, $new_field_schema_data);

    // Check that temporary tables have been removed.
    $tables = $schema
      ->findTables('tmp_%');
    $this
      ->assertCount(0, $tables);
    $current_table_names = $storage
      ->getCustomTableMapping($original_entity_type, $original_storage_definitions)
      ->getTableNames();
    foreach ($current_table_names as $table_name) {
      $this
        ->assertTrue($schema
        ->tableExists($table_name));
    }

    // Check that backup tables do not exist anymore, since they were
    // restored/renamed.
    $tables = $schema
      ->findTables('old_%');
    $this
      ->assertCount(0, $tables);

    // Check that the original tables still exist and their data is intact.
    $this
      ->assertTrue($schema
      ->tableExists('entity_test_update'));
    $this
      ->assertTrue($schema
      ->tableExists('entity_test_update_data'));

    // Check that the revision tables have not been created.
    $this
      ->assertFalse($schema
      ->tableExists('entity_test_update_revision'));
    $this
      ->assertFalse($schema
      ->tableExists('entity_test_update_revision_data'));
    $base_table_count = $this->database
      ->select('entity_test_update')
      ->countQuery()
      ->execute()
      ->fetchField();
    $this
      ->assertEquals(3, $base_table_count);
    $data_table_count = $this->database
      ->select('entity_test_update_data')
      ->countQuery()
      ->execute()
      ->fetchField();

    // There are two records for each entity, one for English and one for
    // Romanian.
    $this
      ->assertEquals(6, $data_table_count);
    $base_table_row = $this->database
      ->select('entity_test_update')
      ->fields('entity_test_update')
      ->condition('id', 1, '=')
      ->condition('langcode', 'en', '=')
      ->execute()
      ->fetchAllAssoc('id');
    $this
      ->assertEquals($this->testEntities[1]
      ->uuid(), $base_table_row[1]->uuid);
    $data_table_row = $this->database
      ->select('entity_test_update_data')
      ->fields('entity_test_update_data')
      ->condition('id', 1, '=')
      ->condition('langcode', 'en', '=')
      ->execute()
      ->fetchAllAssoc('id');
    $this
      ->assertEquals('test entity - 1 - en', $data_table_row[1]->name);
    $this
      ->assertEquals('shared table - 1 - value 1 - en', $data_table_row[1]->test_multiple_properties__value1);
    $this
      ->assertEquals('shared table - 1 - value 2 - en', $data_table_row[1]->test_multiple_properties__value2);
    $data_table_row = $this->database
      ->select('entity_test_update_data')
      ->fields('entity_test_update_data')
      ->condition('id', 1, '=')
      ->condition('langcode', 'ro', '=')
      ->execute()
      ->fetchAllAssoc('id');
    $this
      ->assertEquals('test entity - 1 - ro', $data_table_row[1]->name);
    $this
      ->assertEquals('shared table - 1 - value 1 - ro', $data_table_row[1]->test_multiple_properties__value1);
    $this
      ->assertEquals('shared table - 1 - value 2 - ro', $data_table_row[1]->test_multiple_properties__value2);
    $dedicated_table_name = $table_mapping
      ->getFieldTableName('test_multiple_properties_multiple_values');
    $dedicated_table_row = $this->database
      ->select($dedicated_table_name)
      ->fields($dedicated_table_name)
      ->condition('entity_id', 1, '=')
      ->condition('langcode', 'en', '=')
      ->execute()
      ->fetchAllAssoc('delta');
    $this
      ->assertEquals('dedicated table - 1 - delta 0 - value 1 - en', $dedicated_table_row[0]->test_multiple_properties_multiple_values_value1);
    $this
      ->assertEquals('dedicated table - 1 - delta 0 - value 2 - en', $dedicated_table_row[0]->test_multiple_properties_multiple_values_value2);
    $this
      ->assertEquals('dedicated table - 1 - delta 1 - value 1 - en', $dedicated_table_row[1]->test_multiple_properties_multiple_values_value1);
    $this
      ->assertEquals('dedicated table - 1 - delta 1 - value 2 - en', $dedicated_table_row[1]->test_multiple_properties_multiple_values_value2);
    $dedicated_table_row = $this->database
      ->select($dedicated_table_name)
      ->fields($dedicated_table_name)
      ->condition('entity_id', 1, '=')
      ->condition('langcode', 'ro', '=')
      ->execute()
      ->fetchAllAssoc('delta');
    $this
      ->assertEquals('dedicated table - 1 - delta 0 - value 1 - ro', $dedicated_table_row[0]->test_multiple_properties_multiple_values_value1);
    $this
      ->assertEquals('dedicated table - 1 - delta 0 - value 2 - ro', $dedicated_table_row[0]->test_multiple_properties_multiple_values_value2);
    $this
      ->assertEquals('dedicated table - 1 - delta 1 - value 1 - ro', $dedicated_table_row[1]->test_multiple_properties_multiple_values_value1);
    $this
      ->assertEquals('dedicated table - 1 - delta 1 - value 2 - ro', $dedicated_table_row[1]->test_multiple_properties_multiple_values_value2);
  }
}