Problem/Motivation
The d6_block migration attempts to migrate all records from the D6 blocks table, ordered by block ID (bid). When multiple themes are enabled on a site, then the same block can be listed multiple times in this table. For example, looking at the user login block (module = user, delta = 0), there may be several records in the D6 blocks table for this one block: http://note.io/1ioysQj
Keeping in mind that the blocks table has no knowledge of the current default theme on the D6 site, when the d6_block migration runs, it first migrates bid=1 from the screenshot above. This is the user login block placement in the Garland theme. This is migrated into D8 with the config name "block.block.user" (http://note.io/1ioz8Fj) and with an entry in the migrate_map_d6_block table (http://note.io/1iozfkf).
The next D6 block record to be migrated is bid=2, the user's "system_menu_block:tools" block (module = user, delta = 1). Again, this appears to be migrated into config properly with a name of "block.block.user_1" and a reasonable migrate_map_d6_block table record (http://note.io/1iozVWO).
Issue 1
Continuing, this appears to all work fine until we get to D6 block table records with: module = block (custom blocks): http://note.io/1ioAos3. The first one (bid=10) is migrated into D8 with a config name of "block.block.block" and a reasonable entry in migrate_map_d6_block (http://note.io/1ioAEHq). It is with the second custom block (bid=11) where we see things start to go sideways. There is no config entry created for the second block (leading me to think that there is an issue deduping custom block ids), but the migrate_map_d6_block table record again looks sound (http://note.io/1ioBdku).
Issue 2
Continuing with the block table migration, looking at bid=13, again, we're looking at a user login block (module = user, delta = 0), but for a different theme (chameleon). When the migration runs, it sees that we've already migrated a block with "sourceid1 = user" and "sourceid2 = 0", therefore it doesn't migrate it. But, as I mentioned earlier, the blocks table has no knowledge of the current default theme, so we may be ignoring block records for the current default theme that should be migrated.
Proposed resolution
Issue 1: fix the dedupe bug so that custom blocks are deduped properly (block, block_1, block_2, etc...)
Issue 2: this one is a little trickier and I think there are two options:
- Add a new sourceid to the migration, the theme name. I think this will also mean that we need to modify the config name of migrated blocks to something like: block.block.theme_name.block, block.block.theme_name.block_1, etc... (although I see config names like block.block.bartik_tools and block.block.bartik_help in the D8 config table, so maybe that's the way to go).
- Modify the d6_block query to only migrate blocks from the current default and admin themes. This will be a bit of a downer for sites with multiple active themes, but I think that's a pretty small percentage.
Remaining tasks
Find and fix the dedupe bug.
Determine which is the best solution for the multiple source theme issue and implement.
User interface changes
None.
API changes
Hopefully, none.
Comment | File | Size | Author |
---|---|---|---|
#24 | interdiff.txt | 717 bytes | chx |
#24 | 2250429_21.patch | 17.53 KB | chx |
#21 | dedupe-2250429-21.patch | 17.6 KB | ultimike |
#18 | dedupe-2250429-18.patch | 17.06 KB | ultimike |
#16 | dedupe-2250429-15.patch | 16.52 KB | ultimike |
Comments
Comment #1
chx CreditAttribution: chx commentedI am a little confused about the problems outlined -- what doesn't get migrated , the blocks table or the boxes table? When migrating the blocks table (the block placement) into block config entities we do not use the delta at all; we use module as prefix (but honestly we could just use dancing_pink_elephant for a common prefix, it doesn't matter) and then dedupe. When migrating the boxes table into the custom block content entity then we are using the boxes.bid as an id which is equal to the delta in the blocks table, that's true. Not quite what doesn't work here. I suspect it's the former. Is the dedupe somehow broken? I will try to find the time to test this more; but if you get there first, DedupeEntity::exists is what needs debug.
Comment #2
ultimikeIt's the blocks table that isn't migrating properly, and yes, I think the issue is with the dedupe function.
Here's another way of looking at it - when a custom block is created in D8, its "Block description" (and therefore its machine name) must be unique. For example, if the block description is "D8 custom block", then its config entry has the name "block.block.d8customblock".
When custom blocks block table records are migrated from D6 to D8, their config name is always "block.block.block". So, I'm guessing that the first one gets in okay, but then all the rest don't (because they have the same name).
This behavior is really easy to see with the patch from https://drupal.org/node/2248407 and test migrating at least two custom D6 blocks.
-mike
Comment #3
ultimikeOk - I did another round of (much more methodical) testing, and I think I've narrowed it down to 2 specific issues. I've updated the issue summary with the relevant info.
Thanks,
-mike
Comment #4
chx CreditAttribution: chx commentedIssue #2 is easy to fix: the source getIds needs to contain theme, you are right.
Comment #5
ultimikeThe attached patch should take care of both issues. Thanks to chx for all his guidance on this!
-mike
Comment #7
chx CreditAttribution: chx commentedWow! Someone wrote a unit test for DedupeEntity? Apparently we also need an integration test that checks for duplicated values. Block looks like a good place. To fix the unit test, remove TestDedupeEntity and create a mock of the QueryFactoryInterface which returns the $entity_query for every get call:
Note the __construct method doesn't pass the migration to the parent which it should... which finds us a new bug -- the ProcessPluginBase doesn't store $this->migration which it totally should. But that's a different issue.
And please please flesh poor block test out a bit. It's my fault that test is so nothing -- but getting block to *pass* was such arduous work I left it like that.
Comment #8
ultimikePatch updated with a working dedupe test.
Updating the block test should be a new issue, correct?
Thanks,
-mike
Comment #9
chx CreditAttribution: chx commentedI think it can be very well be here; after all we just gotten the tests not break but didn't actually test the new things work. Thanks!
Comment #10
ultimikeLooking at the current tests, here's what I see:
Drupal\migrate_drupal\Tests\d6\MigrateBlockTest
Currently creates 3 D8 blocks (including 1 custom block), then migrates 10 blocks (including one custom block) from a dump file. All migrated blocks are assigned to a single source theme (garland). The lone assertion is that after the migration, we have at least 1 block in D8 (I'm pretty sure I'm reading it correctly).
I think we should increase the number of both D8 and D6 blocks in setUp(), including multiple custom blocks (to test the deduping). I'll also need to figure out which additional assertions to add.
We can add additional tests for the block theme/region mapping as part of this patch: https://drupal.org/node/2248407
Drupal\migrate_drupal\Tests\d6\MigrateCustomBlockTest
Currently migrates 1 custom block from a dump file. Has multiple assertions for all the relevant block data.
I think we should increase the number of both D6 custom blocks to be migrated in setUp(). We can probably repeat the same (or similar assertions).
Does this sound about right? Will this cover what we need?
Thanks,
-mike
Comment #11
chx CreditAttribution: chx commentedI think MigrateBlockTest is the one that needs help; MigrateCustomBlockTest is not affected. But yes, what I was talking about is the sad lonely assert in MigrateBlockTest.
Comment #12
ultimikeUpdated the patch with a more robust test.
-mike
Comment #14
ultimikeHmmm - I tried running the MigrateDrupal6Test in an up-to-date Drupal 8 environment (without this patch applied) and it failed pretty hard (http://note.io/1n2frVS).
Errors appear to be related to taxonomy term node, taxonomy term node revisions, url alias, user profile entity form display, vocabulary entity display, vocabulary entity form display, and vocabulary field instance migrations.
-mike
Comment #15
ultimikeMy tests in comment 14 were run from the UI.
Based on chx's suggestion, I re-ran the tests via the CLI:
chx helped me understand that the MigrateDrupal6Test didn't run the setup() methods of the various tests, instead it just loads all the dump files and uses those as a giant combined setup (so to speak). Therefore, the custom blocks defined in core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6Box.php need to be in-sync with the blocks in core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Tests/Dump/Drupal6Block.php. I went ahead and made this change, then ran the MigrateBlockTest and MigrateCustomBlockTest separately (via the CLI and UI) to ensure that they both passed. They did.
chx asked me to codify the fact that custom blocks must be migrated before blocks - I did this by adding a migration dependency to d6_custom_block in the d6_block.yml. Unfortunately, the MigrateDrupal6Test still fails (see below for output).
I'm not really sure what to do from here. Help?!
Thanks,
-mike
Comment #16
ultimikeUpdated patch with the new custom block stuff I mentioned in the previous comment.
-mike
Comment #17
chx CreditAttribution: chx commentedtl;dr: add d6_node_type to the migration dependencies of d6_upload_field_instance
Here's how to find this one out:
$this->addDependency('entity', $bundle_entity->getConfigDependencyName());
with the condition
!is_object($bundle_entity)
. Go into the MigrateExecutable in the backtrace , open the migration entity belonging to it so now know the migration running isd6_upload_field_instance
.node.page.upload
but can not find the entity of typenode_type
with idpage
.MigrateUploadInstanceTest::setUp
creates the page node type. ButMigrateDrupal6Test
does not runsetUp
of individual test but rather depends on previous tests to do it. First thing to check: is the dependency in order? Well, dependency on what?Nothing else. That makes it easy.
d6_upload_field_instance
migrate dependencies recursively and quickly find that it depends ond6_upload_field
butd6_upload_field
has no migration_dependencies. That's the bug. We forgot a dependency, your new dependency have shuffled the sort enough that the previous accidental order is no longer in effectComment #18
ultimikechx,
Whoa - that's some strong kung-fu. Your explanation make sense, but I'm still a little ways away from being able to figure that out on my own. Thanks for the assistance.
Updated patch attached.
Thanks,
-mike
Comment #20
chx CreditAttribution: chx commentedAh yes! Adding a migration_dependency requires patching the id mappings in setUp of the relevant test. MigrateFieldInstanceTest has an example for d6_node_type mappings. Beyond that, we only have a fail that seems relevant to the issue.
Comment #21
ultimikeLet's try this again - I fixed an issue with the custom block DB dump. I just ran all the migrate_drupal" tests locally and they all passed. Fingers crossed...
-mike
Comment #22
ultimikeComment #24
chx CreditAttribution: chx commentedAmazing hard work, thanks so much! I have removed one too many copypasted lines (this test only creates page and story, see the entity_create just after the prepareIdMappings call) otherwise it's good. In a followup perhaps we should add a test for an aggregator block too but that's definitely not this issue.
Comment #26
ultimike24: 2250429_21.patch queued for re-testing.
Comment #27
ultimikeComment #28
chx CreditAttribution: chx commentedBack to RTBC after a bot fluke.
Comment #29
alexpottCommitted b45b871 and pushed to 8.x. Thanks!