Files
keystone/tests/Feature/OperationsUiTest.php
Harry Bayliss 5b977c1f41
Some checks failed
CI / Lint (push) Failing after 22s
CI / Tests (push) Failing after 33s
wowowowowo
2026-05-28 15:15:41 +01:00

155 lines
5.5 KiB
PHP

<?php
use App\Enums\OperationKind;
use App\Enums\OperationStatus;
use App\Models\Application;
use App\Models\Environment;
use App\Models\Operation;
use App\Models\Organisation;
use App\Models\Service;
use App\Models\User;
use Inertia\Testing\AssertableInertia;
it('lists organisation operations with filters and target context', function () {
$user = User::factory()->create();
$organisation = Organisation::factory()->create(['owner_id' => $user->id]);
$application = Application::factory()->for($organisation)->create();
$environment = Environment::factory()->for($application)->create();
Operation::factory()->create([
'kind' => OperationKind::ENVIRONMENT_DEPLOY,
'target_type' => $environment->getMorphClass(),
'target_id' => $environment->id,
'status' => OperationStatus::IN_PROGRESS,
]);
$response = $this->actingAs($user)->get(route('operations.index', [
'organisation' => $organisation->id,
'kind' => OperationKind::ENVIRONMENT_DEPLOY->value,
]));
$response->assertOk();
$response->assertInertia(fn (AssertableInertia $page) => $page
->component('operations/Index', false)
->where('operations.data.0.kind', OperationKind::ENVIRONMENT_DEPLOY->value)
->where('filters.kind', OperationKind::ENVIRONMENT_DEPLOY->value));
});
it('shows an operation with steps and children', function () {
$user = User::factory()->create();
$organisation = Organisation::factory()->create(['owner_id' => $user->id]);
$service = Service::factory()->for($organisation)->create();
$operation = Operation::factory()->create([
'target_type' => $service->getMorphClass(),
'target_id' => $service->id,
]);
$operation->steps()->create([
'name' => 'Deploy container',
'order' => 1,
'status' => OperationStatus::COMPLETED,
'script' => 'docker ps',
'logs' => 'ok',
]);
Operation::factory()->create([
'parent_id' => $operation->id,
'target_type' => $service->getMorphClass(),
'target_id' => $service->id,
]);
$response = $this->actingAs($user)->get(route('operations.show', [
'organisation' => $organisation->id,
'operation' => $operation->id,
]));
$response->assertOk();
$response->assertInertia(fn (AssertableInertia $page) => $page
->component('operations/Show', false)
->where('operation.hash', $operation->hash)
->has('operation.steps', 1)
->has('operation.children', 1));
});
it('does not show operations from another organisation', function () {
$user = User::factory()->create();
$organisation = Organisation::factory()->create(['owner_id' => $user->id]);
$otherOrganisation = Organisation::factory()->create();
$service = Service::factory()->for($otherOrganisation)->create();
$operation = Operation::factory()->create([
'target_type' => $service->getMorphClass(),
'target_id' => $service->id,
]);
$response = $this->actingAs($user)->get(route('operations.show', [
'organisation' => $organisation->id,
'operation' => $operation->id,
]));
$response->assertNotFound();
});
it('retries failed operations owned by the organisation', function () {
$user = User::factory()->create();
$organisation = Organisation::factory()->create(['owner_id' => $user->id]);
$service = Service::factory()->for($organisation)->create();
$operation = Operation::factory()->create([
'target_type' => $service->getMorphClass(),
'target_id' => $service->id,
'status' => OperationStatus::FAILED,
'started_at' => now(),
'finished_at' => now(),
]);
$response = $this->actingAs($user)->post(route('operations.retry', [
'organisation' => $organisation->id,
'operation' => $operation->id,
]));
$response->assertRedirect(route('operations.show', [
'organisation' => $organisation->id,
'operation' => $operation->id,
]));
expect($operation->refresh()->status)->toBe(OperationStatus::PENDING)
->and($operation->started_at)->toBeNull()
->and($operation->finished_at)->toBeNull();
});
it('cancels operations and downloads logs', function () {
$user = User::factory()->create();
$organisation = Organisation::factory()->create(['owner_id' => $user->id]);
$service = Service::factory()->for($organisation)->create();
$operation = Operation::factory()->create([
'target_type' => $service->getMorphClass(),
'target_id' => $service->id,
'status' => OperationStatus::IN_PROGRESS,
]);
$operation->steps()->create([
'name' => 'Deploy container',
'order' => 1,
'status' => OperationStatus::IN_PROGRESS,
'script' => 'docker ps',
'logs' => 'hello',
'error_logs' => 'error',
]);
$this->actingAs($user)->post(route('operations.cancel', [
'organisation' => $organisation->id,
'operation' => $operation->id,
]))->assertRedirect(route('operations.show', [
'organisation' => $organisation->id,
'operation' => $operation->id,
]));
expect($operation->refresh()->status)->toBe(OperationStatus::CANCELLED)
->and($operation->finished_at)->not->toBeNull();
$response = $this->actingAs($user)->get(route('operations.logs', [
'organisation' => $organisation->id,
'operation' => $operation->id,
]));
$response->assertOk();
$response->assertHeader('content-type', 'text/plain; charset=UTF-8');
});