Problem/Motivation

It was discovered in #84883: Unicode::mimeHeaderEncode() doesn't correctly follow RFC 2047 that two migration tests, DoubleSlashTest and Upgrade7Test, were sending emails, such as this one.

From: The Site Name <joseph@flattandsons.com>
MIME-Version: 1.0
Reply-to: joseph@flattandsons.com
Return-Path: <joseph@flattandsons.com>
Sender: joseph@flattandsons.com
Subject: Your account is approved!
To: odo@local.host
X-Mailer: DrupalYour account was activated, and there was much rejoicing.

Credit to alexpott for the following (summarized from a Slack conversation).
alexpott pointed out that migrate tests shouldn’t result in the test mailer being replaced and questioned why is a migration sending activation emails. "We’re sending an email because user 2 which is created by \Drupal\Tests\migrate_drupal\Traits\CreateTestContentEntitiesTrait::createContent() is created as a blocked user. And in the drupal7.php user 2 exists and is active. So the migration activates that user and then User::postSave() sends the email. \Drupal\Core\Test\FunctionalTestSetupTrait::initConfig() is being undone by the migration"

This issue is to fix this so the tests use the test mail collector.

Steps to reproduce

N/A

Proposed resolution

Removed the d7_system_mail migration from the migration store before clicking 'Perform upgrade'.
Update migrate drupal functional tests to capture email and test the results. The D6 upgrade does not generate mail but D7 does.

Remaining tasks

Patch
Write Tests
Review
Commit

User interface changes

N/A

API changes

N/A

Data model changes

N/A

Release notes snippet

N/A

Comments

quietone created an issue. See original summary.

quietone’s picture

Issue summary: View changes
StatusFileSize
new1.98 KB
quietone’s picture

Status: Active » Needs review

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

quietone’s picture

StatusFileSize
new1.4 KB
new3.39 KB

Add tests to confirm emails were not captured for D6 upgrade and were captured for D7 upgrade.

Status: Needs review » Needs work

The last submitted patch, 5: 3207907-5.patch, failed testing. View results

quietone’s picture

Status: Needs work » Needs review

Retest and tests passing again.

quietone’s picture

Issue summary: View changes
quietone’s picture

Title: Ensure funcational tests use the test mail collector » Ensure functional tests use the test mail collector

@benjifisher prompted me on Slack to fix the typo in the title. :-)

berdir’s picture

