95 lines
3.8 KiB
PHP
95 lines
3.8 KiB
PHP
<?php
|
|
|
|
use App\Models\Host;
|
|
use App\Models\Instance;
|
|
use App\Models\Order;
|
|
use App\Models\ProvisioningRun;
|
|
use App\Models\RunResource;
|
|
use App\Notifications\CloudReady;
|
|
use App\Provisioning\RunRunner;
|
|
use Illuminate\Support\Facades\Notification;
|
|
use Illuminate\Support\Facades\Queue;
|
|
|
|
it('provisions a paid order all the way to active (mocked)', function () {
|
|
Notification::fake();
|
|
Queue::fake(); // drive the runner manually, one step per advance
|
|
$s = fakeServices();
|
|
$s['pve']->guestScript('status.php', 0, 'ok');
|
|
$s['pve']->guestScript('hostname -I', 0, '10.20.0.9');
|
|
$s['pve']->guestScript('occ status', 0, '{"installed":true,"maintenance":false}'); // deploy health + acceptance probe
|
|
// Fake defaults: tasks stopped/OK, guest agent up, cert reachable.
|
|
|
|
Host::factory()->active()->create(['datacenter' => 'fsn', 'node' => 'pve', 'total_gb' => 1000]);
|
|
$order = Order::factory()->create(['status' => 'paid', 'plan' => 'start', 'datacenter' => 'fsn']);
|
|
$run = ProvisioningRun::factory()->create([
|
|
'subject_type' => Order::class, 'subject_id' => $order->id, 'pipeline' => 'customer', 'context' => [],
|
|
]);
|
|
|
|
$runner = app(RunRunner::class);
|
|
for ($i = 0; $i < 60; $i++) {
|
|
$run->refresh();
|
|
if (in_array($run->status, ['completed', 'failed'], true)) {
|
|
break;
|
|
}
|
|
if ($run->next_attempt_at?->isFuture()) {
|
|
$run->update(['next_attempt_at' => now()]);
|
|
}
|
|
$runner->advance($run);
|
|
}
|
|
|
|
$run->refresh();
|
|
$instance = Instance::query()->where('order_id', $order->id)->firstOrFail();
|
|
|
|
expect($run->status)->toBe('completed')
|
|
->and($run->error)->toBeNull()
|
|
->and($order->fresh()->status)->toBe('active')
|
|
->and($instance->status)->toBe('active')
|
|
->and($instance->vmid)->not->toBeNull()
|
|
->and($instance->cert_ok)->toBeTrue()
|
|
->and($instance->onboardingTasks()->count())->toBeGreaterThan(0);
|
|
|
|
// Every external resource created exactly once.
|
|
foreach (['instance_id', 'vmid', 'dns_record_id', 'nc_admin', 'backup_job_id', 'monitoring_target_id'] as $kind) {
|
|
expect(RunResource::where('run_id', $run->id)->where('kind', $kind)->count())->toBe(1);
|
|
}
|
|
|
|
// Secrets scrubbed from state; credentials delivered.
|
|
expect($run->context('admin_password'))->toBeNull()
|
|
->and($run->context('db_password'))->toBeNull();
|
|
Notification::assertSentOnDemand(CloudReady::class);
|
|
});
|
|
|
|
it('does not duplicate external resources when a step re-runs after a crash', function () {
|
|
Notification::fake();
|
|
Queue::fake();
|
|
$s = fakeServices();
|
|
$s['pve']->guestScript('status.php', 0, 'ok');
|
|
$s['pve']->guestScript('hostname -I', 0, '10.20.0.9');
|
|
$s['pve']->guestScript('occ status', 0, '{"installed":true,"maintenance":false}');
|
|
|
|
Host::factory()->active()->create(['datacenter' => 'fsn', 'node' => 'pve', 'total_gb' => 1000]);
|
|
$order = Order::factory()->create(['status' => 'paid', 'plan' => 'start', 'datacenter' => 'fsn']);
|
|
$run = ProvisioningRun::factory()->create([
|
|
'subject_type' => Order::class, 'subject_id' => $order->id, 'pipeline' => 'customer', 'context' => [],
|
|
]);
|
|
$runner = app(RunRunner::class);
|
|
|
|
// Drive a few steps, then rewind to the clone step and replay it.
|
|
for ($i = 0; $i < 5; $i++) {
|
|
$run->refresh();
|
|
if ($run->next_attempt_at?->isFuture()) {
|
|
$run->update(['next_attempt_at' => now()]);
|
|
}
|
|
$runner->advance($run);
|
|
}
|
|
$cloneIndex = array_search(
|
|
\App\Provisioning\Steps\Customer\CloneVirtualMachine::class,
|
|
config('provisioning.pipelines.customer'),
|
|
true,
|
|
);
|
|
$run->update(['current_step' => $cloneIndex, 'status' => 'running']);
|
|
$runner->advance($run->fresh());
|
|
|
|
expect(RunResource::where('run_id', $run->id)->where('kind', 'vmid')->count())->toBe(1);
|
|
});
|