115 lines
3.9 KiB
PHP
115 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Release\Index;
|
|
use App\Models\AuditEvent;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\RateLimiter;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
class ReleasePageTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private string $dir;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
config()->set('clusev.release_controls', true);
|
|
config()->set('clusev.version', '0.9.58');
|
|
$this->actingAs(User::factory()->create(['must_change_password' => false]));
|
|
$this->dir = storage_path('app/restart-signal');
|
|
@mkdir($this->dir, 0775, true);
|
|
@unlink($this->dir.'/release-request.json');
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
@unlink($this->dir.'/release-request.json');
|
|
foreach (glob($this->dir.'/release-result-*.json') ?: [] as $f) {
|
|
@unlink($f);
|
|
}
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function test_deploy_staging_for_an_allowed_target_writes_a_request_and_audits(): void
|
|
{
|
|
Livewire::test(Index::class)->call('deployStaging', '0.10.0');
|
|
|
|
$payload = json_decode((string) file_get_contents($this->dir.'/release-request.json'), true);
|
|
$this->assertSame('stage', $payload['action']);
|
|
$this->assertSame('0.10.0', $payload['target']);
|
|
$this->assertTrue(AuditEvent::where('action', 'deploy.staging_release')->exists());
|
|
}
|
|
|
|
public function test_deploy_staging_rejects_a_target_not_in_the_allowed_set(): void
|
|
{
|
|
Livewire::test(Index::class)->call('deployStaging', '5.5.5');
|
|
|
|
$this->assertFileDoesNotExist($this->dir.'/release-request.json');
|
|
}
|
|
|
|
public function test_deploy_staging_is_throttled_per_user(): void
|
|
{
|
|
$key = 'release-stage:'.auth()->id();
|
|
for ($i = 0; $i < 3; $i++) {
|
|
RateLimiter::hit($key, 600);
|
|
}
|
|
|
|
Livewire::test(Index::class)->call('deployStaging', '0.10.0');
|
|
|
|
$this->assertFileDoesNotExist($this->dir.'/release-request.json');
|
|
}
|
|
|
|
public function test_poll_result_surfaces_a_success(): void
|
|
{
|
|
$c = Livewire::test(Index::class)->call('deployStaging', '0.10.0');
|
|
$id = $c->get('pendingId');
|
|
file_put_contents(
|
|
$this->dir."/release-result-{$id}.json",
|
|
json_encode(['id' => $id, 'ok' => true, 'tag' => 'v0.10.0-beta1', 'message' => 'ok'])
|
|
);
|
|
|
|
$c->call('pollResult')->assertSet('pendingId', null)->assertSee('v0.10.0-beta1');
|
|
}
|
|
|
|
public function test_poll_result_audits_a_host_failure_as_an_error(): void
|
|
{
|
|
$c = Livewire::test(Index::class)->call('deployStaging', '0.10.0');
|
|
$id = $c->get('pendingId');
|
|
file_put_contents(
|
|
$this->dir."/release-result-{$id}.json",
|
|
json_encode(['id' => $id, 'ok' => false, 'tag' => null, 'message' => 'dirty-tree'])
|
|
);
|
|
|
|
$c->call('pollResult')->assertSet('pendingId', null);
|
|
$this->assertTrue(AuditEvent::where('action', 'deploy.staging_release_failed')->exists());
|
|
}
|
|
|
|
public function test_mount_aborts_when_the_flag_is_off(): void
|
|
{
|
|
config()->set('clusev.release_controls', false);
|
|
Livewire::test(Index::class)->assertStatus(404);
|
|
}
|
|
|
|
public function test_render_includes_the_live_pipeline_for_a_beta(): void
|
|
{
|
|
config()->set('clusev.version', '0.9.61-beta1');
|
|
config()->set('clusev.staging_slug', ''); // degrade: no GitHub calls
|
|
config()->set('clusev.github_token', '');
|
|
|
|
Livewire::test(Index::class)
|
|
->assertViewHas('pipeline', fn ($p) => is_array($p) && $p['tag'] === 'v0.9.61-beta1');
|
|
}
|
|
|
|
public function test_render_pipeline_is_null_for_a_stable_version(): void
|
|
{
|
|
config()->set('clusev.version', '0.9.60');
|
|
Livewire::test(Index::class)->assertViewHas('pipeline', null);
|
|
}
|
|
}
|