+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
@@ -57,4 +58,17 @@ public function doUpgradeAndIncremental() {
+   */
+  public function useTestMailCollector() {
+    $store = \Drupal::service('tempstore.private')->get('migrate_drupal_ui');
+    $migration_array = $store->get('migrations');
+    // Only d7_system_mail changes the mail configuration.
+    if (isset($migration_array['d7_system_mail'])) {
+      unset($migration_array['d7_system_mail']);
+    }
+    $store->set('migrations', $migration_array);
+  }

Alternative idea: Use settings.php config overrides to ensure the test mail handler is set, so even *if* config is changed and we'd want to change that, we would not actually use that configuration?

berdir’s picture

That is how \Drupal\KernelTests\KernelTestBase::bootKernel() for example works, but it only puts it into $GLOBALS. For functional tests, we need to write it out into the generated settings.php.

I'm doing that with redis in https://git.drupalcode.org/project/redis/-/blob/8.x-1.x/tests/src/Functi... for example.

berdir’s picture

+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
@@ -228,6 +228,11 @@ public function testUpgradeAndIncremental() {
 
     $this->assertFollowUpMigrationResults();
+
+    // Confirm one user activation email was sent.
+    $captured_emails = \Drupal::state()->get('system.test_mail_collector', []);
+    $this->assertCount(1, $captured_emails);
+    $this->assertEquals('user_status_activated', $captured_emails[0]['id']);
   }

I suppose you could question whether a migration should send such a mail at all, I've had problems with that too in the past where I had to disable e.g. content notifications.

Could imagine a migrate_mail_alter() that prevents all mails from being sent, configurable maybe.

But it's actually useful in this case to make sure that we _do_ collect mails. Maybe we could be even more explicit, also in the D6 test to make sure that the runtime config really uses the correct mail configuration. Although that wouldn't catch the config during web requests either.

quietone’s picture

@Berdir, Thanks for the reply. I don't understand. Are you suggesting that this will work if $settings are changed, like this, before running the test?

    $settings = Settings::getAll();
    $settings['system.mail']['interface']['default'] = 'test_mail_collector';
    new Settings($settings);
berdir’s picture

No, that only works in-memory in the current process, not in web requests.

I'm talking about the stuff around line 90 in the redis test, where the override is written out into settings.php of that test.

No strong feeling on which option is better, the advantage of that would be that you don't need to make runtime changes to what is being migrated.

quietone’s picture

StatusFileSize
new1.53 KB
new3.56 KB

Ah, I see, I get it now.

I do prefer to not make runtime changes. Let's see if this works.

Status: Needs review » Needs work

The last submitted patch, 15: 3207907-15.patch, failed testing. View results

berdir’s picture

Hm, that's an interesting fail. So suddenly we _are_ catching that a mail was sent and before we weren't?

The previous logic only specifically removed the d7 migration, are you sure there's no d6 equivalent that we are now actually catching too?

quietone’s picture

Status: Needs work » Needs review
StatusFileSize
new1.82 KB
new4.05 KB

Yes, I didn't look closely enough at the d6 migration. It doesn't have a migration for 'system_mail' like the d7 migration but like the d7 migration a user activation email is sent.

Since the 3 lines of code for checking the email is the same for d6 and d7 I made a helper function.

berdir’s picture

Status: Needs review » Needs work
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
@@ -358,4 +358,14 @@ protected function assertFileMigrations() {
+  protected function assertEmailsSent() {
+    // There should be on user activation email.

nitpick: onE user activation email.

that is kinda weird though. If there is no migration for that setting then why did it still try to send a real mail before? I tried to look a bit, but I don't know those tests or the migrations too well

quietone’s picture

Status: Needs work » Needs review
StatusFileSize
new831 bytes
new4.05 KB

I don't have a complete answer either. Both Upgrade6Test and Upgrade7Test test the 'complete' migration as run from /upgrade. And both of those will migrate users and as we have seen that results in an activation email. I didn't know the source dbs were setup that way but it is nice to know that activation email can be tested.

But none that explains why for the Drupal 6 migration that the activation email is only caught when the settings.php file is altered and for the Drupal 7 that is not necessary. I've poked around the migrations in the system module but nothing seems relevant. And I don't know enough about the mail system to spend time searching there. Do you think this question prevent this fix from being committed?

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

quietone’s picture

I was thinking about why the patch in #5 passed tests so I came back and re-applied that patch. I then ran Upgrade6Test.php and it failed, like it should have! I don't know what the difference is between #5 and #15 that caused that but it is good to know it was not something in the patches here.

mikelutz’s picture

Status: Needs review » Reviewed & tested by the community

And rerunning #5 here now fails as well, so the pass in #5 must have been some kind of testbot hiccup. Which is slightly bothersome, but not relevant to this patch..

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 20: 3207907-20.patch, failed testing. View results

spokje’s picture

Status: Needs work » Reviewed & tested by the community

Back to RTBC per #23 after #3255836: Test fails due to Composer 2.2 solved the unrelated test failure.

quietone’s picture

StatusFileSize
new4.05 KB

@Spokje, thanks.

Re-uploading the patch so it is tested with 9.4.x

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
@@ -57,4 +59,16 @@ public function doUpgradeAndIncremental() {
+  /**
+   * Helper to set the test mail collector in settings.php.
+   */
+  public function useTestMailCollector() {
+    $filename = $this->siteDirectory . '/settings.php';
+    chmod($filename, 0666);
+    $contents = file_get_contents($filename);
+    $contents .= "\n" . '$config["system.mail"]["interface"]["default"] = "test_mail_collector";';
+    file_put_contents($filename, $contents);
+    OpCodeCache::invalidate(DRUPAL_ROOT . '/' . $filename);
+  }

This should do:

    // Set up an override.
    $settings['config']['system.mail']['interface']['default'] = (object) [
      'value' => 'test_mail_collector',
      'required' => TRUE,
    ];
    $this->writeSettings($settings);

instead... less complexity and relying on the existing API in tests to do this.

quietone’s picture

Status: Needs work » Needs review
StatusFileSize
new1.24 KB
new3.74 KB

Yes, of course.

mikelutz’s picture

Status: Needs review » Reviewed & tested by the community

I must confess I didn't know about that one.

alexpott’s picture

Version: 9.4.x-dev » 9.3.x-dev
Status: Reviewed & tested by the community » Fixed

Committed and pushed 4f043a2ecc9 to 10.0.x and f7c9202be9d to 9.4.x and ee025067d5c to 9.3.x. Thanks!

  • alexpott committed 4f043a2 on 10.0.x
    Issue #3207907 by quietone, Berdir, alexpott: Ensure functional tests...

  • alexpott committed f7c9202 on 9.4.x
    Issue #3207907 by quietone, Berdir, alexpott: Ensure functional tests...

  • alexpott committed ee02506 on 9.3.x
    Issue #3207907 by quietone, Berdir, alexpott: Ensure functional tests...

Status: Fixed » Closed (fixed)

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