From 309599c429218cf0d344e6714396783f4df62a03 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Apr 2026 11:51:28 +0100 Subject: [PATCH] feat: test suite for Names API endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 13 tests covering CheckAvailability, SubmitClaim, NameClaim model scopes, NameActivity logging, and HTTP endpoints. PHPUnit config added. Tests need TestCase base class setup to run — framework testing infrastructure TBD. Co-Authored-By: Claude Opus 4.6 (1M context) --- app/Mod/Names/Tests/Feature/NamesApiTest.php | 151 +++++++++++++++++++ phpunit.xml | 16 ++ 2 files changed, 167 insertions(+) create mode 100644 app/Mod/Names/Tests/Feature/NamesApiTest.php create mode 100644 phpunit.xml diff --git a/app/Mod/Names/Tests/Feature/NamesApiTest.php b/app/Mod/Names/Tests/Feature/NamesApiTest.php new file mode 100644 index 0000000..2cc0dfb --- /dev/null +++ b/app/Mod/Names/Tests/Feature/NamesApiTest.php @@ -0,0 +1,151 @@ +assertArrayHasKey('name', $result); + $this->assertArrayHasKey('available', $result); + $this->assertArrayHasKey('reserved', $result); + $this->assertArrayHasKey('fqdn', $result); + $this->assertEquals('testname123.lthn', $result['fqdn']); + } + + public function test_invalid_name_returns_unavailable(): void + { + $result = CheckAvailability::run('AB'); + + $this->assertFalse($result['available']); + } + + public function test_submit_claim_creates_record(): void + { + $claim = SubmitClaim::run([ + 'name' => 'claimtest', + 'email' => 'test@example.com', + ]); + + $this->assertInstanceOf(NameClaim::class, $claim); + $this->assertEquals('claimtest', $claim->name); + $this->assertEquals('pending', $claim->status); + $this->assertNotEmpty($claim->claim_id); + $this->assertEquals(12, strlen($claim->claim_id)); + + $this->assertDatabaseHas('name_claims', [ + 'name' => 'claimtest', + 'email' => 'test@example.com', + 'status' => 'pending', + ]); + } + + public function test_submit_claim_logs_activity(): void + { + SubmitClaim::run([ + 'name' => 'actlogtest', + 'email' => 'log@example.com', + ]); + + $this->assertDatabaseHas('name_activity', [ + 'name' => 'actlogtest', + 'event' => 'claimed', + ]); + } + + public function test_duplicate_claim_rejected(): void + { + SubmitClaim::run([ + 'name' => 'dupetest1', + 'email' => 'first@example.com', + ]); + + $this->expectException(\Illuminate\Validation\ValidationException::class); + + SubmitClaim::run([ + 'name' => 'dupetest1', + 'email' => 'second@example.com', + ]); + } + + public function test_claim_with_invalid_email_rejected(): void + { + $this->expectException(\Illuminate\Validation\ValidationException::class); + + SubmitClaim::run([ + 'name' => 'emailtest', + 'email' => 'not-an-email', + ]); + } + + public function test_claim_with_short_name_rejected(): void + { + $this->expectException(\Illuminate\Validation\ValidationException::class); + + SubmitClaim::run([ + 'name' => 'abc', + 'email' => 'test@example.com', + ]); + } + + public function test_name_claim_model_scopes(): void + { + NameClaim::create(['name' => 'scope1', 'email' => 'a@b.com', 'status' => 'pending', 'claim_id' => 'aaa']); + NameClaim::create(['name' => 'scope2', 'email' => 'a@b.com', 'status' => 'approved', 'claim_id' => 'bbb']); + + $this->assertEquals(1, NameClaim::pending()->count()); + $this->assertEquals(1, NameClaim::approved()->count()); + } + + public function test_name_activity_log(): void + { + $activity = NameActivity::log('testlog', 'registered', [ + 'address' => 'iTHN...', + ], '1.2.3.4'); + + $this->assertEquals('testlog', $activity->name); + $this->assertEquals('registered', $activity->event); + $this->assertNotNull($activity->ip_hash); + $this->assertNotEquals('1.2.3.4', $activity->ip_hash); // Hashed + $this->assertEquals(['address' => 'iTHN...'], $activity->properties); + } + + public function test_available_endpoint_returns_json(): void + { + $response = $this->getJson('/v1/names/available/apiendtest'); + + $response->assertOk() + ->assertJsonStructure(['name', 'available', 'reserved', 'fqdn']); + } + + public function test_claim_endpoint_returns_201(): void + { + $response = $this->postJson('/v1/names/claim', [ + 'name' => 'endpointtest', + 'email' => 'endpoint@test.com', + ]); + + $response->assertStatus(201) + ->assertJsonStructure(['data' => ['claim_id', 'name', 'fqdn', 'status']]); + } + + public function test_claim_endpoint_validates_input(): void + { + $response = $this->postJson('/v1/names/claim', [ + 'name' => 'ab', + 'email' => 'bad', + ]); + + $response->assertStatus(422); + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..100ab59 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,16 @@ + + + + + app/Mod/*/Tests + + + + + + + +