fedi-feed-router/tests/Unit/Models/PlatformAccountTest.php

417 lines
No EOL
15 KiB
PHP

<?php
namespace Tests\Unit\Models;
use App\Enums\PlatformEnum;
use App\Models\PlatformAccount;
use App\Models\PlatformChannel;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Crypt;
use Tests\TestCase;
class PlatformAccountTest extends TestCase
{
use RefreshDatabase;
public function test_fillable_fields(): void
{
$fillableFields = ['platform', 'instance_url', 'username', 'password', 'settings', 'is_active', 'last_tested_at', 'status'];
$account = new PlatformAccount();
$this->assertEquals($fillableFields, $account->getFillable());
}
public function test_table_name(): void
{
$account = new PlatformAccount();
$this->assertEquals('platform_accounts', $account->getTable());
}
public function test_casts_platform_to_enum(): void
{
$account = PlatformAccount::factory()->create(['platform' => PlatformEnum::LEMMY]);
$this->assertInstanceOf(PlatformEnum::class, $account->platform);
$this->assertEquals(PlatformEnum::LEMMY, $account->platform);
$this->assertEquals('lemmy', $account->platform->value);
}
public function test_casts_settings_to_array(): void
{
$settings = ['key1' => 'value1', 'nested' => ['key2' => 'value2']];
$account = PlatformAccount::factory()->create(['settings' => $settings]);
$this->assertIsArray($account->settings);
$this->assertEquals($settings, $account->settings);
}
public function test_casts_is_active_to_boolean(): void
{
$account = PlatformAccount::factory()->create(['is_active' => '1']);
$this->assertIsBool($account->is_active);
$this->assertTrue($account->is_active);
$account->update(['is_active' => '0']);
$account->refresh();
$this->assertIsBool($account->is_active);
$this->assertFalse($account->is_active);
}
public function test_casts_last_tested_at_to_datetime(): void
{
$timestamp = now()->subHours(2);
$account = PlatformAccount::factory()->create(['last_tested_at' => $timestamp]);
$this->assertInstanceOf(\Carbon\Carbon::class, $account->last_tested_at);
$this->assertEquals($timestamp->format('Y-m-d H:i:s'), $account->last_tested_at->format('Y-m-d H:i:s'));
}
public function test_password_encryption_and_decryption(): void
{
$plainPassword = 'my-secret-password';
$account = PlatformAccount::factory()->create(['password' => $plainPassword]);
// Password should be decrypted when accessing
$this->assertEquals($plainPassword, $account->password);
// But encrypted in the database
$this->assertNotEquals($plainPassword, $account->getAttributes()['password']);
$this->assertNotNull($account->getAttributes()['password']);
}
public function test_password_with_specific_value(): void
{
$password = 'specific-test-password';
$account = PlatformAccount::factory()->create(['password' => $password]);
$this->assertEquals($password, $account->password);
$this->assertNotEquals($password, $account->getAttributes()['password']);
}
public function test_password_encryption_is_different_each_time(): void
{
$password = 'same-password';
$account1 = PlatformAccount::factory()->create(['password' => $password]);
$account2 = PlatformAccount::factory()->create(['password' => $password]);
$this->assertEquals($password, $account1->password);
$this->assertEquals($password, $account2->password);
$this->assertNotEquals($account1->getAttributes()['password'], $account2->getAttributes()['password']);
}
public function test_password_decryption_handles_corruption(): void
{
$account = PlatformAccount::factory()->create();
$originalPassword = $account->password;
// Since the password attribute has special handling, this test verifies the basic functionality
$this->assertNotNull($originalPassword);
$this->assertIsString($originalPassword);
}
public function test_get_active_static_method(): void
{
// Create active and inactive accounts
$activeAccount1 = PlatformAccount::factory()->create([
'platform' => PlatformEnum::LEMMY,
'is_active' => true
]);
$activeAccount2 = PlatformAccount::factory()->create([
'platform' => PlatformEnum::LEMMY,
'is_active' => true
]);
$inactiveAccount = PlatformAccount::factory()->create([
'platform' => PlatformEnum::LEMMY,
'is_active' => false
]);
$activeAccounts = PlatformAccount::getActive(PlatformEnum::LEMMY);
$this->assertCount(2, $activeAccounts);
$this->assertTrue($activeAccounts->contains('id', $activeAccount1->id));
$this->assertTrue($activeAccounts->contains('id', $activeAccount2->id));
$this->assertFalse($activeAccounts->contains('id', $inactiveAccount->id));
}
public function test_set_as_active_method(): void
{
// Create multiple accounts for same platform
$account1 = PlatformAccount::factory()->create([
'platform' => PlatformEnum::LEMMY,
'is_active' => true
]);
$account2 = PlatformAccount::factory()->create([
'platform' => PlatformEnum::LEMMY,
'is_active' => true
]);
$account3 = PlatformAccount::factory()->create([
'platform' => PlatformEnum::LEMMY,
'is_active' => false
]);
// Set account3 as active
$account3->setAsActive();
// Refresh all accounts
$account1->refresh();
$account2->refresh();
$account3->refresh();
// Only account3 should be active
$this->assertFalse($account1->is_active);
$this->assertFalse($account2->is_active);
$this->assertTrue($account3->is_active);
}
public function test_belongs_to_many_channels_relationship(): void
{
$account = PlatformAccount::factory()->create();
$channel1 = PlatformChannel::factory()->create();
$channel2 = PlatformChannel::factory()->create();
// Attach channels with pivot data
$account->channels()->attach($channel1->id, [
'is_active' => true,
'priority' => 100
]);
$account->channels()->attach($channel2->id, [
'is_active' => false,
'priority' => 50
]);
$channels = $account->channels;
$this->assertCount(2, $channels);
$this->assertTrue($channels->contains('id', $channel1->id));
$this->assertTrue($channels->contains('id', $channel2->id));
// Test pivot data
$channel1FromRelation = $channels->find($channel1->id);
$this->assertEquals(1, $channel1FromRelation->pivot->is_active);
$this->assertEquals(100, $channel1FromRelation->pivot->priority);
$channel2FromRelation = $channels->find($channel2->id);
$this->assertEquals(0, $channel2FromRelation->pivot->is_active);
$this->assertEquals(50, $channel2FromRelation->pivot->priority);
}
public function test_active_channels_relationship(): void
{
$account = PlatformAccount::factory()->create();
$activeChannel1 = PlatformChannel::factory()->create();
$activeChannel2 = PlatformChannel::factory()->create();
$inactiveChannel = PlatformChannel::factory()->create();
// Attach channels
$account->channels()->attach($activeChannel1->id, [
'is_active' => true,
'priority' => 100
]);
$account->channels()->attach($activeChannel2->id, [
'is_active' => true,
'priority' => 200
]);
$account->channels()->attach($inactiveChannel->id, [
'is_active' => false,
'priority' => 150
]);
$activeChannels = $account->activeChannels;
$this->assertCount(2, $activeChannels);
$this->assertTrue($activeChannels->contains('id', $activeChannel1->id));
$this->assertTrue($activeChannels->contains('id', $activeChannel2->id));
$this->assertFalse($activeChannels->contains('id', $inactiveChannel->id));
// Test ordering by priority descending
$channelIds = $activeChannels->pluck('id')->toArray();
$this->assertEquals($activeChannel2->id, $channelIds[0]); // Priority 200
$this->assertEquals($activeChannel1->id, $channelIds[1]); // Priority 100
}
public function test_account_creation_with_factory(): void
{
$account = PlatformAccount::factory()->create();
$this->assertInstanceOf(PlatformAccount::class, $account);
$this->assertInstanceOf(PlatformEnum::class, $account->platform);
$this->assertEquals(PlatformEnum::LEMMY, $account->platform);
$this->assertIsString($account->instance_url);
$this->assertIsString($account->username);
$this->assertEquals('test-password', $account->password);
$this->assertIsBool($account->is_active);
$this->assertTrue($account->is_active);
$this->assertEquals('untested', $account->status);
$this->assertIsArray($account->settings);
}
public function test_account_creation_with_explicit_values(): void
{
$settings = ['custom' => 'value', 'nested' => ['key' => 'value']];
$timestamp = now()->subHours(1);
$account = PlatformAccount::create([
'platform' => PlatformEnum::LEMMY,
'instance_url' => 'https://lemmy.example.com',
'username' => 'testuser',
'password' => 'secret123',
'settings' => $settings,
'is_active' => false,
'last_tested_at' => $timestamp,
'status' => 'working'
]);
$this->assertEquals(PlatformEnum::LEMMY, $account->platform);
$this->assertEquals('https://lemmy.example.com', $account->instance_url);
$this->assertEquals('testuser', $account->username);
$this->assertEquals('secret123', $account->password);
$this->assertEquals($settings, $account->settings);
$this->assertFalse($account->is_active);
$this->assertEquals($timestamp->format('Y-m-d H:i:s'), $account->last_tested_at->format('Y-m-d H:i:s'));
$this->assertEquals('working', $account->status);
}
public function test_account_factory_states(): void
{
$inactiveAccount = PlatformAccount::factory()->inactive()->create();
$this->assertFalse($inactiveAccount->is_active);
$testedAccount = PlatformAccount::factory()->tested()->create();
$this->assertNotNull($testedAccount->last_tested_at);
$this->assertEquals('working', $testedAccount->status);
$failedAccount = PlatformAccount::factory()->failed()->create();
$this->assertNotNull($failedAccount->last_tested_at);
$this->assertEquals('failed', $failedAccount->status);
}
public function test_account_update(): void
{
$account = PlatformAccount::factory()->create([
'username' => 'original_user',
'is_active' => true
]);
$account->update([
'username' => 'updated_user',
'is_active' => false
]);
$account->refresh();
$this->assertEquals('updated_user', $account->username);
$this->assertFalse($account->is_active);
}
public function test_account_deletion(): void
{
$account = PlatformAccount::factory()->create();
$accountId = $account->id;
$account->delete();
$this->assertDatabaseMissing('platform_accounts', ['id' => $accountId]);
}
public function test_account_settings_can_be_empty_array(): void
{
$account = PlatformAccount::factory()->create(['settings' => []]);
$this->assertIsArray($account->settings);
$this->assertEmpty($account->settings);
}
public function test_account_settings_can_be_complex_structure(): void
{
$complexSettings = [
'authentication' => [
'method' => 'jwt',
'timeout' => 30
],
'features' => ['posting', 'commenting'],
'rate_limits' => [
'posts_per_hour' => 10,
'comments_per_hour' => 50
]
];
$account = PlatformAccount::factory()->create(['settings' => $complexSettings]);
$this->assertEquals($complexSettings, $account->settings);
$this->assertEquals('jwt', $account->settings['authentication']['method']);
$this->assertEquals(['posting', 'commenting'], $account->settings['features']);
}
public function test_account_can_have_null_last_tested_at(): void
{
$account = PlatformAccount::factory()->create(['last_tested_at' => null]);
$this->assertNull($account->last_tested_at);
}
public function test_account_timestamps(): void
{
$account = PlatformAccount::factory()->create();
$this->assertNotNull($account->created_at);
$this->assertNotNull($account->updated_at);
$this->assertInstanceOf(\Carbon\Carbon::class, $account->created_at);
$this->assertInstanceOf(\Carbon\Carbon::class, $account->updated_at);
}
public function test_account_can_have_multiple_channels_with_different_priorities(): void
{
$account = PlatformAccount::factory()->create();
$channel1 = PlatformChannel::factory()->create();
$channel2 = PlatformChannel::factory()->create();
$channel3 = PlatformChannel::factory()->create();
// Attach channels with different priorities
$account->channels()->attach([
$channel1->id => ['is_active' => true, 'priority' => 300],
$channel2->id => ['is_active' => true, 'priority' => 100],
$channel3->id => ['is_active' => false, 'priority' => 200]
]);
$allChannels = $account->channels;
$activeChannels = $account->activeChannels;
$this->assertCount(3, $allChannels);
$this->assertCount(2, $activeChannels);
// Test that we can access pivot data
foreach ($allChannels as $channel) {
$this->assertNotNull($channel->pivot->priority);
$this->assertIsInt($channel->pivot->is_active);
}
}
public function test_password_withoutObjectCaching_prevents_caching(): void
{
$account = PlatformAccount::factory()->create(['password' => 'original']);
// Access password to potentially cache it
$originalPassword = $account->password;
$this->assertEquals('original', $originalPassword);
// Update password directly in database
$account->update(['password' => 'updated']);
// Since withoutObjectCaching is used, the new value should be retrieved
$account->refresh();
$this->assertEquals('updated', $account->password);
}
}