66 lines
3.0 KiB
PHP
66 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\EcommerceFinance;
|
|
|
|
use Mockery;
|
|
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
|
|
use Modules\EcommerceFinance\Services\UpstreamDatabaseProbe;
|
|
use PDO;
|
|
use PDOException;
|
|
use PDOStatement;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
|
|
|
class UpstreamDatabaseProbeTest extends TestCase
|
|
{
|
|
use MockeryPHPUnitIntegration;
|
|
|
|
private function connection(): array
|
|
{
|
|
return ['host' => 'db.example.test', 'port' => 25432, 'database' => "test' database",
|
|
'username' => 'reader', 'password' => 'fixture-secret', 'connect_timeout' => 5, 'query_timeout' => 120];
|
|
}
|
|
|
|
public function test_postgres_uses_tls_read_only_timeout_and_one_select(): void
|
|
{
|
|
$statement = Mockery::mock(PDOStatement::class);
|
|
$statement->shouldReceive('fetchColumn')->once()->andReturn(1);
|
|
$statement->shouldReceive('closeCursor')->once();
|
|
$pdo = Mockery::mock(PDO::class);
|
|
$pdo->shouldReceive('query')->once()->with('SELECT 1')->andReturn($statement);
|
|
$probe = Mockery::mock(UpstreamDatabaseProbe::class)->makePartial()->shouldAllowMockingProtectedMethods();
|
|
$probe->shouldReceive('connect')->once()->withArgs(function ($dsn, $user, $password) {
|
|
$this->assertStringContainsString('sslmode=require', $dsn);
|
|
$this->assertStringContainsString('default_transaction_read_only=on', $dsn);
|
|
$this->assertStringContainsString('statement_timeout=15000', $dsn);
|
|
$this->assertStringContainsString("dbname='test\\' database'", $dsn);
|
|
$this->assertStringContainsString('connect_timeout=5', $dsn);
|
|
$this->assertStringNotContainsString('fixture-secret', $dsn);
|
|
|
|
return $user === 'reader' && $password === 'fixture-secret';
|
|
})->andReturn($pdo);
|
|
$probe->probe('pgsql', $this->connection(), '测试库');
|
|
}
|
|
|
|
public function test_driver_error_never_exposes_credentials(): void
|
|
{
|
|
$probe = Mockery::mock(UpstreamDatabaseProbe::class)->makePartial()->shouldAllowMockingProtectedMethods();
|
|
$probe->shouldReceive('connect')->once()->andThrow(new PDOException('fixture-secret private driver detail'));
|
|
try {
|
|
$probe->probe('pgsql', $this->connection(), '测试库');
|
|
$this->fail('Expected sanitized connection error');
|
|
} catch (ServiceUnavailableHttpException $exception) {
|
|
$this->assertStringContainsString('PostgreSQL 连接失败', $exception->getMessage());
|
|
$this->assertStringNotContainsString('fixture-secret', $exception->getMessage());
|
|
$this->assertNull($exception->getPrevious());
|
|
}
|
|
}
|
|
|
|
public function test_unsupported_driver_is_not_probed(): void
|
|
{
|
|
$this->expectException(ServiceUnavailableHttpException::class);
|
|
$this->expectExceptionMessage('不支持此数据库类型');
|
|
(new UpstreamDatabaseProbe())->probe('unknown', [], '测试库');
|
|
}
|
|
}
|