213 lines
8.1 KiB
PHP
213 lines
8.1 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Settings\Email;
|
|
use App\Models\AuditEvent;
|
|
use App\Models\Setting;
|
|
use App\Models\User;
|
|
use App\Providers\AppServiceProvider;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Crypt;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
class SmtpConfigTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function actingUser(): User
|
|
{
|
|
$user = User::factory()->create(['email' => 'admin@clusev.local']);
|
|
$this->actingAs($user);
|
|
|
|
return $user;
|
|
}
|
|
|
|
public function test_saving_persists_settings_and_stores_password_encrypted(): void
|
|
{
|
|
$this->actingUser();
|
|
|
|
Livewire::test(Email::class)
|
|
->set('mail_host', 'smtp.example.com')
|
|
->set('mail_port', 2525)
|
|
->set('mail_username', 'panel')
|
|
->set('mail_password', 's3cr3t-pw')
|
|
->set('mail_encryption', 'tls')
|
|
->set('mail_from_address', 'panel@example.com')
|
|
->set('mail_from_name', 'Clusev')
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$this->assertSame('smtp.example.com', Setting::get('mail_host'));
|
|
$this->assertSame('2525', Setting::get('mail_port'));
|
|
$this->assertSame('panel', Setting::get('mail_username'));
|
|
$this->assertSame('tls', Setting::get('mail_encryption'));
|
|
$this->assertSame('panel@example.com', Setting::get('mail_from_address'));
|
|
$this->assertSame('Clusev', Setting::get('mail_from_name'));
|
|
|
|
// Stored value must NOT be the plaintext, but must decrypt back to it.
|
|
$stored = Setting::get('mail_password');
|
|
$this->assertNotNull($stored);
|
|
$this->assertNotSame('s3cr3t-pw', $stored, 'password must be encrypted at rest');
|
|
$this->assertSame('s3cr3t-pw', Crypt::decryptString($stored));
|
|
|
|
$this->assertDatabaseHas('audit_events', ['action' => 'mail.configure', 'target' => 'smtp.example.com']);
|
|
}
|
|
|
|
public function test_clear_config_removes_all_mail_settings(): void
|
|
{
|
|
$this->actingUser();
|
|
Setting::put('mail_host', 'smtp.example.com');
|
|
Setting::put('mail_port', '2525');
|
|
Setting::put('mail_username', 'panel');
|
|
Setting::put('mail_password', Crypt::encryptString('s3cr3t-pw'));
|
|
Setting::put('mail_encryption', 'ssl');
|
|
Setting::put('mail_from_address', 'panel@example.com');
|
|
Setting::put('mail_from_name', 'Clusev');
|
|
|
|
Livewire::test(Email::class)
|
|
->assertSet('mail_host', 'smtp.example.com') // mounted from the stored value
|
|
->call('clearConfig')
|
|
->assertHasNoErrors()
|
|
->assertSet('mail_host', '')
|
|
->assertSet('mail_from_address', '')
|
|
->assertSet('passwordSet', false);
|
|
|
|
foreach (['mail_host', 'mail_port', 'mail_username', 'mail_password', 'mail_encryption', 'mail_from_address', 'mail_from_name'] as $key) {
|
|
$this->assertNull(Setting::get($key), "$key must be cleared");
|
|
}
|
|
$this->assertDatabaseHas('audit_events', ['action' => 'mail.reset']);
|
|
}
|
|
|
|
public function test_password_is_not_overwritten_when_left_blank(): void
|
|
{
|
|
$this->actingUser();
|
|
Setting::put('mail_host', 'smtp.example.com');
|
|
Setting::put('mail_from_address', 'panel@example.com');
|
|
Setting::put('mail_password', Crypt::encryptString('original-pw'));
|
|
|
|
Livewire::test(Email::class)
|
|
->set('mail_from_name', 'Clusev')
|
|
->set('mail_password', '') // left blank -> keep the stored one
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$this->assertSame('original-pw', Crypt::decryptString(Setting::get('mail_password')));
|
|
}
|
|
|
|
public function test_configured_reflects_host_and_from_presence(): void
|
|
{
|
|
$this->actingUser();
|
|
|
|
$component = Livewire::test(Email::class);
|
|
$this->assertFalse($component->instance()->configured());
|
|
|
|
$component->set('mail_host', 'smtp.example.com');
|
|
$this->assertFalse($component->instance()->configured(), 'host alone is not enough');
|
|
|
|
$component->set('mail_from_address', 'panel@example.com');
|
|
$this->assertTrue($component->instance()->configured());
|
|
}
|
|
|
|
public function test_runtime_override_switches_to_smtp_when_configured(): void
|
|
{
|
|
config(['mail.default' => 'log']);
|
|
|
|
Setting::put('mail_host', 'smtp.example.com');
|
|
Setting::put('mail_port', '2525');
|
|
Setting::put('mail_username', 'panel');
|
|
Setting::put('mail_password', Crypt::encryptString('s3cr3t-pw'));
|
|
Setting::put('mail_encryption', 'ssl');
|
|
Setting::put('mail_from_address', 'panel@example.com');
|
|
Setting::put('mail_from_name', 'Clusev');
|
|
|
|
// Re-run the provider's boot, which applies the mail settings.
|
|
$this->app->register(AppServiceProvider::class, true);
|
|
|
|
$this->assertSame('smtp', config('mail.default'));
|
|
$this->assertSame('smtp.example.com', config('mail.mailers.smtp.host'));
|
|
$this->assertSame(2525, config('mail.mailers.smtp.port'));
|
|
$this->assertSame('panel', config('mail.mailers.smtp.username'));
|
|
$this->assertSame('s3cr3t-pw', config('mail.mailers.smtp.password'));
|
|
$this->assertSame('ssl', config('mail.mailers.smtp.encryption'));
|
|
$this->assertSame('panel@example.com', config('mail.from.address'));
|
|
}
|
|
|
|
public function test_runtime_override_leaves_default_mailer_when_unconfigured(): void
|
|
{
|
|
config(['mail.default' => 'log']);
|
|
|
|
// No settings -> default mailer must stay untouched.
|
|
$this->app->register(AppServiceProvider::class, true);
|
|
|
|
$this->assertSame('log', config('mail.default'));
|
|
}
|
|
|
|
public function test_encryption_none_maps_to_null(): void
|
|
{
|
|
config(['mail.default' => 'log']);
|
|
Setting::put('mail_host', 'smtp.example.com');
|
|
Setting::put('mail_encryption', 'none');
|
|
Setting::put('mail_from_address', 'panel@example.com');
|
|
|
|
$this->app->register(AppServiceProvider::class, true);
|
|
|
|
$this->assertSame('smtp', config('mail.default'));
|
|
$this->assertNull(config('mail.mailers.smtp.encryption'));
|
|
}
|
|
|
|
public function test_test_send_dispatches_a_mail_to_the_current_user(): void
|
|
{
|
|
// Force the smtp mailer onto the in-memory `array` transport so the test-send
|
|
// captures the message WITHOUT opening a real SMTP connection. The component's
|
|
// runtime config() only sets host/port/etc., never `transport`, so this sticks
|
|
// across its Mail::purge('smtp') rebuild — fully deterministic, no network.
|
|
config(['mail.mailers.smtp.transport' => 'array']);
|
|
|
|
$user = $this->actingUser();
|
|
Setting::put('mail_host', 'smtp.example.com');
|
|
Setting::put('mail_from_address', 'panel@example.com');
|
|
|
|
Livewire::test(Email::class)
|
|
->set('mail_host', 'smtp.example.com')
|
|
->set('mail_from_address', 'panel@example.com')
|
|
->call('sendTest')
|
|
->assertHasNoErrors();
|
|
|
|
$messages = app('mailer')->getSymfonyTransport()->messages();
|
|
$this->assertCount(1, $messages, 'exactly one test mail must be sent');
|
|
|
|
$sent = $messages[0]->getOriginalMessage();
|
|
$recipients = array_map(fn ($a) => $a->getAddress(), $sent->getTo());
|
|
$this->assertSame([$user->email], $recipients, 'test mail must go only to the current user');
|
|
}
|
|
|
|
public function test_test_send_does_nothing_when_unconfigured(): void
|
|
{
|
|
Mail::fake();
|
|
$this->actingUser();
|
|
|
|
Livewire::test(Email::class)
|
|
->call('sendTest')
|
|
->assertHasNoErrors();
|
|
|
|
Mail::assertNothingSent();
|
|
}
|
|
|
|
public function test_audit_event_is_recorded_on_save(): void
|
|
{
|
|
$this->actingUser();
|
|
|
|
Livewire::test(Email::class)
|
|
->set('mail_host', 'smtp.example.com')
|
|
->set('mail_from_address', 'panel@example.com')
|
|
->set('mail_from_name', 'Clusev')
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$this->assertSame(1, AuditEvent::where('action', 'mail.configure')->count());
|
|
}
|
|
}
|