create([ 'username' => 'apikey_test_' . $suffix, 'password' => 'Pass_' . $suffix, 'email' => 'apikey_test_' . $suffix . '@example.com', 'status' => 1, 'api_key_enabled' => true, ]); } public function test_generate_returns_plain_key_and_model(): void { $this->runInCoroutine(function (): void { $user = $this->createTestUser(); $result = ApiKey::generate($user->id, 'Test Key'); $this->assertArrayHasKey('plain_key', $result); $this->assertArrayHasKey('api_key', $result); $this->assertInstanceOf(ApiKey::class, $result['api_key']); $this->assertSame(64, strlen($result['plain_key'])); }); } public function test_generate_stores_sha256_hash(): void { $this->runInCoroutine(function (): void { $user = $this->createTestUser(); $result = ApiKey::generate($user->id, 'Hash Test'); $expected_hash = hash('sha256', $result['plain_key']); $this->assertSame($expected_hash, $result['api_key']->key_hash); }); } public function test_generate_stores_prefix(): void { $this->runInCoroutine(function (): void { $user = $this->createTestUser(); $result = ApiKey::generate($user->id, 'Prefix Test'); $expected_prefix = substr($result['plain_key'], 0, 8); $this->assertSame($expected_prefix, $result['api_key']->key_prefix); }); } public function test_find_by_plain_key_returns_valid_key(): void { $this->runInCoroutine(function (): void { $user = $this->createTestUser(); $result = ApiKey::generate($user->id, 'Find Test'); $found = ApiKey::findByPlainKey($result['plain_key']); $this->assertNotNull($found); $this->assertSame($result['api_key']->id, $found->id); }); } public function test_find_by_plain_key_returns_null_for_invalid_key(): void { $this->runInCoroutine(function (): void { $found = ApiKey::findByPlainKey('invalid_key_that_does_not_exist'); $this->assertNull($found); }); } public function test_find_by_plain_key_excludes_disabled_key(): void { $this->runInCoroutine(function (): void { $user = $this->createTestUser(); $result = ApiKey::generate($user->id, 'Disabled Test'); $result['api_key']->enabled = false; $result['api_key']->save(); $found = ApiKey::findByPlainKey($result['plain_key']); $this->assertNull($found); }); } public function test_find_by_plain_key_excludes_expired_key(): void { $this->runInCoroutine(function (): void { $user = $this->createTestUser(); $result = ApiKey::generate($user->id, 'Expired Test', \Carbon\Carbon::now()->subDay()->toDateTimeString()); $found = ApiKey::findByPlainKey($result['plain_key']); $this->assertNull($found); }); } public function test_key_hash_is_hidden_in_json(): void { $this->runInCoroutine(function (): void { $user = $this->createTestUser(); $result = ApiKey::generate($user->id, 'Hidden Test'); $json = $result['api_key']->toArray(); $this->assertArrayNotHasKey('key_hash', $json); }); } public function test_is_valid_returns_true_for_active_key(): void { $this->runInCoroutine(function (): void { $user = $this->createTestUser(); $result = ApiKey::generate($user->id, 'Valid Test'); $this->assertTrue($result['api_key']->isValid()); }); } public function test_is_valid_returns_false_for_disabled_key(): void { $this->runInCoroutine(function (): void { $user = $this->createTestUser(); $result = ApiKey::generate($user->id, 'Disabled Valid'); $result['api_key']->enabled = false; $this->assertFalse($result['api_key']->isValid()); }); } }