393 lines
13 KiB
PHP
393 lines
13 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Tests\Unit\Modules\Lemmy\Services;
|
||
|
|
|
||
|
|
use App\Enums\PlatformEnum;
|
||
|
|
use App\Exceptions\PlatformAuthException;
|
||
|
|
use App\Models\Article;
|
||
|
|
use App\Models\PlatformAccount;
|
||
|
|
use App\Models\PlatformChannel;
|
||
|
|
use App\Models\PlatformInstance;
|
||
|
|
use App\Modules\Lemmy\Services\LemmyApiService;
|
||
|
|
use App\Modules\Lemmy\Services\LemmyPublisher;
|
||
|
|
use App\Services\Auth\LemmyAuthService;
|
||
|
|
use Exception;
|
||
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
|
|
use Illuminate\Support\Facades\Cache;
|
||
|
|
use Illuminate\Support\Facades\Http;
|
||
|
|
use Illuminate\Support\Facades\Queue;
|
||
|
|
use Mockery;
|
||
|
|
use Tests\TestCase;
|
||
|
|
|
||
|
|
class LemmyPublisherTest extends TestCase
|
||
|
|
{
|
||
|
|
use RefreshDatabase;
|
||
|
|
|
||
|
|
protected function setUp(): void
|
||
|
|
{
|
||
|
|
parent::setUp();
|
||
|
|
Queue::fake();
|
||
|
|
Http::fake();
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function tearDown(): void
|
||
|
|
{
|
||
|
|
Mockery::close();
|
||
|
|
parent::tearDown();
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_constructor_creates_api_service(): void
|
||
|
|
{
|
||
|
|
$account = PlatformAccount::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'instance_url' => 'https://lemmy.test'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$publisher = new LemmyPublisher($account);
|
||
|
|
|
||
|
|
$this->assertInstanceOf(LemmyPublisher::class, $publisher);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publish_to_channel_with_minimal_data(): void
|
||
|
|
{
|
||
|
|
$account = PlatformAccount::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'instance_url' => 'https://lemmy.test',
|
||
|
|
'username' => 'testuser',
|
||
|
|
'password' => 'testpass'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$article = Article::factory()->create([
|
||
|
|
'url' => 'https://example.com/article'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$instance = PlatformInstance::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'url' => 'https://lemmy.test'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$channel = PlatformChannel::factory()->create([
|
||
|
|
'platform_instance_id' => $instance->id,
|
||
|
|
'channel_id' => 123,
|
||
|
|
'name' => 'testcommunity'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$extractedData = [
|
||
|
|
'title' => 'Test Article',
|
||
|
|
'description' => 'Test Description'
|
||
|
|
];
|
||
|
|
|
||
|
|
$expectedResult = [
|
||
|
|
'post_view' => [
|
||
|
|
'post' => [
|
||
|
|
'id' => 456,
|
||
|
|
'name' => 'Test Article'
|
||
|
|
]
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
// Mock LemmyAuthService
|
||
|
|
$this->mock(LemmyAuthService::class, function ($mock) use ($account) {
|
||
|
|
$mock->shouldReceive('getToken')
|
||
|
|
->once()
|
||
|
|
->with($account)
|
||
|
|
->andReturn('test-jwt-token');
|
||
|
|
});
|
||
|
|
|
||
|
|
// Mock LemmyApiService
|
||
|
|
$apiServiceMock = Mockery::mock(LemmyApiService::class);
|
||
|
|
$apiServiceMock->shouldReceive('createPost')
|
||
|
|
->once()
|
||
|
|
->with(
|
||
|
|
'test-jwt-token',
|
||
|
|
'Test Article',
|
||
|
|
'Test Description',
|
||
|
|
123,
|
||
|
|
'https://example.com/article',
|
||
|
|
null,
|
||
|
|
null
|
||
|
|
)
|
||
|
|
->andReturn($expectedResult);
|
||
|
|
|
||
|
|
// Use reflection to replace the api service in the publisher
|
||
|
|
$publisher = new LemmyPublisher($account);
|
||
|
|
$reflection = new \ReflectionClass($publisher);
|
||
|
|
$apiProperty = $reflection->getProperty('api');
|
||
|
|
$apiProperty->setAccessible(true);
|
||
|
|
$apiProperty->setValue($publisher, $apiServiceMock);
|
||
|
|
|
||
|
|
$result = $publisher->publishToChannel($article, $extractedData, $channel);
|
||
|
|
|
||
|
|
$this->assertEquals($expectedResult, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publish_to_channel_with_all_optional_data(): void
|
||
|
|
{
|
||
|
|
$account = PlatformAccount::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'instance_url' => 'https://lemmy.test',
|
||
|
|
'username' => 'testuser',
|
||
|
|
'password' => 'testpass'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$article = Article::factory()->create([
|
||
|
|
'url' => 'https://example.com/article'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$instance = PlatformInstance::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'url' => 'https://lemmy.test'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$channel = PlatformChannel::factory()->create([
|
||
|
|
'platform_instance_id' => $instance->id,
|
||
|
|
'channel_id' => 123,
|
||
|
|
'name' => 'testcommunity'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$extractedData = [
|
||
|
|
'title' => 'Test Article',
|
||
|
|
'description' => 'Test Description',
|
||
|
|
'thumbnail' => 'https://example.com/thumb.jpg',
|
||
|
|
'language_id' => 2
|
||
|
|
];
|
||
|
|
|
||
|
|
$expectedResult = [
|
||
|
|
'post_view' => [
|
||
|
|
'post' => [
|
||
|
|
'id' => 456,
|
||
|
|
'name' => 'Test Article'
|
||
|
|
]
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
// Mock LemmyAuthService
|
||
|
|
$this->mock(LemmyAuthService::class, function ($mock) use ($account) {
|
||
|
|
$mock->shouldReceive('getToken')
|
||
|
|
->once()
|
||
|
|
->with($account)
|
||
|
|
->andReturn('test-jwt-token');
|
||
|
|
});
|
||
|
|
|
||
|
|
// Mock LemmyApiService
|
||
|
|
$apiServiceMock = Mockery::mock(LemmyApiService::class);
|
||
|
|
$apiServiceMock->shouldReceive('createPost')
|
||
|
|
->once()
|
||
|
|
->with(
|
||
|
|
'test-jwt-token',
|
||
|
|
'Test Article',
|
||
|
|
'Test Description',
|
||
|
|
123,
|
||
|
|
'https://example.com/article',
|
||
|
|
'https://example.com/thumb.jpg',
|
||
|
|
2
|
||
|
|
)
|
||
|
|
->andReturn($expectedResult);
|
||
|
|
|
||
|
|
// Use reflection to replace the api service in the publisher
|
||
|
|
$publisher = new LemmyPublisher($account);
|
||
|
|
$reflection = new \ReflectionClass($publisher);
|
||
|
|
$apiProperty = $reflection->getProperty('api');
|
||
|
|
$apiProperty->setAccessible(true);
|
||
|
|
$apiProperty->setValue($publisher, $apiServiceMock);
|
||
|
|
|
||
|
|
$result = $publisher->publishToChannel($article, $extractedData, $channel);
|
||
|
|
|
||
|
|
$this->assertEquals($expectedResult, $result);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publish_to_channel_with_missing_title_uses_default(): void
|
||
|
|
{
|
||
|
|
$this->expectNotToPerformAssertions();
|
||
|
|
|
||
|
|
$account = PlatformAccount::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'instance_url' => 'https://lemmy.test',
|
||
|
|
'username' => 'testuser',
|
||
|
|
'password' => 'testpass'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$article = Article::factory()->create([
|
||
|
|
'url' => 'https://example.com/article'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$instance = PlatformInstance::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'url' => 'https://lemmy.test'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$channel = PlatformChannel::factory()->create([
|
||
|
|
'platform_instance_id' => $instance->id,
|
||
|
|
'channel_id' => 123,
|
||
|
|
'name' => 'testcommunity'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$extractedData = [
|
||
|
|
'description' => 'Test Description'
|
||
|
|
];
|
||
|
|
|
||
|
|
// Mock LemmyAuthService
|
||
|
|
$this->mock(LemmyAuthService::class, function ($mock) use ($account) {
|
||
|
|
$mock->shouldReceive('getToken')
|
||
|
|
->once()
|
||
|
|
->with($account)
|
||
|
|
->andReturn('test-jwt-token');
|
||
|
|
});
|
||
|
|
|
||
|
|
// Mock LemmyApiService
|
||
|
|
$apiServiceMock = Mockery::mock(LemmyApiService::class);
|
||
|
|
$apiServiceMock->shouldReceive('createPost')
|
||
|
|
->once()
|
||
|
|
->with(
|
||
|
|
'test-jwt-token',
|
||
|
|
'Untitled',
|
||
|
|
'Test Description',
|
||
|
|
123,
|
||
|
|
'https://example.com/article',
|
||
|
|
null,
|
||
|
|
null
|
||
|
|
)
|
||
|
|
->andReturn([]);
|
||
|
|
|
||
|
|
// Use reflection to replace the api service in the publisher
|
||
|
|
$publisher = new LemmyPublisher($account);
|
||
|
|
$reflection = new \ReflectionClass($publisher);
|
||
|
|
$apiProperty = $reflection->getProperty('api');
|
||
|
|
$apiProperty->setAccessible(true);
|
||
|
|
$apiProperty->setValue($publisher, $apiServiceMock);
|
||
|
|
|
||
|
|
$publisher->publishToChannel($article, $extractedData, $channel);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publish_to_channel_with_missing_description_uses_default(): void
|
||
|
|
{
|
||
|
|
$this->expectNotToPerformAssertions();
|
||
|
|
|
||
|
|
$account = PlatformAccount::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'instance_url' => 'https://lemmy.test',
|
||
|
|
'username' => 'testuser',
|
||
|
|
'password' => 'testpass'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$article = Article::factory()->create([
|
||
|
|
'url' => 'https://example.com/article'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$instance = PlatformInstance::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'url' => 'https://lemmy.test'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$channel = PlatformChannel::factory()->create([
|
||
|
|
'platform_instance_id' => $instance->id,
|
||
|
|
'channel_id' => 123,
|
||
|
|
'name' => 'testcommunity'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$extractedData = [
|
||
|
|
'title' => 'Test Title'
|
||
|
|
];
|
||
|
|
|
||
|
|
// Mock LemmyAuthService
|
||
|
|
$this->mock(LemmyAuthService::class, function ($mock) use ($account) {
|
||
|
|
$mock->shouldReceive('getToken')
|
||
|
|
->once()
|
||
|
|
->with($account)
|
||
|
|
->andReturn('test-jwt-token');
|
||
|
|
});
|
||
|
|
|
||
|
|
// Mock LemmyApiService
|
||
|
|
$apiServiceMock = Mockery::mock(LemmyApiService::class);
|
||
|
|
$apiServiceMock->shouldReceive('createPost')
|
||
|
|
->once()
|
||
|
|
->with(
|
||
|
|
'test-jwt-token',
|
||
|
|
'Test Title',
|
||
|
|
'',
|
||
|
|
123,
|
||
|
|
'https://example.com/article',
|
||
|
|
null,
|
||
|
|
null
|
||
|
|
)
|
||
|
|
->andReturn([]);
|
||
|
|
|
||
|
|
// Use reflection to replace the api service in the publisher
|
||
|
|
$publisher = new LemmyPublisher($account);
|
||
|
|
$reflection = new \ReflectionClass($publisher);
|
||
|
|
$apiProperty = $reflection->getProperty('api');
|
||
|
|
$apiProperty->setAccessible(true);
|
||
|
|
$apiProperty->setValue($publisher, $apiServiceMock);
|
||
|
|
|
||
|
|
$publisher->publishToChannel($article, $extractedData, $channel);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publish_to_channel_throws_platform_auth_exception_when_auth_fails(): void
|
||
|
|
{
|
||
|
|
$account = PlatformAccount::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'instance_url' => 'https://lemmy.test',
|
||
|
|
'username' => 'testuser',
|
||
|
|
'password' => 'testpass'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$article = Article::factory()->create();
|
||
|
|
$channel = PlatformChannel::factory()->create();
|
||
|
|
$extractedData = ['title' => 'Test', 'description' => 'Test'];
|
||
|
|
|
||
|
|
// Mock LemmyAuthService to throw exception
|
||
|
|
$this->mock(LemmyAuthService::class, function ($mock) use ($account) {
|
||
|
|
$mock->shouldReceive('getToken')
|
||
|
|
->once()
|
||
|
|
->with($account)
|
||
|
|
->andThrow(new PlatformAuthException(PlatformEnum::LEMMY, 'Auth failed'));
|
||
|
|
});
|
||
|
|
|
||
|
|
$publisher = new LemmyPublisher($account);
|
||
|
|
|
||
|
|
$this->expectException(PlatformAuthException::class);
|
||
|
|
$this->expectExceptionMessage('Auth failed');
|
||
|
|
|
||
|
|
$publisher->publishToChannel($article, $extractedData, $channel);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publish_to_channel_throws_exception_when_create_post_fails(): void
|
||
|
|
{
|
||
|
|
$account = PlatformAccount::factory()->create([
|
||
|
|
'platform' => PlatformEnum::LEMMY,
|
||
|
|
'instance_url' => 'https://lemmy.test',
|
||
|
|
'username' => 'testuser',
|
||
|
|
'password' => 'testpass'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$article = Article::factory()->create();
|
||
|
|
$channel = PlatformChannel::factory()->create();
|
||
|
|
$extractedData = ['title' => 'Test', 'description' => 'Test'];
|
||
|
|
|
||
|
|
// Mock LemmyAuthService
|
||
|
|
$this->mock(LemmyAuthService::class, function ($mock) use ($account) {
|
||
|
|
$mock->shouldReceive('getToken')
|
||
|
|
->once()
|
||
|
|
->with($account)
|
||
|
|
->andReturn('test-jwt-token');
|
||
|
|
});
|
||
|
|
|
||
|
|
// Mock LemmyApiService to throw exception
|
||
|
|
$apiServiceMock = Mockery::mock(LemmyApiService::class);
|
||
|
|
$apiServiceMock->shouldReceive('createPost')
|
||
|
|
->once()
|
||
|
|
->andThrow(new Exception('Post creation failed'));
|
||
|
|
|
||
|
|
// Use reflection to replace the api service in the publisher
|
||
|
|
$publisher = new LemmyPublisher($account);
|
||
|
|
$reflection = new \ReflectionClass($publisher);
|
||
|
|
$apiProperty = $reflection->getProperty('api');
|
||
|
|
$apiProperty->setAccessible(true);
|
||
|
|
$apiProperty->setValue($publisher, $apiServiceMock);
|
||
|
|
|
||
|
|
$this->expectException(Exception::class);
|
||
|
|
$this->expectExceptionMessage('Post creation failed');
|
||
|
|
|
||
|
|
$publisher->publishToChannel($article, $extractedData, $channel);
|
||
|
|
}
|
||
|
|
}
|