From 5a142d2a3cdcf6150e3dafd2d9c987f24a7051a0 Mon Sep 17 00:00:00 2001 From: myrmidex Date: Tue, 5 Aug 2025 21:53:49 +0200 Subject: [PATCH] Add missing endpoint tests --- .../Api/V1/PlatformAccountsController.php | 11 +- .../Api/V1/PlatformChannelsController.php | 14 +- .../Controllers/Api/V1/RoutingController.php | 12 +- .../Resources/PlatformAccountResource.php | 10 +- backend/app/Models/Route.php | 8 +- .../Controllers/Api/V1/LogsControllerTest.php | 193 +++++++++ .../Api/V1/PlatformAccountsControllerTest.php | 204 +++++++++ .../Api/V1/PlatformChannelsControllerTest.php | 234 +++++++++++ .../Api/V1/RoutingControllerTest.php | 390 ++++++++++++++++++ 9 files changed, 1052 insertions(+), 24 deletions(-) create mode 100644 backend/tests/Feature/Http/Controllers/Api/V1/LogsControllerTest.php create mode 100644 backend/tests/Feature/Http/Controllers/Api/V1/PlatformAccountsControllerTest.php create mode 100644 backend/tests/Feature/Http/Controllers/Api/V1/PlatformChannelsControllerTest.php create mode 100644 backend/tests/Feature/Http/Controllers/Api/V1/RoutingControllerTest.php diff --git a/backend/app/Http/Controllers/Api/V1/PlatformAccountsController.php b/backend/app/Http/Controllers/Api/V1/PlatformAccountsController.php index 7e23fcf..f9b3a58 100644 --- a/backend/app/Http/Controllers/Api/V1/PlatformAccountsController.php +++ b/backend/app/Http/Controllers/Api/V1/PlatformAccountsController.php @@ -17,8 +17,7 @@ class PlatformAccountsController extends BaseController */ public function index(): JsonResponse { - $accounts = PlatformAccount::with(['platformInstance']) - ->orderBy('platform') + $accounts = PlatformAccount::orderBy('platform') ->orderBy('created_at', 'desc') ->get(); @@ -63,7 +62,7 @@ public function store(Request $request): JsonResponse } return $this->sendResponse( - new PlatformAccountResource($account->load('platformInstance')), + new PlatformAccountResource($account), 'Platform account created successfully!', 201 ); @@ -80,7 +79,7 @@ public function store(Request $request): JsonResponse public function show(PlatformAccount $platformAccount): JsonResponse { return $this->sendResponse( - new PlatformAccountResource($platformAccount->load('platformInstance')), + new PlatformAccountResource($platformAccount), 'Platform account retrieved successfully.' ); } @@ -106,7 +105,7 @@ public function update(Request $request, PlatformAccount $platformAccount): Json $platformAccount->update($validated); return $this->sendResponse( - new PlatformAccountResource($platformAccount->fresh(['platformInstance'])), + new PlatformAccountResource($platformAccount->fresh()), 'Platform account updated successfully!' ); } catch (ValidationException $e) { @@ -142,7 +141,7 @@ public function setActive(PlatformAccount $platformAccount): JsonResponse $platformAccount->setAsActive(); return $this->sendResponse( - new PlatformAccountResource($platformAccount->fresh(['platformInstance'])), + new PlatformAccountResource($platformAccount->fresh()), "Set {$platformAccount->username}@{$platformAccount->instance_url} as active for {$platformAccount->platform->value}!" ); } catch (\Exception $e) { diff --git a/backend/app/Http/Controllers/Api/V1/PlatformChannelsController.php b/backend/app/Http/Controllers/Api/V1/PlatformChannelsController.php index eaf7f5d..9b9381f 100644 --- a/backend/app/Http/Controllers/Api/V1/PlatformChannelsController.php +++ b/backend/app/Http/Controllers/Api/V1/PlatformChannelsController.php @@ -60,10 +60,10 @@ public function store(Request $request): JsonResponse /** * Display the specified platform channel */ - public function show(PlatformChannel $channel): JsonResponse + public function show(PlatformChannel $platformChannel): JsonResponse { return $this->sendResponse( - new PlatformChannelResource($channel->load('platformInstance')), + new PlatformChannelResource($platformChannel->load('platformInstance')), 'Platform channel retrieved successfully.' ); } @@ -71,7 +71,7 @@ public function show(PlatformChannel $channel): JsonResponse /** * Update the specified platform channel */ - public function update(Request $request, PlatformChannel $channel): JsonResponse + public function update(Request $request, PlatformChannel $platformChannel): JsonResponse { try { $validated = $request->validate([ @@ -81,10 +81,10 @@ public function update(Request $request, PlatformChannel $channel): JsonResponse 'is_active' => 'boolean', ]); - $channel->update($validated); + $platformChannel->update($validated); return $this->sendResponse( - new PlatformChannelResource($channel->fresh(['platformInstance'])), + new PlatformChannelResource($platformChannel->fresh(['platformInstance'])), 'Platform channel updated successfully!' ); } catch (ValidationException $e) { @@ -97,10 +97,10 @@ public function update(Request $request, PlatformChannel $channel): JsonResponse /** * Remove the specified platform channel */ - public function destroy(PlatformChannel $channel): JsonResponse + public function destroy(PlatformChannel $platformChannel): JsonResponse { try { - $channel->delete(); + $platformChannel->delete(); return $this->sendResponse( null, diff --git a/backend/app/Http/Controllers/Api/V1/RoutingController.php b/backend/app/Http/Controllers/Api/V1/RoutingController.php index c99a862..8f3ddb3 100644 --- a/backend/app/Http/Controllers/Api/V1/RoutingController.php +++ b/backend/app/Http/Controllers/Api/V1/RoutingController.php @@ -97,7 +97,9 @@ public function update(Request $request, Feed $feed, PlatformChannel $channel): 'priority' => 'nullable|integer|min:0', ]); - $route->update($validated); + Route::where('feed_id', $feed->id) + ->where('platform_channel_id', $channel->id) + ->update($validated); return $this->sendResponse( new RouteResource($route->fresh(['feed', 'platformChannel'])), @@ -124,7 +126,9 @@ public function destroy(Feed $feed, PlatformChannel $channel): JsonResponse return $this->sendNotFound('Routing configuration not found.'); } - $route->delete(); + Route::where('feed_id', $feed->id) + ->where('platform_channel_id', $channel->id) + ->delete(); return $this->sendResponse( null, @@ -150,7 +154,9 @@ public function toggle(Feed $feed, PlatformChannel $channel): JsonResponse } $newStatus = !$route->is_active; - $route->update(['is_active' => $newStatus]); + Route::where('feed_id', $feed->id) + ->where('platform_channel_id', $channel->id) + ->update(['is_active' => $newStatus]); $status = $newStatus ? 'activated' : 'deactivated'; diff --git a/backend/app/Http/Resources/PlatformAccountResource.php b/backend/app/Http/Resources/PlatformAccountResource.php index 8bae2f4..a32f771 100644 --- a/backend/app/Http/Resources/PlatformAccountResource.php +++ b/backend/app/Http/Resources/PlatformAccountResource.php @@ -16,15 +16,15 @@ public function toArray(Request $request): array { return [ 'id' => $this->id, - 'platform_instance_id' => $this->platform_instance_id, - 'account_id' => $this->account_id, + 'platform' => $this->platform->value, + 'instance_url' => $this->instance_url, 'username' => $this->username, - 'display_name' => $this->display_name, - 'description' => $this->description, + 'settings' => $this->settings, 'is_active' => $this->is_active, + 'last_tested_at' => $this->last_tested_at?->toISOString(), + 'status' => $this->status, 'created_at' => $this->created_at->toISOString(), 'updated_at' => $this->updated_at->toISOString(), - 'platform_instance' => new PlatformInstanceResource($this->whenLoaded('platformInstance')), 'channels' => PlatformChannelResource::collection($this->whenLoaded('channels')), ]; } diff --git a/backend/app/Models/Route.php b/backend/app/Models/Route.php index c7732c4..c18ed38 100644 --- a/backend/app/Models/Route.php +++ b/backend/app/Models/Route.php @@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\Relations\Pivot; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Carbon; /** @@ -18,13 +18,15 @@ * @property Carbon $created_at * @property Carbon $updated_at */ -class Route extends Pivot +class Route extends Model { /** @use HasFactory */ use HasFactory; protected $table = 'routes'; - + + // Laravel doesn't handle composite primary keys well, so we'll use regular queries + protected $primaryKey = null; public $incrementing = false; protected $fillable = [ diff --git a/backend/tests/Feature/Http/Controllers/Api/V1/LogsControllerTest.php b/backend/tests/Feature/Http/Controllers/Api/V1/LogsControllerTest.php new file mode 100644 index 0000000..cbdfada --- /dev/null +++ b/backend/tests/Feature/Http/Controllers/Api/V1/LogsControllerTest.php @@ -0,0 +1,193 @@ +count(5)->create(); + + $response = $this->getJson('/api/v1/logs'); + + $response->assertStatus(200) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + 'logs' => [ + '*' => [ + 'id', + 'level', + 'message', + 'context', + 'created_at', + 'updated_at', + ] + ], + 'pagination' => [ + 'current_page', + 'last_page', + 'per_page', + 'total', + 'from', + 'to', + ] + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Logs retrieved successfully.' + ]); + } + + public function test_index_orders_logs_by_created_at_desc(): void + { + $oldLog = Log::factory()->create(['created_at' => now()->subDays(2)]); + $newLog = Log::factory()->create(['created_at' => now()->subDay()]); + $newestLog = Log::factory()->create(['created_at' => now()]); + + $response = $this->getJson('/api/v1/logs'); + + $response->assertStatus(200); + + $logs = $response->json('data.logs'); + + $this->assertEquals($newestLog->id, $logs[0]['id']); + $this->assertEquals($newLog->id, $logs[1]['id']); + $this->assertEquals($oldLog->id, $logs[2]['id']); + } + + public function test_index_filters_by_level(): void + { + Log::factory()->create(['level' => LogLevelEnum::ERROR]); + Log::factory()->create(['level' => LogLevelEnum::WARNING]); + Log::factory()->create(['level' => LogLevelEnum::INFO]); + + $response = $this->getJson('/api/v1/logs?level=error'); + + $response->assertStatus(200); + + $logs = $response->json('data.logs'); + + $this->assertCount(1, $logs); + $this->assertEquals('error', $logs[0]['level']); + } + + public function test_index_respects_per_page_parameter(): void + { + Log::factory()->count(15)->create(); + + $response = $this->getJson('/api/v1/logs?per_page=5'); + + $response->assertStatus(200); + + $logs = $response->json('data.logs'); + $pagination = $response->json('data.pagination'); + + $this->assertCount(5, $logs); + $this->assertEquals(5, $pagination['per_page']); + $this->assertEquals(15, $pagination['total']); + $this->assertEquals(3, $pagination['last_page']); + } + + public function test_index_limits_per_page_to_maximum(): void + { + Log::factory()->count(10)->create(); + + $response = $this->getJson('/api/v1/logs?per_page=150'); + + $response->assertStatus(200); + + $pagination = $response->json('data.pagination'); + + // Should be limited to 100 as per controller logic + $this->assertEquals(100, $pagination['per_page']); + } + + public function test_index_uses_default_per_page_when_not_specified(): void + { + Log::factory()->count(25)->create(); + + $response = $this->getJson('/api/v1/logs'); + + $response->assertStatus(200); + + $pagination = $response->json('data.pagination'); + + // Should use default of 20 + $this->assertEquals(20, $pagination['per_page']); + } + + public function test_index_handles_empty_logs(): void + { + $response = $this->getJson('/api/v1/logs'); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Logs retrieved successfully.', + 'data' => [ + 'logs' => [], + 'pagination' => [ + 'total' => 0, + 'current_page' => 1, + 'last_page' => 1, + ] + ] + ]); + } + + public function test_index_pagination_works_correctly(): void + { + Log::factory()->count(25)->create(); + + // Test first page + $response = $this->getJson('/api/v1/logs?per_page=10&page=1'); + $response->assertStatus(200); + + $pagination = $response->json('data.pagination'); + $this->assertEquals(1, $pagination['current_page']); + $this->assertEquals(3, $pagination['last_page']); + $this->assertEquals(1, $pagination['from']); + $this->assertEquals(10, $pagination['to']); + + // Test second page + $response = $this->getJson('/api/v1/logs?per_page=10&page=2'); + $response->assertStatus(200); + + $pagination = $response->json('data.pagination'); + $this->assertEquals(2, $pagination['current_page']); + $this->assertEquals(11, $pagination['from']); + $this->assertEquals(20, $pagination['to']); + } + + public function test_index_with_multiple_log_levels(): void + { + Log::factory()->create(['level' => LogLevelEnum::ERROR, 'message' => 'Error message']); + Log::factory()->create(['level' => LogLevelEnum::WARNING, 'message' => 'Warning message']); + Log::factory()->create(['level' => LogLevelEnum::INFO, 'message' => 'Info message']); + Log::factory()->create(['level' => LogLevelEnum::DEBUG, 'message' => 'Debug message']); + + $response = $this->getJson('/api/v1/logs'); + + $response->assertStatus(200); + + $logs = $response->json('data.logs'); + + $this->assertCount(4, $logs); + + $levels = array_column($logs, 'level'); + $this->assertContains('error', $levels); + $this->assertContains('warning', $levels); + $this->assertContains('info', $levels); + $this->assertContains('debug', $levels); + } +} \ No newline at end of file diff --git a/backend/tests/Feature/Http/Controllers/Api/V1/PlatformAccountsControllerTest.php b/backend/tests/Feature/Http/Controllers/Api/V1/PlatformAccountsControllerTest.php new file mode 100644 index 0000000..ae4573a --- /dev/null +++ b/backend/tests/Feature/Http/Controllers/Api/V1/PlatformAccountsControllerTest.php @@ -0,0 +1,204 @@ +create(); + PlatformAccount::factory()->count(3)->create(); + + $response = $this->getJson('/api/v1/platform-accounts'); + + $response->assertStatus(200) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + '*' => [ + 'id', + 'platform', + 'instance_url', + 'username', + 'is_active', + 'created_at', + 'updated_at', + ] + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Platform accounts retrieved successfully.' + ]); + } + + public function test_store_creates_platform_account_successfully(): void + { + $data = [ + 'platform' => 'lemmy', + 'instance_url' => 'https://lemmy.example.com', + 'username' => 'testuser', + 'password' => 'testpass123', + 'settings' => ['key' => 'value'] + ]; + + $response = $this->postJson('/api/v1/platform-accounts', $data); + + $response->assertStatus(201) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + 'id', + 'platform', + 'instance_url', + 'username', + 'is_active', + 'created_at', + 'updated_at', + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Platform account created successfully!' + ]); + + $this->assertDatabaseHas('platform_accounts', [ + 'platform' => 'lemmy', + 'instance_url' => 'https://lemmy.example.com', + 'username' => 'testuser', + ]); + } + + public function test_store_validates_required_fields(): void + { + $response = $this->postJson('/api/v1/platform-accounts', []); + + $response->assertStatus(422) + ->assertJsonValidationErrors(['platform', 'instance_url', 'username', 'password']); + } + + public function test_show_returns_platform_account_successfully(): void + { + $account = PlatformAccount::factory()->create(); + + $response = $this->getJson("/api/v1/platform-accounts/{$account->id}"); + + $response->assertStatus(200) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + 'id', + 'platform', + 'instance_url', + 'username', + 'is_active', + 'created_at', + 'updated_at', + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Platform account retrieved successfully.', + 'data' => [ + 'id' => $account->id, + 'username' => $account->username, + ] + ]); + } + + public function test_update_modifies_platform_account_successfully(): void + { + $account = PlatformAccount::factory()->create(); + + $updateData = [ + 'instance_url' => 'https://updated.example.com', + 'username' => 'updateduser', + 'settings' => ['updated' => 'value'] + ]; + + $response = $this->putJson("/api/v1/platform-accounts/{$account->id}", $updateData); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Platform account updated successfully!' + ]); + + $this->assertDatabaseHas('platform_accounts', [ + 'id' => $account->id, + 'instance_url' => 'https://updated.example.com', + 'username' => 'updateduser', + ]); + } + + public function test_destroy_deletes_platform_account_successfully(): void + { + $account = PlatformAccount::factory()->create(); + + $response = $this->deleteJson("/api/v1/platform-accounts/{$account->id}"); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Platform account deleted successfully!' + ]); + + $this->assertDatabaseMissing('platform_accounts', [ + 'id' => $account->id + ]); + } + + public function test_set_active_activates_platform_account(): void + { + $account = PlatformAccount::factory()->create(['is_active' => false]); + + $response = $this->postJson("/api/v1/platform-accounts/{$account->id}/set-active"); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + ]); + + $this->assertDatabaseHas('platform_accounts', [ + 'id' => $account->id, + 'is_active' => true + ]); + } + + public function test_set_active_deactivates_other_accounts_of_same_platform(): void + { + $activeAccount = PlatformAccount::factory()->create([ + 'platform' => 'lemmy', + 'is_active' => true + ]); + + $newAccount = PlatformAccount::factory()->create([ + 'platform' => 'lemmy', + 'is_active' => false + ]); + + $response = $this->postJson("/api/v1/platform-accounts/{$newAccount->id}/set-active"); + + $response->assertStatus(200); + + $this->assertDatabaseHas('platform_accounts', [ + 'id' => $activeAccount->id, + 'is_active' => false + ]); + + $this->assertDatabaseHas('platform_accounts', [ + 'id' => $newAccount->id, + 'is_active' => true + ]); + } +} \ No newline at end of file diff --git a/backend/tests/Feature/Http/Controllers/Api/V1/PlatformChannelsControllerTest.php b/backend/tests/Feature/Http/Controllers/Api/V1/PlatformChannelsControllerTest.php new file mode 100644 index 0000000..1beb154 --- /dev/null +++ b/backend/tests/Feature/Http/Controllers/Api/V1/PlatformChannelsControllerTest.php @@ -0,0 +1,234 @@ +create(); + PlatformChannel::factory()->count(3)->create(['platform_instance_id' => $instance->id]); + + $response = $this->getJson('/api/v1/platform-channels'); + + $response->assertStatus(200) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + '*' => [ + 'id', + 'platform_instance_id', + 'channel_id', + 'name', + 'display_name', + 'description', + 'is_active', + 'created_at', + 'updated_at', + 'platform_instance' + ] + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Platform channels retrieved successfully.' + ]); + } + + public function test_store_creates_platform_channel_successfully(): void + { + $instance = PlatformInstance::factory()->create(); + + $data = [ + 'platform_instance_id' => $instance->id, + 'channel_id' => 'test_channel', + 'name' => 'Test Channel', + 'display_name' => 'Test Channel Display', + 'description' => 'A test channel', + 'is_active' => true + ]; + + $response = $this->postJson('/api/v1/platform-channels', $data); + + $response->assertStatus(201) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + 'id', + 'platform_instance_id', + 'channel_id', + 'name', + 'display_name', + 'description', + 'is_active', + 'created_at', + 'updated_at', + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Platform channel created successfully!' + ]); + + $this->assertDatabaseHas('platform_channels', [ + 'platform_instance_id' => $instance->id, + 'channel_id' => 'test_channel', + 'name' => 'Test Channel', + ]); + } + + public function test_store_validates_required_fields(): void + { + $response = $this->postJson('/api/v1/platform-channels', []); + + $response->assertStatus(422) + ->assertJsonValidationErrors(['platform_instance_id', 'channel_id', 'name']); + } + + public function test_store_validates_platform_instance_exists(): void + { + $data = [ + 'platform_instance_id' => 999, + 'channel_id' => 'test_channel', + 'name' => 'Test Channel' + ]; + + $response = $this->postJson('/api/v1/platform-channels', $data); + + $response->assertStatus(422) + ->assertJsonValidationErrors(['platform_instance_id']); + } + + public function test_show_returns_platform_channel_successfully(): void + { + $instance = PlatformInstance::factory()->create(); + $channel = PlatformChannel::factory()->create(['platform_instance_id' => $instance->id]); + + $response = $this->getJson("/api/v1/platform-channels/{$channel->id}"); + + $response->assertStatus(200) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + 'id', + 'platform_instance_id', + 'channel_id', + 'name', + 'display_name', + 'description', + 'is_active', + 'created_at', + 'updated_at', + 'platform_instance' + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Platform channel retrieved successfully.', + 'data' => [ + 'id' => $channel->id, + 'name' => $channel->name, + ] + ]); + } + + public function test_update_modifies_platform_channel_successfully(): void + { + $instance = PlatformInstance::factory()->create(); + $channel = PlatformChannel::factory()->create(['platform_instance_id' => $instance->id]); + + $updateData = [ + 'name' => 'Updated Channel', + 'display_name' => 'Updated Display Name', + 'description' => 'Updated description', + 'is_active' => false + ]; + + $response = $this->putJson("/api/v1/platform-channels/{$channel->id}", $updateData); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Platform channel updated successfully!' + ]); + + $this->assertDatabaseHas('platform_channels', [ + 'id' => $channel->id, + 'name' => 'Updated Channel', + 'display_name' => 'Updated Display Name', + 'is_active' => false, + ]); + } + + public function test_destroy_deletes_platform_channel_successfully(): void + { + $instance = PlatformInstance::factory()->create(); + $channel = PlatformChannel::factory()->create(['platform_instance_id' => $instance->id]); + + $response = $this->deleteJson("/api/v1/platform-channels/{$channel->id}"); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Platform channel deleted successfully!' + ]); + + $this->assertDatabaseMissing('platform_channels', [ + 'id' => $channel->id + ]); + } + + public function test_toggle_activates_inactive_channel(): void + { + $instance = PlatformInstance::factory()->create(); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'is_active' => false + ]); + + $response = $this->postJson("/api/v1/platform-channels/{$channel->id}/toggle"); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Platform channel activated successfully!' + ]); + + $this->assertDatabaseHas('platform_channels', [ + 'id' => $channel->id, + 'is_active' => true + ]); + } + + public function test_toggle_deactivates_active_channel(): void + { + $instance = PlatformInstance::factory()->create(); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'is_active' => true + ]); + + $response = $this->postJson("/api/v1/platform-channels/{$channel->id}/toggle"); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Platform channel deactivated successfully!' + ]); + + $this->assertDatabaseHas('platform_channels', [ + 'id' => $channel->id, + 'is_active' => false + ]); + } +} \ No newline at end of file diff --git a/backend/tests/Feature/Http/Controllers/Api/V1/RoutingControllerTest.php b/backend/tests/Feature/Http/Controllers/Api/V1/RoutingControllerTest.php new file mode 100644 index 0000000..c8356ea --- /dev/null +++ b/backend/tests/Feature/Http/Controllers/Api/V1/RoutingControllerTest.php @@ -0,0 +1,390 @@ +create(); + $instance = PlatformInstance::factory()->create(); + + // Create unique feeds and channels for this test + $feeds = Feed::factory()->count(3)->create(['language_id' => $language->id]); + $channels = PlatformChannel::factory()->count(3)->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + foreach ($feeds as $index => $feed) { + Route::factory()->create([ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channels[$index]->id + ]); + } + + $response = $this->getJson('/api/v1/routing'); + + $response->assertStatus(200) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + '*' => [ + 'feed_id', + 'platform_channel_id', + 'is_active', + 'priority', + 'created_at', + 'updated_at', + ] + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Routing configurations retrieved successfully.' + ]); + } + + public function test_store_creates_routing_configuration_successfully(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $data = [ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id, + 'is_active' => true, + 'priority' => 5 + ]; + + $response = $this->postJson('/api/v1/routing', $data); + + $response->assertStatus(201) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + 'feed_id', + 'platform_channel_id', + 'is_active', + 'priority', + 'created_at', + 'updated_at', + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Routing configuration created successfully!' + ]); + + $this->assertDatabaseHas('routes', [ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id, + 'is_active' => true, + 'priority' => 5, + ]); + } + + public function test_store_validates_required_fields(): void + { + $response = $this->postJson('/api/v1/routing', []); + + $response->assertStatus(422) + ->assertJsonValidationErrors(['feed_id', 'platform_channel_id']); + } + + public function test_store_validates_feed_exists(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $data = [ + 'feed_id' => 999, + 'platform_channel_id' => $channel->id + ]; + + $response = $this->postJson('/api/v1/routing', $data); + + $response->assertStatus(422) + ->assertJsonValidationErrors(['feed_id']); + } + + public function test_store_validates_platform_channel_exists(): void + { + $language = Language::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + + $data = [ + 'feed_id' => $feed->id, + 'platform_channel_id' => 999 + ]; + + $response = $this->postJson('/api/v1/routing', $data); + + $response->assertStatus(422) + ->assertJsonValidationErrors(['platform_channel_id']); + } + + public function test_show_returns_routing_configuration_successfully(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $route = Route::factory()->create([ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id + ]); + + $response = $this->getJson("/api/v1/routing/{$feed->id}/{$channel->id}"); + + $response->assertStatus(200) + ->assertJsonStructure([ + 'success', + 'message', + 'data' => [ + 'feed_id', + 'platform_channel_id', + 'is_active', + 'priority', + 'created_at', + 'updated_at', + ] + ]) + ->assertJson([ + 'success' => true, + 'message' => 'Routing configuration retrieved successfully.' + ]); + } + + public function test_show_returns_404_for_nonexistent_routing(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $response = $this->getJson("/api/v1/routing/{$feed->id}/{$channel->id}"); + + $response->assertStatus(404) + ->assertJson([ + 'success' => false, + 'message' => 'Routing configuration not found.' + ]); + } + + public function test_update_modifies_routing_configuration_successfully(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $route = Route::factory()->create([ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id, + 'is_active' => true, + 'priority' => 1 + ]); + + $updateData = [ + 'is_active' => false, + 'priority' => 10 + ]; + + $response = $this->putJson("/api/v1/routing/{$feed->id}/{$channel->id}", $updateData); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Routing configuration updated successfully!' + ]); + + $this->assertDatabaseHas('routes', [ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id, + 'is_active' => false, + 'priority' => 10, + ]); + } + + public function test_update_returns_404_for_nonexistent_routing(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $response = $this->putJson("/api/v1/routing/{$feed->id}/{$channel->id}", [ + 'is_active' => false + ]); + + $response->assertStatus(404) + ->assertJson([ + 'success' => false, + 'message' => 'Routing configuration not found.' + ]); + } + + public function test_destroy_deletes_routing_configuration_successfully(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $route = Route::factory()->create([ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id + ]); + + $response = $this->deleteJson("/api/v1/routing/{$feed->id}/{$channel->id}"); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Routing configuration deleted successfully!' + ]); + + $this->assertDatabaseMissing('routes', [ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id + ]); + } + + public function test_destroy_returns_404_for_nonexistent_routing(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $response = $this->deleteJson("/api/v1/routing/{$feed->id}/{$channel->id}"); + + $response->assertStatus(404) + ->assertJson([ + 'success' => false, + 'message' => 'Routing configuration not found.' + ]); + } + + public function test_toggle_activates_inactive_routing(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $route = Route::factory()->create([ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id, + 'is_active' => false + ]); + + $response = $this->postJson("/api/v1/routing/{$feed->id}/{$channel->id}/toggle"); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Routing configuration activated successfully!' + ]); + + $this->assertDatabaseHas('routes', [ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id, + 'is_active' => true + ]); + } + + public function test_toggle_deactivates_active_routing(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $route = Route::factory()->create([ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id, + 'is_active' => true + ]); + + $response = $this->postJson("/api/v1/routing/{$feed->id}/{$channel->id}/toggle"); + + $response->assertStatus(200) + ->assertJson([ + 'success' => true, + 'message' => 'Routing configuration deactivated successfully!' + ]); + + $this->assertDatabaseHas('routes', [ + 'feed_id' => $feed->id, + 'platform_channel_id' => $channel->id, + 'is_active' => false + ]); + } + + public function test_toggle_returns_404_for_nonexistent_routing(): void + { + $language = Language::factory()->create(); + $instance = PlatformInstance::factory()->create(); + $feed = Feed::factory()->create(['language_id' => $language->id]); + $channel = PlatformChannel::factory()->create([ + 'platform_instance_id' => $instance->id, + 'language_id' => $language->id + ]); + + $response = $this->postJson("/api/v1/routing/{$feed->id}/{$channel->id}/toggle"); + + $response->assertStatus(404) + ->assertJson([ + 'success' => false, + 'message' => 'Routing configuration not found.' + ]); + } +} \ No newline at end of file