125 lines
5.0 KiB
PHP
125 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Modals\SmtpSetup;
|
|
use App\Models\Addon;
|
|
use App\Models\Device;
|
|
use App\Models\User;
|
|
use App\Services\NotificationService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
class NotificationTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function configureSmtp(array $events = ['device_offline' => true, 'low_battery' => true, 'automation' => true]): void
|
|
{
|
|
Addon::create([
|
|
'key' => 'smtp',
|
|
'installed' => true,
|
|
'status' => 'connected',
|
|
'config' => [
|
|
'host' => 'smtp.example.com', 'port' => 587, 'encryption' => 'tls',
|
|
'username' => 'u', 'password' => 'p', 'from_email' => 'homeos@example.com',
|
|
'from_name' => 'HomeOS', 'to_email' => 'me@example.com', 'events' => $events,
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function test_notify_does_nothing_without_the_smtp_addon(): void
|
|
{
|
|
Mail::fake();
|
|
$this->assertFalse(app(NotificationService::class)->notify('device_offline', 's', 'b'));
|
|
}
|
|
|
|
public function test_notify_respects_the_per_event_toggle(): void
|
|
{
|
|
Mail::fake();
|
|
$this->configureSmtp(['device_offline' => false, 'low_battery' => true, 'automation' => true]);
|
|
|
|
$this->assertFalse(app(NotificationService::class)->notify('device_offline', 's', 'b'));
|
|
$this->assertTrue(app(NotificationService::class)->notify('low_battery', 's', 'b'));
|
|
}
|
|
|
|
public function test_smtp_setup_persists_config_and_keeps_password(): void
|
|
{
|
|
$this->actingAs(User::factory()->create());
|
|
|
|
Livewire::test(SmtpSetup::class)
|
|
->set('host', 'smtp.gmail.com')->set('port', '587')->set('encryption', 'tls')
|
|
->set('username', 'me')->set('password', 'secret')
|
|
->set('fromEmail', 'from@x.com')->set('toEmail', 'to@x.com')
|
|
->set('evLowBattery', false)
|
|
->call('save')
|
|
->assertRedirect(route('addons.index'));
|
|
|
|
$cfg = Addon::where('key', 'smtp')->first()->config;
|
|
$this->assertSame('smtp.gmail.com', $cfg['host']);
|
|
$this->assertSame('secret', $cfg['password']);
|
|
$this->assertFalse($cfg['events']['low_battery']);
|
|
|
|
// Re-saving with a blank password keeps the stored one.
|
|
Livewire::test(SmtpSetup::class)
|
|
->set('host', 'smtp.gmail.com')->set('port', '465')->set('encryption', 'ssl')
|
|
->set('fromEmail', 'from@x.com')->set('toEmail', 'to@x.com')
|
|
->set('password', '')
|
|
->call('save');
|
|
|
|
$this->assertSame('secret', Addon::where('key', 'smtp')->first()->config['password']);
|
|
}
|
|
|
|
public function test_dead_battery_at_zero_percent_alerts(): void
|
|
{
|
|
Mail::fake();
|
|
$this->configureSmtp();
|
|
|
|
$device = \App\Models\Device::create(['name' => 'Sensor', 'vendor' => 'Shelly', 'protocol' => 'mqtt', 'status' => 'active', 'demo' => false, 'last_seen_at' => now(), 'config' => ['mqtt_prefix' => 'x']]);
|
|
$entity = \App\Models\Entity::create(['device_id' => $device->id, 'type' => 'battery', 'key' => 'battery:0']);
|
|
\App\Models\DeviceState::create(['entity_id' => $entity->id, 'state' => ['percent' => 0]]);
|
|
|
|
$this->artisan('notifications:sweep')->assertSuccessful();
|
|
|
|
$this->assertTrue(Cache::has("notified:battery:{$entity->id}"));
|
|
}
|
|
|
|
public function test_smtp_setup_allows_no_encryption(): void
|
|
{
|
|
$this->actingAs(User::factory()->create());
|
|
|
|
Livewire::test(SmtpSetup::class)
|
|
->set('host', 'localhost')->set('port', '25')->set('encryption', '')
|
|
->set('fromEmail', 'a@b.com')->set('toEmail', 'c@d.com')
|
|
->call('save')
|
|
->assertHasNoErrors()
|
|
->assertRedirect(route('addons.index'));
|
|
|
|
$this->assertSame('', Addon::where('key', 'smtp')->first()->config['encryption']);
|
|
}
|
|
|
|
public function test_sweep_emails_once_per_offline_device(): void
|
|
{
|
|
Mail::fake();
|
|
$this->configureSmtp();
|
|
|
|
// Active, not demo, stale last_seen → offline.
|
|
$device = Device::create(['name' => 'Lampe', 'vendor' => 'Shelly', 'protocol' => 'http', 'status' => 'active', 'demo' => false, 'last_seen_at' => now()->subHour(), 'config' => ['ip' => '1.2.3.4']]);
|
|
|
|
$this->artisan('notifications:sweep')->assertSuccessful();
|
|
$this->assertTrue(Cache::has("notified:offline:{$device->id}"));
|
|
|
|
// Second sweep — still flagged, no re-notify (flag unchanged).
|
|
$this->artisan('notifications:sweep')->assertSuccessful();
|
|
$this->assertTrue(Cache::has("notified:offline:{$device->id}"));
|
|
|
|
// Back online → flag cleared so a future outage notifies again.
|
|
$device->update(['last_seen_at' => now()]);
|
|
$this->artisan('notifications:sweep')->assertSuccessful();
|
|
$this->assertFalse(Cache::has("notified:offline:{$device->id}"));
|
|
}
|
|
}
|