306 lines
12 KiB
PHP
306 lines
12 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Tests\Unit\Models;
|
||
|
|
|
||
|
|
use App\Models\Article;
|
||
|
|
use App\Models\ArticlePublication;
|
||
|
|
use App\Models\PlatformChannel;
|
||
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
|
|
use Tests\TestCase;
|
||
|
|
|
||
|
|
class ArticlePublicationTest extends TestCase
|
||
|
|
{
|
||
|
|
use RefreshDatabase;
|
||
|
|
|
||
|
|
public function test_fillable_fields(): void
|
||
|
|
{
|
||
|
|
$fillableFields = ['article_id', 'platform_channel_id', 'post_id', 'published_at', 'published_by', 'platform', 'publication_data'];
|
||
|
|
$publication = new ArticlePublication();
|
||
|
|
|
||
|
|
$this->assertEquals($fillableFields, $publication->getFillable());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_table_name(): void
|
||
|
|
{
|
||
|
|
$publication = new ArticlePublication();
|
||
|
|
|
||
|
|
$this->assertEquals('article_publications', $publication->getTable());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_casts_published_at_to_datetime(): void
|
||
|
|
{
|
||
|
|
$timestamp = now()->subHours(2);
|
||
|
|
$publication = ArticlePublication::factory()->create(['published_at' => $timestamp]);
|
||
|
|
|
||
|
|
$this->assertInstanceOf(\Carbon\Carbon::class, $publication->published_at);
|
||
|
|
$this->assertEquals($timestamp->format('Y-m-d H:i:s'), $publication->published_at->format('Y-m-d H:i:s'));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_casts_publication_data_to_array(): void
|
||
|
|
{
|
||
|
|
$publicationData = [
|
||
|
|
'post_url' => 'https://lemmy.world/post/123',
|
||
|
|
'platform_response' => [
|
||
|
|
'id' => 123,
|
||
|
|
'status' => 'success',
|
||
|
|
'metadata' => ['views' => 0, 'votes' => 0]
|
||
|
|
],
|
||
|
|
'retry_count' => 0
|
||
|
|
];
|
||
|
|
|
||
|
|
$publication = ArticlePublication::factory()->create(['publication_data' => $publicationData]);
|
||
|
|
|
||
|
|
$this->assertIsArray($publication->publication_data);
|
||
|
|
$this->assertEquals($publicationData, $publication->publication_data);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_belongs_to_article_relationship(): void
|
||
|
|
{
|
||
|
|
$article = Article::factory()->create();
|
||
|
|
$publication = ArticlePublication::factory()->create(['article_id' => $article->id]);
|
||
|
|
|
||
|
|
$this->assertInstanceOf(Article::class, $publication->article);
|
||
|
|
$this->assertEquals($article->id, $publication->article->id);
|
||
|
|
$this->assertEquals($article->title, $publication->article->title);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_creation_with_factory(): void
|
||
|
|
{
|
||
|
|
$publication = ArticlePublication::factory()->create();
|
||
|
|
|
||
|
|
$this->assertInstanceOf(ArticlePublication::class, $publication);
|
||
|
|
$this->assertNotNull($publication->article_id);
|
||
|
|
$this->assertNotNull($publication->platform_channel_id);
|
||
|
|
$this->assertIsString($publication->post_id);
|
||
|
|
$this->assertInstanceOf(\Carbon\Carbon::class, $publication->published_at);
|
||
|
|
$this->assertIsString($publication->published_by);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_creation_with_explicit_values(): void
|
||
|
|
{
|
||
|
|
$article = Article::factory()->create();
|
||
|
|
$channel = PlatformChannel::factory()->create();
|
||
|
|
$publicationData = ['status' => 'success', 'external_id' => '12345'];
|
||
|
|
$publishedAt = now()->subHours(1);
|
||
|
|
|
||
|
|
$publication = ArticlePublication::create([
|
||
|
|
'article_id' => $article->id,
|
||
|
|
'platform_channel_id' => $channel->id,
|
||
|
|
'post_id' => 'post-123',
|
||
|
|
'published_at' => $publishedAt,
|
||
|
|
'published_by' => 'test_bot',
|
||
|
|
'platform' => 'lemmy',
|
||
|
|
'publication_data' => $publicationData
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->assertEquals($article->id, $publication->article_id);
|
||
|
|
$this->assertEquals($channel->id, $publication->platform_channel_id);
|
||
|
|
$this->assertEquals('post-123', $publication->post_id);
|
||
|
|
$this->assertEquals($publishedAt->format('Y-m-d H:i:s'), $publication->published_at->format('Y-m-d H:i:s'));
|
||
|
|
$this->assertEquals('test_bot', $publication->published_by);
|
||
|
|
$this->assertEquals('lemmy', $publication->platform);
|
||
|
|
$this->assertEquals($publicationData, $publication->publication_data);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_factory_recently_published_state(): void
|
||
|
|
{
|
||
|
|
$publication = ArticlePublication::factory()->recentlyPublished()->create();
|
||
|
|
|
||
|
|
$this->assertInstanceOf(\Carbon\Carbon::class, $publication->published_at);
|
||
|
|
$this->assertTrue($publication->published_at->isAfter(now()->subDay()));
|
||
|
|
$this->assertTrue($publication->published_at->isBefore(now()->addMinute()));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_update(): void
|
||
|
|
{
|
||
|
|
$publication = ArticlePublication::factory()->create([
|
||
|
|
'post_id' => 'original-id',
|
||
|
|
'published_by' => 'original_user'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$publication->update([
|
||
|
|
'post_id' => 'updated-id',
|
||
|
|
'published_by' => 'updated_user'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$publication->refresh();
|
||
|
|
|
||
|
|
$this->assertEquals('updated-id', $publication->post_id);
|
||
|
|
$this->assertEquals('updated_user', $publication->published_by);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_deletion(): void
|
||
|
|
{
|
||
|
|
$publication = ArticlePublication::factory()->create();
|
||
|
|
$publicationId = $publication->id;
|
||
|
|
|
||
|
|
$publication->delete();
|
||
|
|
|
||
|
|
$this->assertDatabaseMissing('article_publications', ['id' => $publicationId]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_data_can_be_empty_array(): void
|
||
|
|
{
|
||
|
|
$publication = ArticlePublication::factory()->create(['publication_data' => []]);
|
||
|
|
|
||
|
|
$this->assertIsArray($publication->publication_data);
|
||
|
|
$this->assertEmpty($publication->publication_data);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_data_can_be_null(): void
|
||
|
|
{
|
||
|
|
$publication = ArticlePublication::factory()->create(['publication_data' => null]);
|
||
|
|
|
||
|
|
$this->assertNull($publication->publication_data);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_data_can_be_complex_structure(): void
|
||
|
|
{
|
||
|
|
$complexData = [
|
||
|
|
'platform_response' => [
|
||
|
|
'post_id' => 'abc123',
|
||
|
|
'url' => 'https://lemmy.world/post/abc123',
|
||
|
|
'created_at' => '2023-01-01T12:00:00Z',
|
||
|
|
'author' => [
|
||
|
|
'id' => 456,
|
||
|
|
'name' => 'bot_user',
|
||
|
|
'display_name' => 'Bot User'
|
||
|
|
]
|
||
|
|
],
|
||
|
|
'metadata' => [
|
||
|
|
'retry_attempts' => 1,
|
||
|
|
'processing_time_ms' => 1250,
|
||
|
|
'error_log' => []
|
||
|
|
],
|
||
|
|
'analytics' => [
|
||
|
|
'initial_views' => 0,
|
||
|
|
'initial_votes' => 0,
|
||
|
|
'engagement_tracked' => false
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$publication = ArticlePublication::factory()->create(['publication_data' => $complexData]);
|
||
|
|
|
||
|
|
$this->assertEquals($complexData, $publication->publication_data);
|
||
|
|
$this->assertEquals('abc123', $publication->publication_data['platform_response']['post_id']);
|
||
|
|
$this->assertEquals(1, $publication->publication_data['metadata']['retry_attempts']);
|
||
|
|
$this->assertFalse($publication->publication_data['analytics']['engagement_tracked']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_with_specific_published_at(): void
|
||
|
|
{
|
||
|
|
$timestamp = now()->subHours(3);
|
||
|
|
$publication = ArticlePublication::factory()->create(['published_at' => $timestamp]);
|
||
|
|
|
||
|
|
$this->assertInstanceOf(\Carbon\Carbon::class, $publication->published_at);
|
||
|
|
$this->assertEquals($timestamp->format('Y-m-d H:i:s'), $publication->published_at->format('Y-m-d H:i:s'));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_with_specific_published_by(): void
|
||
|
|
{
|
||
|
|
$publication = ArticlePublication::factory()->create(['published_by' => 'custom_bot']);
|
||
|
|
|
||
|
|
$this->assertEquals('custom_bot', $publication->published_by);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_with_specific_platform(): void
|
||
|
|
{
|
||
|
|
$publication = ArticlePublication::factory()->create(['platform' => 'lemmy']);
|
||
|
|
|
||
|
|
$this->assertEquals('lemmy', $publication->platform);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_timestamps(): void
|
||
|
|
{
|
||
|
|
$publication = ArticlePublication::factory()->create();
|
||
|
|
|
||
|
|
$this->assertNotNull($publication->created_at);
|
||
|
|
$this->assertNotNull($publication->updated_at);
|
||
|
|
$this->assertInstanceOf(\Carbon\Carbon::class, $publication->created_at);
|
||
|
|
$this->assertInstanceOf(\Carbon\Carbon::class, $publication->updated_at);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_multiple_publications_for_same_article(): void
|
||
|
|
{
|
||
|
|
$article = Article::factory()->create();
|
||
|
|
$channel1 = PlatformChannel::factory()->create();
|
||
|
|
$channel2 = PlatformChannel::factory()->create();
|
||
|
|
|
||
|
|
$publication1 = ArticlePublication::factory()->create([
|
||
|
|
'article_id' => $article->id,
|
||
|
|
'platform_channel_id' => $channel1->id,
|
||
|
|
'post_id' => 'post-1'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$publication2 = ArticlePublication::factory()->create([
|
||
|
|
'article_id' => $article->id,
|
||
|
|
'platform_channel_id' => $channel2->id,
|
||
|
|
'post_id' => 'post-2'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->assertEquals($article->id, $publication1->article_id);
|
||
|
|
$this->assertEquals($article->id, $publication2->article_id);
|
||
|
|
$this->assertNotEquals($publication1->platform_channel_id, $publication2->platform_channel_id);
|
||
|
|
$this->assertNotEquals($publication1->post_id, $publication2->post_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_with_different_platforms(): void
|
||
|
|
{
|
||
|
|
$publication1 = ArticlePublication::factory()->create(['platform' => 'lemmy']);
|
||
|
|
$publication2 = ArticlePublication::factory()->create(['platform' => 'lemmy']);
|
||
|
|
|
||
|
|
$this->assertEquals('lemmy', $publication1->platform);
|
||
|
|
$this->assertEquals('lemmy', $publication2->platform);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_post_id_variations(): void
|
||
|
|
{
|
||
|
|
$publications = [
|
||
|
|
ArticlePublication::factory()->create(['post_id' => 'numeric-123']),
|
||
|
|
ArticlePublication::factory()->create(['post_id' => 'uuid-' . fake()->uuid()]),
|
||
|
|
ArticlePublication::factory()->create(['post_id' => 'alphanumeric_post_456']),
|
||
|
|
ArticlePublication::factory()->create(['post_id' => '12345']),
|
||
|
|
];
|
||
|
|
|
||
|
|
foreach ($publications as $publication) {
|
||
|
|
$this->assertIsString($publication->post_id);
|
||
|
|
$this->assertNotEmpty($publication->post_id);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_data_with_error_information(): void
|
||
|
|
{
|
||
|
|
$errorData = [
|
||
|
|
'status' => 'failed',
|
||
|
|
'error' => [
|
||
|
|
'code' => 403,
|
||
|
|
'message' => 'Insufficient permissions',
|
||
|
|
'details' => 'Bot account lacks posting privileges'
|
||
|
|
],
|
||
|
|
'retry_info' => [
|
||
|
|
'max_retries' => 3,
|
||
|
|
'current_attempt' => 2,
|
||
|
|
'next_retry_at' => '2023-01-01T13:00:00Z'
|
||
|
|
]
|
||
|
|
];
|
||
|
|
|
||
|
|
$publication = ArticlePublication::factory()->create(['publication_data' => $errorData]);
|
||
|
|
|
||
|
|
$this->assertEquals('failed', $publication->publication_data['status']);
|
||
|
|
$this->assertEquals(403, $publication->publication_data['error']['code']);
|
||
|
|
$this->assertEquals(2, $publication->publication_data['retry_info']['current_attempt']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_publication_relationship_with_article_data(): void
|
||
|
|
{
|
||
|
|
$article = Article::factory()->create([
|
||
|
|
'title' => 'Test Article Title',
|
||
|
|
'description' => 'Test article description'
|
||
|
|
]);
|
||
|
|
|
||
|
|
$publication = ArticlePublication::factory()->create(['article_id' => $article->id]);
|
||
|
|
|
||
|
|
$this->assertEquals('Test Article Title', $publication->article->title);
|
||
|
|
$this->assertEquals('Test article description', $publication->article->description);
|
||
|
|
}
|
||
|
|
}
|