Files
timebank-cc-public/app/Console/Commands/TestBounceSystem.php
Ronald Huynen 2547717edb Initial commit
2026-03-23 21:37:59 +01:00

227 lines
7.5 KiB
PHP
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Console\Commands;
use App\Models\MailingBounce;
use App\Models\User;
use App\Models\Organization;
use Illuminate\Console\Command;
class TestBounceSystem extends Command
{
/**
* The name and signature of the console command.
*/
protected $signature = 'test:bounce-system
{--email= : Email to test (default: creates test emails)}
{--scenario= : Test scenario: single, threshold-verification, threshold-suppression, multiple}';
/**
* The console command description.
*/
protected $description = 'Test the bounce handling system with simulated bounces';
/**
* Execute the console command.
*/
public function handle()
{
$scenario = $this->option('scenario') ?: 'single';
$email = $this->option('email');
switch ($scenario) {
case 'single':
$this->testSingleBounce($email);
break;
case 'threshold-verification':
$this->testVerificationThreshold($email);
break;
case 'threshold-suppression':
$this->testSuppressionThreshold($email);
break;
case 'multiple':
$this->testMultipleEmails();
break;
default:
$this->error("Unknown scenario: {$scenario}");
$this->info("Available scenarios: single, threshold-verification, threshold-suppression, multiple");
return 1;
}
return 0;
}
/**
* Test a single bounce (should not trigger any thresholds)
*/
protected function testSingleBounce(?string $email): void
{
$testEmail = $email ?: 'test-single@example.com';
$this->info("🧪 Testing Single Bounce for: {$testEmail}");
// Create a test user with verified email
$this->createTestUser($testEmail);
// Record a single hard bounce with definitive pattern
$bounce = MailingBounce::recordBounce(
$testEmail,
'hard',
'user unknown - mailbox does not exist'
);
$this->line("✅ Created bounce record ID: {$bounce->id}");
// Check the results
$stats = MailingBounce::getBounceStats($testEmail);
$this->displayResults($testEmail, $stats);
}
/**
* Test verification threshold (2 bounces)
*/
protected function testVerificationThreshold(?string $email): void
{
$testEmail = $email ?: 'test-verification@example.com';
$this->info("🧪 Testing Verification Reset Threshold for: {$testEmail}");
// Create test user with verified email
$user = $this->createTestUser($testEmail);
$this->line("📧 Created test user with verified email: {$user->email_verified_at}");
// Record first bounce with exact pattern from config
$this->line("1⃣ Recording first hard bounce...");
MailingBounce::recordBounce($testEmail, 'hard', 'user unknown - definitive bounce');
$user->refresh();
$this->line(" User email_verified_at: " . ($user->email_verified_at ?: 'NULL'));
// Record second bounce (should trigger verification reset)
$this->line("2⃣ Recording second hard bounce (should reset verification)...");
MailingBounce::recordBounce($testEmail, 'hard', 'mailbox unavailable - permanent failure');
$user->refresh();
$this->line(" User email_verified_at: " . ($user->email_verified_at ?: 'NULL'));
// Check results
$stats = MailingBounce::getBounceStats($testEmail);
$this->displayResults($testEmail, $stats);
if (!$user->email_verified_at) {
$this->info("✅ SUCCESS: Email verification was reset!");
} else {
$this->error("❌ FAILED: Email verification was NOT reset!");
}
}
/**
* Test suppression threshold (3 bounces)
*/
protected function testSuppressionThreshold(?string $email): void
{
$testEmail = $email ?: 'test-suppression@example.com';
$this->info("🧪 Testing Suppression Threshold for: {$testEmail}");
// Create test user
$user = $this->createTestUser($testEmail);
// Record three bounces
for ($i = 1; $i <= 3; $i++) {
$this->line("{$i}️⃣ Recording hard bounce #{$i}...");
MailingBounce::recordBounce($testEmail, 'hard', "user unknown - attempt {$i}");
$user->refresh();
$isSuppressed = MailingBounce::isSuppressed($testEmail);
$this->line(" Suppressed: " . ($isSuppressed ? 'YES' : 'NO'));
$this->line(" Email verified: " . ($user->email_verified_at ? 'YES' : 'NO'));
}
// Check final results
$stats = MailingBounce::getBounceStats($testEmail);
$this->displayResults($testEmail, $stats);
if ($stats['is_suppressed']) {
$this->info("✅ SUCCESS: Email was suppressed after 3 bounces!");
} else {
$this->error("❌ FAILED: Email was NOT suppressed!");
}
}
/**
* Test multiple emails with different scenarios
*/
protected function testMultipleEmails(): void
{
$this->info("🧪 Testing Multiple Email Scenarios");
$scenarios = [
'no-bounce@example.com' => 0,
'one-bounce@example.com' => 1,
'verification-reset@example.com' => 2,
'suppressed@example.com' => 3,
'over-threshold@example.com' => 5
];
foreach ($scenarios as $email => $bounceCount) {
$this->line("Setting up {$email} with {$bounceCount} bounces...");
$this->createTestUser($email);
for ($i = 1; $i <= $bounceCount; $i++) {
MailingBounce::recordBounce($email, 'hard', "user unknown - bounce {$i}");
}
}
$this->info("\n📊 Results Summary:");
foreach ($scenarios as $email => $expectedBounces) {
$stats = MailingBounce::getBounceStats($email);
$user = User::where('email', $email)->first();
$this->line("📧 {$email}:");
$this->line(" Hard bounces: {$stats['recent_hard_bounces']}");
$this->line(" Suppressed: " . ($stats['is_suppressed'] ? 'YES' : 'NO'));
$this->line(" Verified: " . ($user && $user->email_verified_at ? 'YES' : 'NO'));
}
}
/**
* Create a test user with verified email
*/
protected function createTestUser(string $email): User
{
// Remove existing test user if any
User::where('email', $email)->delete();
$user = User::create([
'name' => 'Test User ' . substr($email, 0, strpos($email, '@')),
'email' => $email,
'password' => bcrypt('password'),
]);
// Use forceFill since email_verified_at isn't in fillable
$user->forceFill(['email_verified_at' => now()])->save();
return $user;
}
/**
* Display test results
*/
protected function displayResults(string $email, array $stats): void
{
$this->info("\n📊 Test Results for {$email}:");
$this->line("Total bounces: {$stats['total_bounces']}");
$this->line("Recent hard bounces: {$stats['recent_hard_bounces']}");
$this->line("Is suppressed: " . ($stats['is_suppressed'] ? 'YES' : 'NO'));
$user = User::where('email', $email)->first();
if ($user) {
$this->line("Email verified: " . ($user->email_verified_at ? 'YES' : 'NO'));
}
$this->line("");
}
}