121 lines
3.6 KiB
PHP
121 lines
3.6 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace HyperfTest\Cases\Integration\System;
|
||
|
|
|
||
|
|
use App\Model\User;
|
||
|
|
use HyperfTest\TestCase;
|
||
|
|
use HyperfTest\Traits\AuthenticatedTestTrait;
|
||
|
|
use Qbhy\HyperfAuth\AuthManager;
|
||
|
|
|
||
|
|
use function Hyperf\Support\make;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* POST /api/v1/routes/sync 集成测试
|
||
|
|
*
|
||
|
|
* 覆盖管理员成功、非管理员 403、重复调用幂等
|
||
|
|
*
|
||
|
|
* @internal
|
||
|
|
* @coversNothing
|
||
|
|
*/
|
||
|
|
class RouteSyncTest extends TestCase
|
||
|
|
{
|
||
|
|
use AuthenticatedTestTrait;
|
||
|
|
|
||
|
|
private static ?User $nonAdminUser = null;
|
||
|
|
|
||
|
|
protected function getNonAdminHeaders(): array
|
||
|
|
{
|
||
|
|
if (self::$nonAdminUser === null) {
|
||
|
|
self::$nonAdminUser = $this->runInCoroutine(static function (): User {
|
||
|
|
return User::query()->create([
|
||
|
|
'username' => 'route_sync_test_nonadmin_' . uniqid(),
|
||
|
|
'password' => 'TestPass123',
|
||
|
|
'email' => 'route_sync_nonadmin_' . uniqid() . '@example.com',
|
||
|
|
'status' => 1,
|
||
|
|
]);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this->runInCoroutine(function (): array {
|
||
|
|
$auth = make(AuthManager::class);
|
||
|
|
$token = $auth->guard('jwt')->login(self::$nonAdminUser);
|
||
|
|
return ['Authorization' => 'Bearer ' . $token];
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function tearDownAfterClass(): void
|
||
|
|
{
|
||
|
|
if (self::$nonAdminUser !== null) {
|
||
|
|
$user_id = self::$nonAdminUser->id;
|
||
|
|
$cleanup = static function () use ($user_id): void {
|
||
|
|
User::query()->where('id', $user_id)->delete();
|
||
|
|
};
|
||
|
|
|
||
|
|
if (\Swoole\Coroutine::getCid() > 0) {
|
||
|
|
$cleanup();
|
||
|
|
} else {
|
||
|
|
\Swoole\Coroutine\run($cleanup);
|
||
|
|
}
|
||
|
|
self::$nonAdminUser = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
parent::tearDownAfterClass();
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== 管理员成功 ==========
|
||
|
|
|
||
|
|
public function test_admin_can_sync_routes(): void
|
||
|
|
{
|
||
|
|
$response = $this->post('/api/v1/routes/sync', [], $this->authHeaders());
|
||
|
|
|
||
|
|
$response->assertOk();
|
||
|
|
$body = $response->json();
|
||
|
|
|
||
|
|
$this->assertSame(0, $body['code']);
|
||
|
|
$this->assertSame('同步成功', $body['message']);
|
||
|
|
$this->assertIsArray($body['data']);
|
||
|
|
$this->assertArrayHasKey('synced', $body['data']);
|
||
|
|
$this->assertArrayHasKey('total', $body['data']);
|
||
|
|
$this->assertIsInt($body['data']['synced']);
|
||
|
|
$this->assertIsInt($body['data']['total']);
|
||
|
|
$this->assertGreaterThan(0, $body['data']['synced']);
|
||
|
|
$this->assertSame($body['data']['synced'], $body['data']['total']);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== 非管理员 403 ==========
|
||
|
|
|
||
|
|
public function test_non_admin_receives_403(): void
|
||
|
|
{
|
||
|
|
$response = $this->post('/api/v1/routes/sync', [], $this->getNonAdminHeaders());
|
||
|
|
|
||
|
|
$response->assertStatus(403);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== 未认证 401 ==========
|
||
|
|
|
||
|
|
public function test_unauthenticated_returns_401(): void
|
||
|
|
{
|
||
|
|
$response = $this->post('/api/v1/routes/sync');
|
||
|
|
|
||
|
|
$response->assertStatus(401);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== 重复调用幂等 ==========
|
||
|
|
|
||
|
|
public function test_repeated_sync_is_idempotent(): void
|
||
|
|
{
|
||
|
|
$response1 = $this->post('/api/v1/routes/sync', [], $this->authHeaders());
|
||
|
|
$response1->assertOk();
|
||
|
|
$data1 = $response1->json('data');
|
||
|
|
|
||
|
|
$response2 = $this->post('/api/v1/routes/sync', [], $this->authHeaders());
|
||
|
|
$response2->assertOk();
|
||
|
|
$data2 = $response2->json('data');
|
||
|
|
|
||
|
|
$this->assertSame($data1['synced'], $data2['synced']);
|
||
|
|
$this->assertSame($data1['total'], $data2['total']);
|
||
|
|
}
|
||
|
|
}
|