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'); });