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_request_writes_a_validated_stage_request_and_returns_an_id(): void { $id = app(ReleaseBridge::class)->requestStaging('0.10.0'); $this->assertNotNull($id); $this->assertMatchesRegularExpression('/^[A-Za-z0-9]{32}$/', $id); $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->assertSame($id, $payload['id']); } public function test_request_rejects_a_non_semver_target_without_writing_a_request(): void { try { app(ReleaseBridge::class)->requestStaging('garbage'); $this->fail('expected InvalidArgumentException for a non-semver target'); } catch (\InvalidArgumentException) { // expected — validation throws before any write } $this->assertFileDoesNotExist($this->dir.'/release-request.json'); } public function test_result_reads_the_host_result_for_the_issued_id(): void { $id = app(ReleaseBridge::class)->requestStaging('0.10.0'); file_put_contents( $this->dir."/release-result-{$id}.json", json_encode(['id' => $id, 'ok' => true, 'tag' => 'v0.10.0-rc1', 'message' => 'ok']) ); $res = app(ReleaseBridge::class)->result($id); $this->assertTrue($res['ok']); $this->assertSame('v0.10.0-rc1', $res['tag']); } public function test_result_is_null_until_the_host_replies(): void { $id = app(ReleaseBridge::class)->requestStaging('0.10.0'); $this->assertNull(app(ReleaseBridge::class)->result($id)); } }