Problem/Motivation

See #2336895: Allow entity type and field storage definition objects to be compared for definition equality. Switching out the storage class of a content entity should not result in a possible schema change, only if the storage actually returns a different schema.

This is a problem because it means that changing a storage handler that does not actually change anything about the schema (Not a very common thing, but it can happen, in my case, to provide a different implementation for the threaded-comments-list query) blocks update.php if you already have data. We have no other choice but to do that if there is an actual schema change, but we should try very hard to avoid that if we don't actually need any updates.

@catch considered this to be a critical problem in the parent issue in comment #6: #2336895-6: Allow entity type and field storage definition objects to be compared for definition equality.

Proposed resolution

Remove the check from SqlContentEntityStorageSchema::requiresEntityStorageSchemaChanges().

Remaining tasks

User interface changes

API changes

Comments

jhedstrom’s picture

Status: Active » Needs review
StatusFileSize
new813 bytes

Can it really be this simple?

berdir’s picture

Issue tags: +Needs tests

Yes, that is the relevant part of my patch from #2336895: Allow entity type and field storage definition objects to be compared for definition equality :)

What we need now is a unit test. Looks like this method has no unit test coverage yet.

jhedstrom’s picture

Assigned: Unassigned » jhedstrom

Oh, I didn't realize the other issue had a patch for this one. I'll work on unit tests.

jhedstrom’s picture

Assigned: jhedstrom » Unassigned
StatusFileSize
new6.43 KB
new6.47 KB

This adds unit tests for SqlContentEntityStorageSchema::requiresEntityStorageSchemaChanges().

jhedstrom’s picture

StatusFileSize
new5.68 KB

Oops, test in #4 was a partial to my local branch. Here's the full test.

The last submitted patch, 4: entity-storage-class-switch-2419065-04-TEST-ONLY.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 5: entity-storage-class-switch-2419065-05-TESTS-ONLY.patch, failed testing.

jhedstrom’s picture

Status: Needs work » Needs review

Patch in #5 was expected to fail, back to needs review.

plach’s picture

Looks good to me, thanks :)

@Berdir:

Want to RTBC this?

berdir’s picture

Status: Needs review » Needs work

