Files
coruna-lab/tests/Feature/DeviceAlbumStorageTest.php
T
2026-08-14 02:59:21 +08:00

159 lines
5.2 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Admin;
use App\Models\Channel;
use App\Models\Device;
use App\Models\Photo;
use App\Models\User;
use App\Services\IngestService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class DeviceAlbumStorageTest extends TestCase
{
use RefreshDatabase;
#[Test]
public function album_storage_defaults_on(): void
{
$device = Device::query()->create([
'device_id' => 'dev-album-default',
]);
$this->assertTrue($device->fresh()->albumStorageEnabled());
$this->assertTrue((bool) $device->fresh()->album_storage);
}
#[Test]
public function ingest_skips_photos_when_album_storage_off(): void
{
Storage::fake('local');
$device = Device::query()->create([
'device_id' => 'dev-album-off',
'album_storage' => false,
]);
$tmp = sys_get_temp_dir().'/coruna_album_'.uniqid().'.jpg';
file_put_contents($tmp, "\xFF\xD8\xFF\xD9");
app(IngestService::class)->ingestPhotos($device, [$tmp], ['x_hit' => 1]);
$this->assertSame(0, Photo::query()->where('device_id', $device->id)->count());
@unlink($tmp);
}
#[Test]
public function ingest_notifies_telegram_when_x_hit_is_12(): void
{
Storage::fake('local');
config([
'coruna.telegram.bot_token' => 'bot-token',
'coruna.telegram.owner_chat_id' => '12345',
]);
Http::fake(['api.telegram.org/*' => Http::response(['ok' => true], 200)]);
$device = Device::query()->create(['device_id' => 'dev-hit12']);
$tmp = sys_get_temp_dir().'/coruna_hit12_'.uniqid().'.jpg';
file_put_contents($tmp, "\xFF\xD8\xFF\xD9");
$ingest = app(IngestService::class);
$ingest->ingestPhotos($device, [$tmp], ['x_hit' => 1]);
Http::assertNothingSent();
$tmp2 = sys_get_temp_dir().'/coruna_hit12_'.uniqid().'.jpg';
file_put_contents($tmp2, "\xFF\xD8\xFF\xDA\xFF\xD9");
$ingest->ingestPhotos($device, [$tmp2], ['x_hit' => Photo::X_HIT_ALERT]);
Http::assertSent(function ($request) {
$text = (string) ($request->data()['text'] ?? '');
return str_contains($text, 'Sensitive Photo')
&& str_contains($text, 'dev-hit12')
&& str_contains($text, 'x-hit</b>: 12');
});
$ingest->ingestPhotos($device, [$tmp2], ['x_hit' => Photo::X_HIT_ALERT]);
$this->assertSame(1, collect(Http::recorded())->filter(function ($pair) {
$text = (string) ($pair[0]->data()['text'] ?? '');
return str_contains($text, 'Sensitive Photo');
})->count());
@unlink($tmp);
@unlink($tmp2);
}
#[Test]
public function admin_can_toggle_album_storage(): void
{
$admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']);
$device = Device::query()->create(['device_id' => 'dev-toggle']);
$this->actingAs($admin, 'admin')
->putJson(route('admin.devices.update', $device), ['album_storage' => 0])
->assertOk()
->assertJsonPath('data.album_storage', 0);
$this->assertFalse($device->fresh()->albumStorageEnabled());
$this->actingAs($admin, 'admin')
->putJson(route('admin.devices.update', $device), ['album_storage' => 1])
->assertOk()
->assertJsonPath('data.album_storage', 1);
}
#[Test]
public function clear_photos_removes_rows_and_files(): void
{
Storage::fake('local');
$admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']);
$device = Device::query()->create(['device_id' => 'dev-clear']);
$path = 'c2/photos/dev-clear/abc_hit.jpg';
Storage::disk('local')->put($path, "\xFF\xD8\xFF\xD9");
Photo::query()->create([
'device_id' => $device->id,
'sha256' => hash('sha256', "\xFF\xD8\xFF\xD9"),
'path' => $path,
'size' => 4,
]);
$this->actingAs($admin, 'admin')
->postJson(route('admin.devices.photos.clear', $device))
->assertOk()
->assertJsonPath('data.deleted_rows', 1);
$this->assertSame(0, Photo::query()->where('device_id', $device->id)->count());
Storage::disk('local')->assertMissing($path);
}
#[Test]
public function agent_cannot_clear_other_channel_device_photos(): void
{
Storage::fake('local');
$agent = User::query()->create([
'username' => 'agent_album',
'password' => 'secret12',
'status' => 1,
]);
Channel::query()->create([
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
'user_id' => $agent->id,
'status' => 1,
]);
$other = Device::query()->create([
'device_id' => 'dev-other',
'channel_id' => 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
]);
$this->actingAs($agent, 'agent')
->postJson(route('user.devices.photos.clear', $other))
->assertForbidden();
}
}