fedi-feed-router/backend/tests/Unit/Modules/Lemmy/Services/LemmyApiServiceTest.php

417 lines
13 KiB
PHP
Raw Normal View History

2025-08-07 21:19:19 +02:00
<?php
namespace Tests\Unit\Modules\Lemmy\Services;
use App\Enums\PlatformEnum;
use App\Models\PlatformChannelPost;
use App\Modules\Lemmy\LemmyRequest;
use App\Modules\Lemmy\Services\LemmyApiService;
use Exception;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Mockery;
use Tests\TestCase;
class LemmyApiServiceTest extends TestCase
{
use RefreshDatabase;
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function test_constructor_sets_instance(): void
{
$service = new LemmyApiService('lemmy.test');
$this->assertInstanceOf(LemmyApiService::class, $service);
}
public function test_login_successful(): void
{
Http::fake([
'https://lemmy.test/api/v3/user/login' => Http::response([
'jwt' => 'test-jwt-token'
], 200)
]);
$service = new LemmyApiService('lemmy.test');
$result = $service->login('testuser', 'testpass');
$this->assertEquals('test-jwt-token', $result);
Http::assertSent(function ($request) {
return $request->url() === 'https://lemmy.test/api/v3/user/login' &&
$request->method() === 'POST' &&
$request->data() === [
'username_or_email' => 'testuser',
'password' => 'testpass'
];
});
}
public function test_login_failed_response(): void
{
Http::fake([
'https://lemmy.test/api/v3/user/login' => Http::response(['error' => 'Invalid credentials'], 401)
]);
Log::shouldReceive('error')
->once()
->with('Lemmy login failed', Mockery::type('array'));
$service = new LemmyApiService('lemmy.test');
$result = $service->login('testuser', 'wrongpass');
$this->assertNull($result);
}
public function test_login_missing_jwt_in_response(): void
{
Http::fake([
'https://lemmy.test/api/v3/user/login' => Http::response(['success' => true], 200)
]);
$service = new LemmyApiService('lemmy.test');
$result = $service->login('testuser', 'testpass');
$this->assertNull($result);
}
public function test_login_exception_handling(): void
{
Http::fake([
'https://lemmy.test/api/v3/user/login' => function () {
throw new Exception('Network error');
}
]);
Log::shouldReceive('error')
->once()
->with('Lemmy login exception', ['error' => 'Network error']);
$service = new LemmyApiService('lemmy.test');
$result = $service->login('testuser', 'testpass');
$this->assertNull($result);
}
public function test_get_community_id_successful(): void
{
Http::fake([
'https://lemmy.test/api/v3/community*' => Http::response([
'community_view' => [
'community' => [
'id' => 123
]
]
], 200)
]);
$service = new LemmyApiService('lemmy.test');
$result = $service->getCommunityId('testcommunity', 'test-token');
$this->assertEquals(123, $result);
Http::assertSent(function ($request) {
return str_contains($request->url(), 'community') &&
$request->hasHeader('Authorization', 'Bearer test-token');
});
}
public function test_get_community_id_failed_response(): void
{
Http::fake([
'https://lemmy.test/api/v3/community*' => Http::response(['error' => 'Not found'], 404)
]);
Log::shouldReceive('error')
->once()
->with('Community lookup failed', Mockery::type('array'));
$service = new LemmyApiService('lemmy.test');
$this->expectException(Exception::class);
$this->expectExceptionMessage('Failed to fetch community: 404');
$service->getCommunityId('nonexistent', 'test-token');
}
public function test_get_community_id_missing_data(): void
{
Http::fake([
'https://lemmy.test/api/v3/community*' => Http::response([
'community_view' => ['community' => []]
], 200)
]);
Log::shouldReceive('error')
->once()
->with('Community lookup failed', Mockery::type('array'));
$service = new LemmyApiService('lemmy.test');
$this->expectException(Exception::class);
$this->expectExceptionMessage('Community not found');
$service->getCommunityId('testcommunity', 'test-token');
}
public function test_sync_channel_posts_successful(): void
{
Http::fake([
'https://lemmy.test/api/v3/post/list*' => Http::response([
'posts' => [
[
'post' => [
'id' => 1,
'name' => 'Test Post 1',
'url' => 'https://example.com/1',
'published' => '2023-01-01T00:00:00Z'
]
],
[
'post' => [
'id' => 2,
'name' => 'Test Post 2',
'published' => '2023-01-02T00:00:00Z'
]
]
]
], 200)
]);
Log::shouldReceive('info')
->once()
->with('Synced channel posts', [
'platform_channel_id' => 123,
'posts_count' => 2
]);
$service = new LemmyApiService('lemmy.test');
$service->syncChannelPosts('test-token', 123, 'testcommunity');
// Verify posts were stored
$this->assertDatabaseCount('platform_channel_posts', 2);
$this->assertDatabaseHas('platform_channel_posts', [
'platform' => PlatformEnum::LEMMY,
'channel_id' => '123',
'post_id' => '1'
]);
}
public function test_sync_channel_posts_failed_response(): void
{
Http::fake([
'https://lemmy.test/api/v3/post/list*' => Http::response(['error' => 'Unauthorized'], 401)
]);
Log::shouldReceive('warning')
->once()
->with('Failed to sync channel posts', [
'status' => 401,
'platform_channel_id' => 123
]);
$service = new LemmyApiService('lemmy.test');
$service->syncChannelPosts('test-token', 123, 'testcommunity');
// Verify no posts were stored
$this->assertDatabaseCount('platform_channel_posts', 0);
}
public function test_sync_channel_posts_exception_handling(): void
{
Http::fake([
'https://lemmy.test/api/v3/post/list*' => function () {
throw new Exception('Network error');
}
]);
Log::shouldReceive('error')
->once()
->with('Exception while syncing channel posts', [
'error' => 'Network error',
'platform_channel_id' => 123
]);
$service = new LemmyApiService('lemmy.test');
$service->syncChannelPosts('test-token', 123, 'testcommunity');
$this->assertDatabaseCount('platform_channel_posts', 0);
}
public function test_create_post_successful_minimal_data(): void
{
Http::fake([
'https://lemmy.test/api/v3/post' => Http::response([
'post_view' => [
'post' => [
'id' => 456,
'name' => 'Test Title'
]
]
], 200)
]);
$service = new LemmyApiService('lemmy.test');
$result = $service->createPost('test-token', 'Test Title', 'Test Body', 123);
$this->assertIsArray($result);
$this->assertEquals(456, $result['post_view']['post']['id']);
Http::assertSent(function ($request) {
return $request->url() === 'https://lemmy.test/api/v3/post' &&
$request->method() === 'POST' &&
$request->data() === [
'name' => 'Test Title',
'body' => 'Test Body',
'community_id' => 123
];
});
}
public function test_create_post_successful_with_all_optional_data(): void
{
Http::fake([
'https://lemmy.test/api/v3/post' => Http::response([
'post_view' => ['post' => ['id' => 456]]
], 200)
]);
$service = new LemmyApiService('lemmy.test');
$result = $service->createPost(
'test-token',
'Test Title',
'Test Body',
123,
'https://example.com',
'https://example.com/thumb.jpg',
2
);
$this->assertIsArray($result);
Http::assertSent(function ($request) {
return $request->data() === [
'name' => 'Test Title',
'body' => 'Test Body',
'community_id' => 123,
'url' => 'https://example.com',
'custom_thumbnail' => 'https://example.com/thumb.jpg',
'language_id' => 2
];
});
}
public function test_create_post_failed_response(): void
{
Http::fake([
'https://lemmy.test/api/v3/post' => Http::response(['error' => 'Validation failed'], 400)
]);
Log::shouldReceive('error')
->once()
->with('Post creation failed', Mockery::type('array'));
$service = new LemmyApiService('lemmy.test');
$this->expectException(Exception::class);
$this->expectExceptionMessage('Failed to create post: 400');
$service->createPost('test-token', 'Test Title', 'Test Body', 123);
}
public function test_create_post_exception_handling(): void
{
Http::fake([
'https://lemmy.test/api/v3/post' => function () {
throw new Exception('Network error');
}
]);
Log::shouldReceive('error')
->once()
->with('Post creation failed', ['error' => 'Network error']);
$service = new LemmyApiService('lemmy.test');
$this->expectException(Exception::class);
$this->expectExceptionMessage('Network error');
$service->createPost('test-token', 'Test Title', 'Test Body', 123);
}
public function test_get_languages_successful(): void
{
Http::fake([
'https://lemmy.test/api/v3/site' => Http::response([
'all_languages' => [
['id' => 0, 'code' => 'und', 'name' => 'Undetermined'],
['id' => 1, 'code' => 'en', 'name' => 'English'],
['id' => 2, 'code' => 'es', 'name' => 'Spanish']
]
], 200)
]);
$service = new LemmyApiService('lemmy.test');
$result = $service->getLanguages();
$this->assertIsArray($result);
$this->assertCount(3, $result);
$this->assertEquals('English', $result[1]['name']);
}
public function test_get_languages_failed_response(): void
{
Http::fake([
'https://lemmy.test/api/v3/site' => Http::response(['error' => 'Server error'], 500)
]);
Log::shouldReceive('warning')
->once()
->with('Failed to fetch site languages', ['status' => 500]);
$service = new LemmyApiService('lemmy.test');
$result = $service->getLanguages();
$this->assertIsArray($result);
$this->assertEmpty($result);
}
public function test_get_languages_missing_data(): void
{
Http::fake([
'https://lemmy.test/api/v3/site' => Http::response(['site_view' => []], 200)
]);
$service = new LemmyApiService('lemmy.test');
$result = $service->getLanguages();
$this->assertIsArray($result);
$this->assertEmpty($result);
}
public function test_get_languages_exception_handling(): void
{
Http::fake([
'https://lemmy.test/api/v3/site' => function () {
throw new Exception('Network error');
}
]);
Log::shouldReceive('error')
->once()
->with('Exception while fetching languages', ['error' => 'Network error']);
$service = new LemmyApiService('lemmy.test');
$result = $service->getLanguages();
$this->assertIsArray($result);
$this->assertEmpty($result);
}
}