Some feedback on the tests structure, what they are testing looks great to me as well.

  1. +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
    @@ -1163,6 +1163,102 @@ public function testRequiresEntityDataMigration($updated_entity_type_definition,
    +    $updated_entity_type_definition = $this->getMockBuilder('\Drupal\Core\Entity\ContentEntityTypeInterface')
    +      ->disableOriginalConstructor()
    +      ->getMock();
    +    $original_entity_type_definition = $this->getMockBuilder('\Drupal\Core\Entity\ContentEntityTypeInterface')
    +      ->disableOriginalConstructor()
    +      ->getMock();
    

    No need for the constructor stuff on an Interface, just use getMock() ?

  2. +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
    @@ -1163,6 +1163,102 @@ public function testRequiresEntityDataMigration($updated_entity_type_definition,
    +    // Case 1: Class names change, should not result in required schema change.
    

    Multiple scenarios are usually either tested with data providers (would be very hard I guess here) or multiple methods. So this one would be come testRequiresEntityStorageSchemaChangesStorageClassChange() or so.

  3. +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
    @@ -1163,6 +1163,102 @@ public function testRequiresEntityDataMigration($updated_entity_type_definition,
    +      ->willReturn('Drupal\Core\Entity\Sql\SqlContentEntityStorage');
    ...
    +      ->willReturn('\Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema');
    

    it is correct that any class works, but reads strange. There's a null implementation of the storage, you could use that, for example..

plach’s picture

/me sucks at reviewing tests...

jhedstrom’s picture

Status: Needs work » Needs review
StatusFileSize
new1.73 KB
new6.16 KB
new5.36 KB

Regarding data providers, I originally set out to use them, but since the internal logic of the method being called relies so heavily on making mocks for each iteration, the data provider method was going to be quite convoluted. Also, separate methods for each iteration of the method seem like overkill, but perhaps they'd be easier to read...

For now, here's an attempt at addressing #10 without splitting each variation into a separate method.

jhedstrom’s picture

Oops, left over docblock comment.

berdir’s picture

+++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
@@ -1163,6 +1163,92 @@ public function testRequiresEntityDataMigration($updated_entity_type_definition,
+      ->getMock();
+    $original_entity_type_definition = $this->getMockBuilder('\Drupal\Core\Entity\ContentEntityTypeInterface')
+      ->getMock();

Nitpick: Sorry, what I meant is just $this->getMock('\Drupal\Core\Entity\ContentEntityTypeInterface'); We don't need to get the mockbuilder here.

Did not review the rest yet.

The last submitted patch, 13: entity-storage-class-switch-2419065-13-TEST-ONLY.patch, failed testing.

The last submitted patch, 12: entity-storage-class-switch-2419065-12-TEST-ONLY.patch, failed testing.

jhedstrom’s picture

Assigned: Unassigned » jhedstrom
Status: Needs review » Needs work

Actually, I think I figured out a clean way to use data providers.

jhedstrom’s picture

Assigned: jhedstrom » Unassigned
Status: Needs work » Needs review
StatusFileSize
new9.61 KB
new7.86 KB
new8.66 KB

This switches to use a data provider, and to simply use getMock() for interfaces (I updated an existing test to do this here as well).

The last submitted patch, 18: entity-storage-class-switch-2419065-18-TEST-ONLY.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 18: entity-storage-class-switch-2419065-18.patch, failed testing.

Status: Needs work » Needs review

The last submitted patch, 4: entity-storage-class-switch-2419065-04-TEST-ONLY.patch, failed testing.

The last submitted patch, 5: entity-storage-class-switch-2419065-05-TESTS-ONLY.patch, failed testing.

The last submitted patch, 12: entity-storage-class-switch-2419065-12-TEST-ONLY.patch, failed testing.

The last submitted patch, 13: entity-storage-class-switch-2419065-13-TEST-ONLY.patch, failed testing.

The last submitted patch, 18: entity-storage-class-switch-2419065-18-TEST-ONLY.patch, failed testing.

jhedstrom’s picture

Issue tags: -Needs tests

Removing 'needs tests' tag.

plach’s picture

  1. +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
    @@ -1163,6 +1156,118 @@ public function testRequiresEntityDataMigration($updated_entity_type_definition,
    +    $cases[] = [$updated, $original, FALSE, FALSE, FALSE];
    

    Isn't this the same of case 1?

  2. +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
    @@ -1163,6 +1156,118 @@ public function testRequiresEntityDataMigration($updated_entity_type_definition,
    +  public function testRequiresEntityStorageSchemaChanges(ContentEntityTypeInterface $updated, ContentEntityTypeInterface $original, $requires_change, $change_schema = FALSE, $change_shared_table = FALSE) {
    

    It seems the data provider almost always provides values also for the last two arguments. Can we remove the default values and make sure we always the actual ones?

xjm’s picture

Per @berdir:

see https://www.drupal.org/node/2336895#comment-9575337 and catch then promoted that to critical. switching a storage handler to implement one method differently currently makes it impossible to run update.php

Can we clarify that in the summary? Thanks!

jhedstrom’s picture

re: #33 you're right regarding those duplicated cases. I've updated the test to remove the duplicate, and also remove the default values as suggested.

The last submitted patch, 35: entity-storage-class-switch-2419065-35-TEST-ONLY.patch, failed testing.

berdir’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update

Updated issue summary, better now?

The reason I didn't comment on the test yet is that I've had bad experiences with mock objects that are set up in a data provider, because they are all created before a test runs and then kinda-survive multiple test executions, but there is code that runs at the end of a test method on all mocks, for example to check that methods were called as often as expected.

The test seems to work, but I suspect it will no longer work as expected if you change those $this->any() to $this->once(), which would be more correct. The only alternative I can offer is to only set up some sort of instrumentalisation of the mock expections and only create the mocks in the test method. Or have multiple test methods with helper methods to pass the mocks into. But I'm think I'm OK with moving forward here if it works, but that is IMHO something that @alexpott/@catch should know about and make a final decision if they're OK with that.

jhedstrom’s picture

I spoke with Berdir on IRC regarding the expects() and mocks from providers. I think in this particular case it should be okay as it is written, because it's either using never() or in the case of once() it's per-unique instance of an object, so shouldn't run into trouble with the way mocks and providers work. The test/provider immediately above this new one uses similar mocks.

berdir’s picture

Reviewed this again. Agreed that this is probably OK like that (Although I'm not 100% sure the never() is working as expected, you call it on the clone and pass to multiple methods, but I'm not sure how that will actually be verified)

Anyway, +1 RTBC on the test coverage, actual change is what I wrote, although you came up with it separately I think. Leaving it to @plach to set RTBC.

plach’s picture

Status: Needs review » Reviewed & tested by the community

If @Berdir is ok with the current code I'll tentatively RTBC it.

For committers: please have a look to #37, just in case.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Yep I'm not keen on setting up mocks in the provider either. But the mocks are not set on the test object so this should be okay. The test is, however, more memory hungry than it needs to be.

This issue addresses a critical bug and is allowed per https://www.drupal.org/core/beta-changes. Committed 7f1b02e and pushed to 8.0.x. Thanks!

  • alexpott committed 7f1b02e on 8.0.x
    Issue #2419065 by jhedstrom: Switching the entity storage class should...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.