296 lines
10 KiB
PHP
296 lines
10 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Services\Auth;
|
|
|
|
use App\Enums\PlatformEnum;
|
|
use App\Exceptions\PlatformAuthException;
|
|
use App\Models\PlatformAccount;
|
|
use App\Modules\Lemmy\Services\LemmyApiService;
|
|
use App\Services\Auth\LemmyAuthService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Cache\CacheManager;
|
|
use Tests\TestCase;
|
|
|
|
class LemmyAuthServiceTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// Don't set default HTTP mocks here - let individual tests control them
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function test_get_token_returns_cached_token_when_available(): void
|
|
{
|
|
// Mock HTTP to prevent any external calls (not needed since token is cached)
|
|
Http::fake(['*' => Http::response('', 500)]);
|
|
|
|
$account = PlatformAccount::factory()->create([
|
|
'username' => 'testuser',
|
|
'password' => 'testpass',
|
|
'instance_url' => 'https://lemmy.test'
|
|
]);
|
|
|
|
$cachedToken = 'cached-jwt-token';
|
|
$cacheKey = "lemmy_jwt_token_{$account->id}";
|
|
|
|
// Put token in cache using Laravel's testing cache
|
|
cache()->put($cacheKey, $cachedToken, 3000);
|
|
|
|
$result = LemmyAuthService::getToken($account);
|
|
|
|
$this->assertEquals($cachedToken, $result);
|
|
}
|
|
|
|
public function test_get_token_throws_exception_when_username_missing(): void
|
|
{
|
|
// Mock HTTP to prevent any external calls (not needed since it throws before API call)
|
|
Http::fake(['*' => Http::response('', 500)]);
|
|
|
|
// Create account with valid data first, then modify username property
|
|
$account = PlatformAccount::factory()->create([
|
|
'username' => 'testuser',
|
|
'password' => 'testpass',
|
|
'instance_url' => 'https://lemmy.test'
|
|
]);
|
|
|
|
// Use reflection to set username to null to bypass validation
|
|
$reflection = new \ReflectionClass($account);
|
|
$property = $reflection->getProperty('attributes');
|
|
$property->setAccessible(true);
|
|
$attributes = $property->getValue($account);
|
|
$attributes['username'] = null;
|
|
$property->setValue($account, $attributes);
|
|
|
|
// Ensure no cached token exists
|
|
cache()->forget("lemmy_jwt_token_{$account->id}");
|
|
|
|
$this->expectException(PlatformAuthException::class);
|
|
$this->expectExceptionMessage('Missing credentials for account: ');
|
|
|
|
LemmyAuthService::getToken($account);
|
|
}
|
|
|
|
public function test_get_token_throws_exception_when_password_missing(): void
|
|
{
|
|
// Mock HTTP to prevent any external calls
|
|
Http::fake(['*' => Http::response('', 500)]);
|
|
|
|
// Create account with valid data first, then modify password property
|
|
$account = PlatformAccount::factory()->create([
|
|
'username' => 'testuser',
|
|
'password' => 'testpass',
|
|
'instance_url' => 'https://lemmy.test'
|
|
]);
|
|
|
|
// Use reflection to set password to null to bypass validation
|
|
$reflection = new \ReflectionClass($account);
|
|
$property = $reflection->getProperty('attributes');
|
|
$property->setAccessible(true);
|
|
$attributes = $property->getValue($account);
|
|
$attributes['password'] = null;
|
|
$property->setValue($account, $attributes);
|
|
|
|
// Ensure no cached token exists
|
|
cache()->forget("lemmy_jwt_token_{$account->id}");
|
|
|
|
$this->expectException(PlatformAuthException::class);
|
|
$this->expectExceptionMessage('Missing credentials for account: testuser');
|
|
|
|
LemmyAuthService::getToken($account);
|
|
}
|
|
|
|
public function test_get_token_throws_exception_when_instance_url_missing(): void
|
|
{
|
|
// Mock HTTP to prevent any external calls
|
|
Http::fake(['*' => Http::response('', 500)]);
|
|
|
|
// Create account with valid data first, then modify instance_url property
|
|
$account = PlatformAccount::factory()->create([
|
|
'username' => 'testuser',
|
|
'password' => 'testpass',
|
|
'instance_url' => 'https://lemmy.test'
|
|
]);
|
|
|
|
// Use reflection to set instance_url to null to bypass validation
|
|
$reflection = new \ReflectionClass($account);
|
|
$property = $reflection->getProperty('attributes');
|
|
$property->setAccessible(true);
|
|
$attributes = $property->getValue($account);
|
|
$attributes['instance_url'] = null;
|
|
$property->setValue($account, $attributes);
|
|
|
|
// Ensure no cached token exists
|
|
cache()->forget("lemmy_jwt_token_{$account->id}");
|
|
|
|
$this->expectException(PlatformAuthException::class);
|
|
$this->expectExceptionMessage('Missing credentials for account: testuser');
|
|
|
|
LemmyAuthService::getToken($account);
|
|
}
|
|
|
|
public function test_get_token_successfully_authenticates_and_caches_token(): void
|
|
{
|
|
// Mock successful HTTP response for both HTTPS and HTTP (fallback)
|
|
Http::fake([
|
|
'https://lemmy.test/api/v3/user/login' => Http::response(['jwt' => 'jwt-123'], 200),
|
|
'http://lemmy.test/api/v3/user/login' => Http::response(['jwt' => 'jwt-123'], 200)
|
|
]);
|
|
|
|
$account = PlatformAccount::factory()->create([
|
|
'username' => 'testuser',
|
|
'password' => 'testpass',
|
|
'instance_url' => 'https://lemmy.test'
|
|
]);
|
|
|
|
$cacheKey = "lemmy_jwt_token_{$account->id}";
|
|
|
|
// Ensure no cached token exists initially
|
|
cache()->forget($cacheKey);
|
|
|
|
$result = LemmyAuthService::getToken($account);
|
|
|
|
$this->assertEquals('jwt-123', $result);
|
|
|
|
// Verify token was cached
|
|
$this->assertEquals('jwt-123', cache()->get($cacheKey));
|
|
}
|
|
|
|
public function test_get_token_throws_exception_when_login_fails(): void
|
|
{
|
|
// Mock failed HTTP response for both HTTPS and HTTP
|
|
Http::fake([
|
|
'https://lemmy.test/api/v3/user/login' => Http::response(['error' => 'Invalid credentials'], 401),
|
|
'http://lemmy.test/api/v3/user/login' => Http::response(['error' => 'Invalid credentials'], 401)
|
|
]);
|
|
|
|
$account = PlatformAccount::factory()->create([
|
|
'username' => 'failingUser',
|
|
'password' => 'badpass',
|
|
'instance_url' => 'https://lemmy.test'
|
|
]);
|
|
|
|
$cacheKey = "lemmy_jwt_token_{$account->id}";
|
|
|
|
// Ensure no cached token exists
|
|
Cache::forget($cacheKey);
|
|
|
|
$this->expectException(PlatformAuthException::class);
|
|
$this->expectExceptionMessage('Login failed for account: failingUser');
|
|
|
|
LemmyAuthService::getToken($account);
|
|
}
|
|
|
|
public function test_get_token_throws_exception_when_login_returns_false(): void
|
|
{
|
|
// Mock response with empty/missing JWT for both HTTPS and HTTP
|
|
Http::fake([
|
|
'https://lemmy.test/api/v3/user/login' => Http::response(['success' => false], 200),
|
|
'http://lemmy.test/api/v3/user/login' => Http::response(['success' => false], 200)
|
|
]);
|
|
|
|
$account = PlatformAccount::factory()->create([
|
|
'username' => 'emptyUser',
|
|
'password' => 'pass',
|
|
'instance_url' => 'https://lemmy.test'
|
|
]);
|
|
|
|
$cacheKey = "lemmy_jwt_token_{$account->id}";
|
|
|
|
// Ensure no cached token exists
|
|
Cache::forget($cacheKey);
|
|
|
|
$this->expectException(PlatformAuthException::class);
|
|
$this->expectExceptionMessage('Login failed for account: emptyUser');
|
|
|
|
LemmyAuthService::getToken($account);
|
|
}
|
|
|
|
public function test_get_token_uses_correct_cache_duration(): void
|
|
{
|
|
// Mock successful HTTP response for both HTTPS and HTTP
|
|
Http::fake([
|
|
'https://lemmy.test/api/v3/user/login' => Http::response(['jwt' => 'xyz'], 200),
|
|
'http://lemmy.test/api/v3/user/login' => Http::response(['jwt' => 'xyz'], 200)
|
|
]);
|
|
|
|
$account = PlatformAccount::factory()->create([
|
|
'username' => 'cacheUser',
|
|
'password' => 'secret',
|
|
'instance_url' => 'https://lemmy.test'
|
|
]);
|
|
|
|
$cacheKey = "lemmy_jwt_token_{$account->id}";
|
|
|
|
// Ensure no cached token exists initially
|
|
cache()->forget($cacheKey);
|
|
|
|
$token = LemmyAuthService::getToken($account);
|
|
$this->assertEquals('xyz', $token);
|
|
|
|
// Verify token was cached
|
|
$this->assertEquals('xyz', cache()->get($cacheKey));
|
|
}
|
|
|
|
public function test_get_token_uses_account_specific_cache_key(): void
|
|
{
|
|
// Mock HTTP to prevent any external calls
|
|
Http::fake(['*' => Http::response('', 500)]);
|
|
|
|
$account1 = PlatformAccount::factory()->create(['username' => 'user1']);
|
|
$account2 = PlatformAccount::factory()->create(['username' => 'user2']);
|
|
|
|
$cacheKey1 = "lemmy_jwt_token_{$account1->id}";
|
|
$cacheKey2 = "lemmy_jwt_token_{$account2->id}";
|
|
|
|
// Set up different cached tokens for each account
|
|
cache()->put($cacheKey1, 'token1', 3000);
|
|
cache()->put($cacheKey2, 'token2', 3000);
|
|
|
|
$result1 = LemmyAuthService::getToken($account1);
|
|
$result2 = LemmyAuthService::getToken($account2);
|
|
|
|
$this->assertEquals('token1', $result1);
|
|
$this->assertEquals('token2', $result2);
|
|
}
|
|
|
|
public function test_platform_auth_exception_contains_correct_platform(): void
|
|
{
|
|
// Mock HTTP to prevent any external calls
|
|
Http::fake(['*' => Http::response('', 500)]);
|
|
|
|
// Create account with valid data first, then modify username property
|
|
$account = PlatformAccount::factory()->create([
|
|
'username' => 'testuser',
|
|
'password' => 'testpass',
|
|
'instance_url' => 'https://lemmy.test'
|
|
]);
|
|
|
|
// Use reflection to set username to null to bypass validation
|
|
$reflection = new \ReflectionClass($account);
|
|
$property = $reflection->getProperty('attributes');
|
|
$property->setAccessible(true);
|
|
$attributes = $property->getValue($account);
|
|
$attributes['username'] = null;
|
|
$property->setValue($account, $attributes);
|
|
|
|
// Ensure no cached token exists
|
|
cache()->forget("lemmy_jwt_token_{$account->id}");
|
|
|
|
try {
|
|
LemmyAuthService::getToken($account);
|
|
$this->fail('Expected PlatformAuthException to be thrown');
|
|
} catch (PlatformAuthException $e) {
|
|
$this->assertEquals(PlatformEnum::LEMMY, $e->getPlatform());
|
|
}
|
|
}
|
|
}
|