'a@a.com', 'code' => '111111', 'expires_at' => now()->subMinute()]); OtpCode::create(['identifier' => 'b@b.com', 'code' => '222222', 'expires_at' => now()->addHour()]); $prunableIds = (new OtpCode)->prunable()->pluck('id'); expect($prunableIds)->toHaveCount(1); }); test('OtpCode prunable returns a Builder instance', function () { expect((new OtpCode)->prunable())->toBeInstanceOf(Builder::class); }); // ── UserTrustedDevice ───────────────────────────────────────────────────────── test('UserTrustedDevice prunable selects expired devices only', function () { $user = User::factory()->create(); UserTrustedDevice::create([ 'user_id' => $user->id, 'device_id' => 'old-device', 'token' => 'tok1', 'expires_at' => now()->subDay(), ]); UserTrustedDevice::create([ 'user_id' => $user->id, 'device_id' => 'fresh-device', 'token' => 'tok2', 'expires_at' => now()->addDays(30), ]); $ids = (new UserTrustedDevice)->prunable()->pluck('id'); expect($ids)->toHaveCount(1); }); test('UserTrustedDevice prunable returns a Builder instance', function () { expect((new UserTrustedDevice)->prunable())->toBeInstanceOf(Builder::class); }); // ── PasswordHistory ─────────────────────────────────────────────────────────── test('PasswordHistory prunable selects records older than 365 days', function () { $user = User::factory()->create(); \DB::table('password_histories')->insert([ ['user_id' => $user->id, 'password' => 'h1', 'created_at' => now()->subDays(400), 'updated_at' => now()], ['user_id' => $user->id, 'password' => 'h2', 'created_at' => now()->subDays(100), 'updated_at' => now()], ]); $ids = (new PasswordHistory)->prunable()->pluck('id'); expect($ids)->toHaveCount(1); }); test('PasswordHistory prunable returns a Builder instance', function () { expect((new PasswordHistory)->prunable())->toBeInstanceOf(Builder::class); }); // ── MobileSyncLog ───────────────────────────────────────────────────────────── test('MobileSyncLog prunable selects records older than 30 days', function () { \DB::table('mobile_sync_logs')->insert([ ['synced_at' => now()->subDays(35)], ['synced_at' => now()->subDays(10)], ]); $ids = (new MobileSyncLog)->prunable()->pluck('id'); expect($ids)->toHaveCount(1); }); test('MobileSyncLog prunable returns a Builder instance', function () { expect((new MobileSyncLog)->prunable())->toBeInstanceOf(Builder::class); }); // ── MobileErrorLog ──────────────────────────────────────────────────────────── test('MobileErrorLog prunable selects records older than 90 days', function () { \DB::table('mobile_error_logs')->insert([ ['message' => 'old error', 'occurred_at' => now()->subDays(100)], ['message' => 'new error', 'occurred_at' => now()->subDays(5)], ]); $ids = (new MobileErrorLog)->prunable()->pluck('id'); expect($ids)->toHaveCount(1); }); test('MobileErrorLog prunable returns a Builder instance', function () { expect((new MobileErrorLog)->prunable())->toBeInstanceOf(Builder::class); }); // ── Notification (system_notifications) ────────────────────────────────────── test('Notification prunable selects records older than 30 days', function () { \DB::table('system_notifications')->insert([ ['title' => 'old', 'message' => 'x', 'recipient' => 'all', 'type' => 'info', 'created_at' => now()->subDays(40), 'updated_at' => now()], ['title' => 'new', 'message' => 'y', 'recipient' => 'all', 'type' => 'info', 'created_at' => now()->subDays(5), 'updated_at' => now()], ]); $ids = (new Notification)->prunable()->pluck('id'); expect($ids)->toHaveCount(1); }); test('Notification prunable returns a Builder instance', function () { expect((new Notification)->prunable())->toBeInstanceOf(Builder::class); }); // ── AiHealingLog ────────────────────────────────────────────────────────────── test('AiHealingLog prunable selects records older than 90 days', function () { \DB::table('ai_healing_logs')->insert([ ['error_message' => 'old', 'created_at' => now()->subDays(100), 'updated_at' => now()], ['error_message' => 'new', 'created_at' => now()->subDays(10), 'updated_at' => now()], ]); $ids = (new AiHealingLog)->prunable()->pluck('id'); expect($ids)->toHaveCount(1); }); test('AiHealingLog prunable returns a Builder instance', function () { expect((new AiHealingLog)->prunable())->toBeInstanceOf(Builder::class); }); // ── AiUsageLog ──────────────────────────────────────────────────────────────── test('AiUsageLog prunable selects records older than 3 months', function () { \DB::table('ai_usage_logs')->insert([ ['provider' => 'openai', 'model' => 'gpt-4', 'status' => 'success', 'created_at' => now()->subMonths(4), 'updated_at' => now()], ['provider' => 'openai', 'model' => 'gpt-4', 'status' => 'success', 'created_at' => now()->subWeek(), 'updated_at' => now()], ]); $ids = (new AiUsageLog)->prunable()->pluck('id'); expect($ids)->toHaveCount(1); }); // ── Edge cases ──────────────────────────────────────────────────────────────── test('OtpCode prunable returns empty when all codes are still valid', function () { OtpCode::create(['identifier' => 'c@c.com', 'code' => '333333', 'expires_at' => now()->addHour()]); $ids = (new OtpCode)->prunable()->pluck('id'); expect($ids)->toBeEmpty(); }); test('UserTrustedDevice prunable returns empty when no devices are expired', function () { $user = User::factory()->create(); UserTrustedDevice::create([ 'user_id' => $user->id, 'device_id' => 'good-device', 'token' => 'tok3', 'expires_at' => now()->addDays(7), ]); $ids = (new UserTrustedDevice)->prunable()->pluck('id'); expect($ids)->toBeEmpty(); });