CluPilotCloud/tests/Feature/MailDispatchTest.php

95 lines
3.6 KiB
PHP

<?php
use App\Jobs\PacedMail;
use App\Mail\DormantAccountWarningMail;
use App\Models\User;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Queue;
/**
* Eine Mail fährt über IHREN Mailer, nicht über den Standard-Mailer.
*
* Jede Mail dieses Systems wählt im Konstruktor ihren Mailer — `cp_mail_<typ>`
* oder `cp_<zweck>`. Dahinter steht MailboxTransport: er sucht das Postfach,
* dessen Adresse im Absender steht, meldet sich mit genau dessen Zugangsdaten
* an, und er ist die Stelle, an der der Notschalter aus App\Support\MailDelivery
* greift.
*
* `Mail::to(…)` löst den STANDARD-Mailer auf. Dessen queue() schreibt dann
* `$view->mailer($this->name)` — der eigene Mailer der Mail wird durch 'smtp'
* ersetzt, bevor der Auftrag überhaupt gebaut ist. Was danach abgeschickt wird,
* kennt weder Postfach noch Schalter: es meldet sich mit den Zugangsdaten aus
* der Konfiguration an, setzt aber den Absender aus der Mail, und ein Server,
* der prüft, wem die Absenderadresse gehört, weist es ab („553 Sender address
* rejected"). Genau das lief hier tagelang im Minutentakt — und eine
* abgeschaltete Zustellung schaltete nichts ab.
*
* Deshalb beginnt jeder Versand mit `Mail::mailer($mail->mailer)`: dann
* schreibt das Überschreiben denselben Wert zurück, den die Mail schon hatte.
*/
it('keeps the mailable own mailer when it is queued through Mail::mailer', function () {
Queue::fake();
$mail = new DormantAccountWarningMail(User::factory()->create(), 30);
$chosen = $mail->mailer;
expect($chosen)->not->toBeNull()
->and($chosen)->not->toBe(config('mail.default'));
Mail::mailer($mail->mailer)->to('empfaenger@example.com')->queue($mail);
Queue::assertPushed(
PacedMail::class,
fn (PacedMail $job) => $job->mailable->mailer === $chosen,
);
});
/**
* Der Gegenbeweis, damit die Regel oben nicht als Aberglaube gilt: dieselbe
* Mail, ohne den benannten Mailer eingereiht, verliert ihn. Schlägt dieser Test
* fehl, hat das Framework sein Verhalten geändert — dann darf die Regel weg,
* vorher nicht.
*/
it('proves that Mail::to alone overwrites the mailable own mailer', function () {
Queue::fake();
$mail = new DormantAccountWarningMail(User::factory()->create(), 30);
$chosen = $mail->mailer;
Mail::to('empfaenger@example.com')->queue($mail);
Queue::assertPushed(
PacedMail::class,
fn (PacedMail $job) => $job->mailable->mailer === config('mail.default')
&& $job->mailable->mailer !== $chosen,
);
});
it('never dispatches a mail through Mail::to without naming the mailer', function () {
$offenders = [];
foreach (File::allFiles(app_path()) as $file) {
if ($file->getExtension() !== 'php') {
continue;
}
foreach (explode("\n", $file->getContents()) as $number => $line) {
// Kommentare beschreiben die Falle — zwei Stellen im Repo tun genau
// das an der Zeile, an der sie umgangen wird. Sie sind der Grund
// für diese Regel, nicht ihr Verstoß.
if (preg_match('#^\s*(//|\*|/\*)#', $line) === 1) {
continue;
}
// Trifft beide Schreibweisen: `Mail::to(` und die voll
// qualifizierte `\Illuminate\Support\Facades\Mail::to(`.
if (preg_match('/(?<![\w\\\\])Mail::to\(/', $line) === 1) {
$offenders[] = str_replace(base_path().'/', '', $file->getPathname()).':'.($number + 1);
}
}
}
expect($offenders)->toBe([]);
});