1
0
mirror of https://github.com/danog/postgres.git synced 2024-12-02 09:27:54 +01:00

Update tests

This commit is contained in:
Aaron Piotrowski 2019-09-26 22:41:47 -05:00
parent 170266227a
commit d5f70b2f4f
No known key found for this signature in database
GPG Key ID: ADD1EF783EDE9EEB
9 changed files with 407 additions and 455 deletions

View File

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016 amphp Copyright (c) 2016-2019 amphp
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -25,8 +25,8 @@
"amphp/sql-common": "^1" "amphp/sql-common": "^1"
}, },
"require-dev": { "require-dev": {
"amphp/phpunit-util": "^1", "amphp/phpunit-util": "^1.1.2",
"phpunit/phpunit": "^6", "phpunit/phpunit": "^7 || ^6",
"amphp/php-cs-fixer-config": "dev-master", "amphp/php-cs-fixer-config": "dev-master",
"phpstan/phpstan": "^0.9" "phpstan/phpstan": "^0.9"
}, },

View File

@ -22,7 +22,4 @@
<directory suffix=".php">src</directory> <directory suffix=".php">src</directory>
</whitelist> </whitelist>
</filter> </filter>
<listeners>
<listener class="Amp\PHPUnit\LoopReset"/>
</listeners>
</phpunit> </phpunit>

View File

@ -4,15 +4,16 @@ namespace Amp\Postgres\Test;
use Amp\CancellationToken; use Amp\CancellationToken;
use Amp\CancellationTokenSource; use Amp\CancellationTokenSource;
use Amp\Loop; use Amp\CancelledException;
use Amp\PHPUnit\AsyncTestCase;
use Amp\Postgres\Connection; use Amp\Postgres\Connection;
use Amp\Postgres\ConnectionConfig as PostgresConnectionConfig; use Amp\Postgres\ConnectionConfig as PostgresConnectionConfig;
use Amp\Promise; use Amp\Promise;
use Amp\Sql\ConnectionConfig; use Amp\Sql\ConnectionConfig;
use Amp\Sql\FailureException;
use Amp\TimeoutCancellationToken; use Amp\TimeoutCancellationToken;
use PHPUnit\Framework\TestCase;
abstract class AbstractConnectTest extends TestCase abstract class AbstractConnectTest extends AsyncTestCase
{ {
/** /**
* @param ConnectionConfig $connectionConfig * @param ConnectionConfig $connectionConfig
@ -22,53 +23,47 @@ abstract class AbstractConnectTest extends TestCase
*/ */
abstract public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise; abstract public function connect(ConnectionConfig $connectionConfig, CancellationToken $token = null): Promise;
public function testConnect() public function testConnect(): \Generator
{ {
Loop::run(function () { $connection = yield $this->connect(
$connection = yield $this->connect( PostgresConnectionConfig::fromString('host=localhost user=postgres'),
PostgresConnectionConfig::fromString('host=localhost user=postgres'), new TimeoutCancellationToken(100)
new TimeoutCancellationToken(100) );
); $this->assertInstanceOf(Connection::class, $connection);
$this->assertInstanceOf(Connection::class, $connection);
});
} }
/** /**
* @depends testConnect * @depends testConnect
* @expectedException \Amp\CancelledException
*/ */
public function testConnectCancellationBeforeConnect() public function testConnectCancellationBeforeConnect(): Promise
{ {
Loop::run(function () { $this->expectException(CancelledException::class);
$source = new CancellationTokenSource;
$token = $source->getToken(); $source = new CancellationTokenSource;
$source->cancel(); $token = $source->getToken();
$connection = yield $this->connect(PostgresConnectionConfig::fromString('host=localhost user=postgres'), $token); $source->cancel();
}); return $this->connect(PostgresConnectionConfig::fromString('host=localhost user=postgres'), $token);
} }
/** /**
* @depends testConnectCancellationBeforeConnect * @depends testConnectCancellationBeforeConnect
*/ */
public function testConnectCancellationAfterConnect() public function testConnectCancellationAfterConnect(): \Generator
{ {
Loop::run(function () { $source = new CancellationTokenSource;
$source = new CancellationTokenSource; $token = $source->getToken();
$token = $source->getToken(); $connection = yield $this->connect(PostgresConnectionConfig::fromString('host=localhost user=postgres'), $token);
$connection = yield $this->connect(PostgresConnectionConfig::fromString('host=localhost user=postgres'), $token); $this->assertInstanceOf(Connection::class, $connection);
$this->assertInstanceOf(Connection::class, $connection); $source->cancel();
$source->cancel();
});
} }
/** /**
* @depends testConnectCancellationBeforeConnect * @depends testConnectCancellationBeforeConnect
* @expectedException \Amp\Sql\FailureException
*/ */
public function testConnectInvalidUser() public function testConnectInvalidUser(): Promise
{ {
Loop::run(function () { $this->expectException(FailureException::class);
$connection = yield $this->connect(PostgresConnectionConfig::fromString('host=localhost user=invalid'), new TimeoutCancellationToken(100));
}); return $this->connect(PostgresConnectionConfig::fromString('host=localhost user=invalid'), new TimeoutCancellationToken(100));
} }
} }

View File

@ -4,20 +4,22 @@ namespace Amp\Postgres\Test;
use Amp\Coroutine; use Amp\Coroutine;
use Amp\Delayed; use Amp\Delayed;
use Amp\Iterator;
use Amp\Loop; use Amp\Loop;
use Amp\PHPUnit\AsyncTestCase;
use Amp\Postgres\Link; use Amp\Postgres\Link;
use Amp\Postgres\Listener; use Amp\Postgres\Listener;
use Amp\Postgres\QueryExecutionError; use Amp\Postgres\QueryExecutionError;
use Amp\Postgres\ResultSet; use Amp\Postgres\ResultSet;
use Amp\Postgres\Transaction; use Amp\Postgres\Transaction;
use Amp\Promise;
use Amp\Sql\CommandResult; use Amp\Sql\CommandResult;
use Amp\Sql\QueryError; use Amp\Sql\QueryError;
use Amp\Sql\Statement; use Amp\Sql\Statement;
use Amp\Sql\Transaction as SqlTransaction; use Amp\Sql\Transaction as SqlTransaction;
use Amp\Sql\TransactionError; use Amp\Sql\TransactionError;
use PHPUnit\Framework\TestCase;
abstract class AbstractLinkTest extends TestCase abstract class AbstractLinkTest extends AsyncTestCase
{ {
/** @var \Amp\Postgres\Connection */ /** @var \Amp\Postgres\Connection */
protected $connection; protected $connection;
@ -44,438 +46,412 @@ abstract class AbstractLinkTest extends TestCase
public function setUp() public function setUp()
{ {
parent::setUp();
$this->connection = $this->createLink('host=localhost user=postgres'); $this->connection = $this->createLink('host=localhost user=postgres');
} }
public function testQueryWithTupleResult() public function testQueryWithTupleResult(): \Generator
{ {
Loop::run(function () { /** @var \Amp\Postgres\ResultSet $result */
/** @var \Amp\Postgres\ResultSet $result */ $result = yield $this->connection->query("SELECT * FROM test");
$result = yield $this->connection->query("SELECT * FROM test");
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount()); $this->assertSame(2, $result->getFieldCount());
$data = $this->getData(); $data = $this->getData();
for ($i = 0; yield $result->advance(); ++$i) { for ($i = 0; yield $result->advance(); ++$i) {
$row = $result->getCurrent(); $row = $result->getCurrent();
$this->assertSame($data[$i][0], $row['domain']); $this->assertSame($data[$i][0], $row['domain']);
$this->assertSame($data[$i][1], $row['tld']); $this->assertSame($data[$i][1], $row['tld']);
} }
});
} }
public function testQueryWithUnconsumedTupleResult() public function testQueryWithUnconsumedTupleResult(): \Generator
{ {
Loop::run(function () { /** @var \Amp\Postgres\ResultSet $result */
/** @var \Amp\Postgres\ResultSet $result */ $result = yield $this->connection->query("SELECT * FROM test");
$result = yield $this->connection->query("SELECT * FROM test");
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
/** @var \Amp\Postgres\ResultSet $result */ unset($result); // Force destruction of result object.
$result = yield $this->connection->query("SELECT * FROM test");
$this->assertInstanceOf(ResultSet::class, $result); /** @var \Amp\Postgres\ResultSet $result */
$result = yield $this->connection->query("SELECT * FROM test");
$data = $this->getData(); $this->assertInstanceOf(ResultSet::class, $result);
for ($i = 0; yield $result->advance(); ++$i) { $data = $this->getData();
$row = $result->getCurrent();
$this->assertSame($data[$i][0], $row['domain']); for ($i = 0; yield $result->advance(); ++$i) {
$this->assertSame($data[$i][1], $row['tld']); $row = $result->getCurrent();
} $this->assertSame($data[$i][0], $row['domain']);
}); $this->assertSame($data[$i][1], $row['tld']);
}
} }
public function testQueryWithCommandResult() public function testQueryWithCommandResult(): \Generator
{ {
Loop::run(function () { /** @var CommandResult $result */
/** @var CommandResult $result */ $result = yield $this->connection->query("INSERT INTO test VALUES ('canon', 'jp')");
$result = yield $this->connection->query("INSERT INTO test VALUES ('canon', 'jp')");
$this->assertInstanceOf(CommandResult::class, $result); $this->assertInstanceOf(CommandResult::class, $result);
$this->assertSame(1, $result->getAffectedRowCount()); $this->assertSame(1, $result->getAffectedRowCount());
});
} }
/** /**
* @expectedException \Amp\Sql\QueryError * @expectedException \Amp\Sql\QueryError
*/ */
public function testQueryWithEmptyQuery() public function testQueryWithEmptyQuery(): Promise
{ {
Loop::run(function () { /** @var \Amp\Sql\CommandResult $result */
/** @var \Amp\Sql\CommandResult $result */ return $this->connection->query('');
$result = yield $this->connection->query('');
});
} }
public function testQueryWithSyntaxError() public function testQueryWithSyntaxError(): \Generator
{ {
Loop::run(function () { /** @var \Amp\Sql\CommandResult $result */
/** @var \Amp\Sql\CommandResult $result */ try {
try { $result = yield $this->connection->query("SELECT & FROM test");
$result = yield $this->connection->query("SELECT & FROM test"); $this->fail(\sprintf("An instance of %s was expected to be thrown", QueryExecutionError::class));
$this->fail(\sprintf("An instance of %s was expected to be thrown", QueryExecutionError::class)); } catch (QueryExecutionError $exception) {
} catch (QueryExecutionError $exception) { $diagnostics = $exception->getDiagnostics();
$diagnostics = $exception->getDiagnostics(); $this->assertArrayHasKey("sqlstate", $diagnostics);
$this->assertArrayHasKey("sqlstate", $diagnostics); }
}
});
} }
public function testPrepare() public function testPrepare(): \Generator
{ {
Loop::run(function () { $query = "SELECT * FROM test WHERE domain=\$1";
$query = "SELECT * FROM test WHERE domain=\$1";
/** @var Statement $statement */ /** @var Statement $statement */
$statement = yield $this->connection->prepare($query); $statement = yield $this->connection->prepare($query);
$this->assertSame($query, $statement->getQuery()); $this->assertSame($query, $statement->getQuery());
$data = $this->getData()[0]; $data = $this->getData()[0];
/** @var \Amp\Postgres\ResultSet $result */ /** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement->execute([$data[0]]); $result = yield $statement->execute([$data[0]]);
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount()); $this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) { while (yield $result->advance()) {
$row = $result->getCurrent(); $row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']); $this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']); $this->assertSame($data[1], $row['tld']);
} }
});
} }
/** /**
* @depends testPrepare * @depends testPrepare
*/ */
public function testPrepareWithNamedParams() public function testPrepareWithNamedParams(): \Generator
{ {
Loop::run(function () { $query = "SELECT * FROM test WHERE domain=:domain AND tld=:tld";
$query = "SELECT * FROM test WHERE domain=:domain AND tld=:tld";
/** @var Statement $statement */ /** @var Statement $statement */
$statement = yield $this->connection->prepare($query); $statement = yield $this->connection->prepare($query);
$data = $this->getData()[0]; $data = $this->getData()[0];
$this->assertSame($query, $statement->getQuery()); $this->assertSame($query, $statement->getQuery());
/** @var \Amp\Postgres\ResultSet $result */ /** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement->execute(['domain' => $data[0], 'tld' => $data[1]]); $result = yield $statement->execute(['domain' => $data[0], 'tld' => $data[1]]);
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount()); $this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) { while (yield $result->advance()) {
$row = $result->getCurrent(); $row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']); $this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']); $this->assertSame($data[1], $row['tld']);
} }
});
} }
/** /**
* @depends testPrepare * @depends testPrepare
*/ */
public function testPrepareWithUnnamedParams() public function testPrepareWithUnnamedParams(): \Generator
{ {
Loop::run(function () { $query = "SELECT * FROM test WHERE domain=? AND tld=?";
$query = "SELECT * FROM test WHERE domain=? AND tld=?";
/** @var Statement $statement */ /** @var Statement $statement */
$statement = yield $this->connection->prepare($query); $statement = yield $this->connection->prepare($query);
$data = $this->getData()[0]; $data = $this->getData()[0];
$this->assertSame($query, $statement->getQuery()); $this->assertSame($query, $statement->getQuery());
/** @var \Amp\Postgres\ResultSet $result */ /** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement->execute([$data[0], $data[1]]); $result = yield $statement->execute([$data[0], $data[1]]);
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount()); $this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) { while (yield $result->advance()) {
$row = $result->getCurrent(); $row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']); $this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']); $this->assertSame($data[1], $row['tld']);
} }
});
} }
/** /**
* @depends testPrepare * @depends testPrepare
*/ */
public function testPrepareWithNamedParamsWithDataAppearingAsNamedParam() public function testPrepareWithNamedParamsWithDataAppearingAsNamedParam(): \Generator
{ {
Loop::run(function () { $query = "SELECT * FROM test WHERE domain=:domain OR domain=':domain'";
$query = "SELECT * FROM test WHERE domain=:domain OR domain=':domain'";
/** @var Statement $statement */ /** @var Statement $statement */
$statement = yield $this->connection->prepare($query); $statement = yield $this->connection->prepare($query);
$data = $this->getData()[0]; $data = $this->getData()[0];
$this->assertSame($query, $statement->getQuery()); $this->assertSame($query, $statement->getQuery());
/** @var \Amp\Postgres\ResultSet $result */ /** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement->execute(['domain' => $data[0]]); $result = yield $statement->execute(['domain' => $data[0]]);
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount()); $this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) { while (yield $result->advance()) {
$row = $result->getCurrent(); $row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']); $this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']); $this->assertSame($data[1], $row['tld']);
} }
});
}
/**
* @depends testPrepare
* @expectedException \Amp\Postgres\QueryExecutionError
* @expectedExceptionMessage column "invalid" does not exist
*/
public function testPrepareInvalidQuery()
{
Loop::run(function () {
$query = "SELECT * FROM test WHERE invalid=\$1";
/** @var Statement $statement */
$statement = yield $this->connection->prepare($query);
});
} }
/** /**
* @depends testPrepare * @depends testPrepare
*/ */
public function testPrepareSameQuery() public function testPrepareInvalidQuery(): Promise
{ {
Loop::run(function () { $this->expectException(QueryExecutionError::class);
$sql = "SELECT * FROM test WHERE domain=\$1"; $this->expectExceptionMessage('column "invalid" does not exist');
/** @var Statement $statement1 */ $query = "SELECT * FROM test WHERE invalid=\$1";
$statement1 = yield $this->connection->prepare($sql);
/** @var Statement $statement2 */ /** @var Statement $statement */
$statement2 = yield $this->connection->prepare($sql); return $this->connection->prepare($query);
}
$this->assertInstanceOf(Statement::class, $statement1); /**
$this->assertInstanceOf(Statement::class, $statement2); * @depends testPrepare
*/
public function testPrepareSameQuery(): \Generator
{
$sql = "SELECT * FROM test WHERE domain=\$1";
unset($statement1); /** @var Statement $statement1 */
$statement1 = yield $this->connection->prepare($sql);
$data = $this->getData()[0]; /** @var Statement $statement2 */
$statement2 = yield $this->connection->prepare($sql);
/** @var \Amp\Postgres\ResultSet $result */ $this->assertInstanceOf(Statement::class, $statement1);
$result = yield $statement2->execute([$data[0]]); $this->assertInstanceOf(Statement::class, $statement2);
$this->assertInstanceOf(ResultSet::class, $result); unset($statement1);
$this->assertSame(2, $result->getFieldCount()); $data = $this->getData()[0];
while (yield $result->advance()) { /** @var \Amp\Postgres\ResultSet $result */
$row = $result->getCurrent(); $result = yield $statement2->execute([$data[0]]);
$this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']); $this->assertInstanceOf(ResultSet::class, $result);
}
}); $this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) {
$row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']);
}
} }
/** /**
* @depends testPrepareSameQuery * @depends testPrepareSameQuery
*/ */
public function testSimultaneousPrepareSameQuery() public function testSimultaneousPrepareSameQuery(): \Generator
{ {
Loop::run(function () { $sql = "SELECT * FROM test WHERE domain=\$1";
$sql = "SELECT * FROM test WHERE domain=\$1";
$statement1 = $this->connection->prepare($sql); $statement1 = $this->connection->prepare($sql);
$statement2 = $this->connection->prepare($sql); $statement2 = $this->connection->prepare($sql);
/** /**
* @var Statement $statement1 * @var Statement $statement1
* @var Statement $statement2 * @var Statement $statement2
*/ */
list($statement1, $statement2) = yield [$statement1, $statement2]; list($statement1, $statement2) = yield [$statement1, $statement2];
$this->assertInstanceOf(Statement::class, $statement1); $this->assertInstanceOf(Statement::class, $statement1);
$this->assertInstanceOf(Statement::class, $statement2); $this->assertInstanceOf(Statement::class, $statement2);
$data = $this->getData()[0]; $data = $this->getData()[0];
/** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement1->execute([$data[0]]);
$this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) {
$row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']);
}
unset($statement1);
/** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement2->execute([$data[0]]);
$this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) {
$row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']);
}
}
public function testPrepareSimilarQueryReturnsDifferentStatements(): \Generator
{
/** @var Statement $statement1 */
$statement1 = $this->connection->prepare("SELECT * FROM test WHERE domain=\$1");
/** @var Statement $statement2 */
$statement2 = $this->connection->prepare("SELECT * FROM test WHERE domain=:domain");
list($statement1, $statement2) = yield [$statement1, $statement2];
$this->assertInstanceOf(Statement::class, $statement1);
$this->assertInstanceOf(Statement::class, $statement2);
$this->assertNotSame($statement1, $statement2);
$data = $this->getData()[0];
$results = [];
$results[] = yield Iterator\toArray(yield $statement1->execute([$data[0]]));
$results[] = yield Iterator\toArray(yield $statement2->execute(['domain' => $data[0]]));
foreach ($results as $result) {
/** @var \Amp\Postgres\ResultSet $result */ /** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement1->execute([$data[0]]); foreach ($result as $row) {
$this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) {
$row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']); $this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']); $this->assertSame($data[1], $row['tld']);
} }
}
unset($statement1);
/** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement2->execute([$data[0]]);
$this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) {
$row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']);
}
});
} }
public function testPrepareSimilarQueryReturnsDifferentStatements() public function testPrepareThenExecuteWithUnconsumedTupleResult(): \Generator
{ {
Loop::run(function () { /** @var Statement $statement */
/** @var Statement $statement1 */ $statement = yield $this->connection->prepare("SELECT * FROM test");
$statement1 = $this->connection->prepare("SELECT * FROM test WHERE domain=\$1");
/** @var Statement $statement2 */ /** @var \Amp\Postgres\ResultSet $result */
$statement2 = $this->connection->prepare("SELECT * FROM test WHERE domain=:domain"); $result = yield $statement->execute();
list($statement1, $statement2) = yield [$statement1, $statement2]; $this->assertInstanceOf(ResultSet::class, $result);
$this->assertInstanceOf(Statement::class, $statement1); unset($result); // Force destruction of result object.
$this->assertInstanceOf(Statement::class, $statement2);
$this->assertNotSame($statement1, $statement2); /** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement->execute();
$data = $this->getData()[0]; $this->assertInstanceOf(ResultSet::class, $result);
$results = yield [$statement1->execute([$data[0]]), $statement2->execute(['domain' => $data[0]])]; $data = $this->getData();
foreach ($results as $result) { for ($i = 0; yield $result->advance(); ++$i) {
/** @var \Amp\Postgres\ResultSet $result */ $row = $result->getCurrent();
while (yield $result->advance()) { $this->assertSame($data[$i][0], $row['domain']);
$row = $result->getCurrent(); $this->assertSame($data[$i][1], $row['tld']);
$this->assertSame($data[0], $row['domain']); }
$this->assertSame($data[1], $row['tld']);
}
}
});
} }
public function testPrepareThenExecuteWithUnconsumedTupleResult() public function testExecute(): \Generator
{ {
Loop::run(function () { $data = $this->getData()[0];
/** @var Statement $statement */
$statement = yield $this->connection->prepare("SELECT * FROM test");
/** @var \Amp\Postgres\ResultSet $result */ /** @var \Amp\Postgres\ResultSet $result */
$result = yield $statement->execute(); $result = yield $this->connection->execute("SELECT * FROM test WHERE domain=\$1", [$data[0]]);
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
/** @var \Amp\Postgres\ResultSet $result */ $this->assertSame(2, $result->getFieldCount());
$result = yield $statement->execute();
$this->assertInstanceOf(ResultSet::class, $result); while (yield $result->advance()) {
$row = $result->getCurrent();
$data = $this->getData(); $this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']);
for ($i = 0; yield $result->advance(); ++$i) { }
$row = $result->getCurrent();
$this->assertSame($data[$i][0], $row['domain']);
$this->assertSame($data[$i][1], $row['tld']);
}
});
}
public function testExecute()
{
Loop::run(function () {
$data = $this->getData()[0];
/** @var \Amp\Postgres\ResultSet $result */
$result = yield $this->connection->execute("SELECT * FROM test WHERE domain=\$1", [$data[0]]);
$this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) {
$row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']);
}
});
} }
/** /**
* @depends testExecute * @depends testExecute
*/ */
public function testExecuteWithNamedParams() public function testExecuteWithNamedParams(): \Generator
{ {
Loop::run(function () { $data = $this->getData()[0];
$data = $this->getData()[0];
/** @var \Amp\Postgres\ResultSet $result */ /** @var \Amp\Postgres\ResultSet $result */
$result = yield $this->connection->execute( $result = yield $this->connection->execute(
"SELECT * FROM test WHERE domain=:domain", "SELECT * FROM test WHERE domain=:domain",
['domain' => $data[0]] ['domain' => $data[0]]
); );
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
$this->assertSame(2, $result->getFieldCount()); $this->assertSame(2, $result->getFieldCount());
while (yield $result->advance()) { while (yield $result->advance()) {
$row = $result->getCurrent(); $row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']); $this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']); $this->assertSame($data[1], $row['tld']);
} }
});
} }
/** /**
* @depends testExecute * @depends testExecute
* @expectedException \Error
* @expectedExceptionMessage Value for unnamed parameter at position 0 missing
*/ */
public function testExecuteWithInvalidParams() public function testExecuteWithInvalidParams(): Promise
{ {
Loop::run(function () { $this->expectException(\Error::class);
$result = yield $this->connection->execute("SELECT * FROM test WHERE domain=\$1"); $this->expectExceptionMessage("Value for unnamed parameter at position 0 missing");
});
return $this->connection->execute("SELECT * FROM test WHERE domain=\$1");
} }
/** /**
* @depends testExecute * @depends testExecute
* @expectedException \Error
* @expectedExceptionMessage Value for named parameter 'domain' missing
*/ */
public function testExecuteWithInvalidNamedParams() public function testExecuteWithInvalidNamedParams(): Promise
{ {
Loop::run(function () { $this->expectException(\Error::class);
$result = yield $this->connection->execute("SELECT * FROM test WHERE domain=:domain", ['tld' => 'com']); $this->expectExceptionMessage("Value for named parameter 'domain' missing");
});
return $this->connection->execute("SELECT * FROM test WHERE domain=:domain", ['tld' => 'com']);
} }
/** /**
* @depends testQueryWithTupleResult * @depends testQueryWithTupleResult
*/ */
public function testSimultaneousQuery() public function testSimultaneousQuery(): Promise
{ {
$callback = \Amp\coroutine(function ($value) { $callback = \Amp\coroutine(function ($value) {
/** @var \Amp\Postgres\ResultSet $result */ /** @var \Amp\Postgres\ResultSet $result */
@ -491,15 +467,13 @@ abstract class AbstractLinkTest extends TestCase
} }
}); });
Loop::run(function () use ($callback) { return Promise\all([$callback(0), $callback(1)]);
yield [$callback(0), $callback(1)];
});
} }
/** /**
* @depends testSimultaneousQuery * @depends testSimultaneousQuery
*/ */
public function testSimultaneousQueryWithOneFailing() public function testSimultaneousQueryWithOneFailing(): \Generator
{ {
$callback = \Amp\coroutine(function ($query) { $callback = \Amp\coroutine(function ($query) {
/** @var \Amp\Postgres\ResultSet $result */ /** @var \Amp\Postgres\ResultSet $result */
@ -516,14 +490,14 @@ abstract class AbstractLinkTest extends TestCase
return $result; return $result;
}); });
try { $result = null;
Loop::run(function () use (&$result, $callback) {
$successful = $callback("SELECT * FROM test");
$failing = $callback("SELECT & FROM test");
$result = yield $successful; try {
yield $failing; $successful = $callback("SELECT * FROM test");
}); $failing = $callback("SELECT & FROM test");
$result = yield $successful;
yield $failing;
} catch (QueryError $exception) { } catch (QueryError $exception) {
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
return; return;
@ -532,7 +506,7 @@ abstract class AbstractLinkTest extends TestCase
$this->fail(\sprintf("Test did not throw an instance of %s", QueryError::class)); $this->fail(\sprintf("Test did not throw an instance of %s", QueryError::class));
} }
public function testSimultaneousQueryAndPrepare() public function testSimultaneousQueryAndPrepare(): Promise
{ {
$promises = []; $promises = [];
$promises[] = new Coroutine((function () { $promises[] = new Coroutine((function () {
@ -564,12 +538,10 @@ abstract class AbstractLinkTest extends TestCase
} }
})()); })());
Loop::run(function () use ($promises) { return Promise\all($promises);
yield $promises;
});
} }
public function testSimultaneousPrepareAndExecute() public function testSimultaneousPrepareAndExecute(): Promise
{ {
$promises[] = new Coroutine((function () { $promises[] = new Coroutine((function () {
/** @var Statement $statement */ /** @var Statement $statement */
@ -600,121 +572,115 @@ abstract class AbstractLinkTest extends TestCase
} }
})()); })());
Loop::run(function () use ($promises) { return Promise\all($promises);
yield $promises;
});
} }
public function testTransaction() public function testTransaction(): \Generator
{ {
Loop::run(function () { $isolation = SqlTransaction::ISOLATION_COMMITTED;
$isolation = SqlTransaction::ISOLATION_COMMITTED;
/** @var \Amp\Postgres\Transaction $transaction */ /** @var \Amp\Postgres\Transaction $transaction */
$transaction = yield $this->connection->beginTransaction($isolation); $transaction = yield $this->connection->beginTransaction($isolation);
$this->assertInstanceOf(Transaction::class, $transaction); $this->assertInstanceOf(Transaction::class, $transaction);
$data = $this->getData()[0]; $data = $this->getData()[0];
$this->assertTrue($transaction->isAlive()); $this->assertTrue($transaction->isAlive());
$this->assertTrue($transaction->isActive()); $this->assertTrue($transaction->isActive());
$this->assertSame($isolation, $transaction->getIsolationLevel()); $this->assertSame($isolation, $transaction->getIsolationLevel());
yield $transaction->createSavepoint('test'); yield $transaction->createSavepoint('test');
$statement = yield $transaction->prepare("SELECT * FROM test WHERE domain=:domain"); $statement = yield $transaction->prepare("SELECT * FROM test WHERE domain=:domain");
$result = yield $statement->execute(['domain' => $data[0]]); $result = yield $statement->execute(['domain' => $data[0]]);
$this->assertInstanceOf(ResultSet::class, $result); $this->assertInstanceOf(ResultSet::class, $result);
$result = yield $transaction->execute("SELECT * FROM test WHERE domain=\$1 FOR UPDATE", [$data[0]]); unset($result); // Force destruction of result object.
$this->assertInstanceOf(ResultSet::class, $result); $result = yield $transaction->execute("SELECT * FROM test WHERE domain=\$1 FOR UPDATE", [$data[0]]);
yield $transaction->rollbackTo('test'); $this->assertInstanceOf(ResultSet::class, $result);
yield $transaction->commit(); unset($result); // Force destruction of result object.
$this->assertFalse($transaction->isAlive()); yield $transaction->rollbackTo('test');
$this->assertFalse($transaction->isActive());
try { yield $transaction->commit();
$result = yield $transaction->execute("SELECT * FROM test");
$this->fail('Query should fail after transaction commit'); $this->assertFalse($transaction->isAlive());
} catch (TransactionError $exception) { $this->assertFalse($transaction->isActive());
// Exception expected.
} try {
}); $result = yield $transaction->execute("SELECT * FROM test");
$this->fail('Query should fail after transaction commit');
} catch (TransactionError $exception) {
// Exception expected.
}
} }
public function testListen() public function testListen(): \Generator
{ {
Loop::run(function () { $channel = "test";
$channel = "test"; /** @var \Amp\Postgres\Listener $listener */
/** @var \Amp\Postgres\Listener $listener */ $listener = yield $this->connection->listen($channel);
$listener = yield $this->connection->listen($channel);
$this->assertInstanceOf(Listener::class, $listener); $this->assertInstanceOf(Listener::class, $listener);
$this->assertSame($channel, $listener->getChannel()); $this->assertSame($channel, $listener->getChannel());
Loop::delay(100, function () use ($channel) { Loop::delay(100, function () use ($channel) {
yield $this->connection->query(\sprintf("NOTIFY %s, '%s'", $channel, '0')); yield $this->connection->query(\sprintf("NOTIFY %s, '%s'", $channel, '0'));
yield $this->connection->query(\sprintf("NOTIFY %s, '%s'", $channel, '1')); yield $this->connection->query(\sprintf("NOTIFY %s, '%s'", $channel, '1'));
});
$count = 0;
Loop::delay(200, function () use ($listener) {
$listener->unlisten();
});
while (yield $listener->advance()) {
$this->assertSame($listener->getCurrent()->payload, (string) $count++);
}
$this->assertSame(2, $count);
}); });
$count = 0;
Loop::delay(200, function () use ($listener) {
$listener->unlisten();
});
while (yield $listener->advance()) {
$this->assertSame($listener->getCurrent()->payload, (string) $count++);
}
$this->assertSame(2, $count);
} }
/** /**
* @depends testListen * @depends testListen
*/ */
public function testNotify() public function testNotify(): \Generator
{ {
Loop::run(function () { $channel = "test";
$channel = "test"; /** @var \Amp\Postgres\Listener $listener */
/** @var \Amp\Postgres\Listener $listener */ $listener = yield $this->connection->listen($channel);
$listener = yield $this->connection->listen($channel);
Loop::delay(100, function () use ($channel) { Loop::delay(100, function () use ($channel) {
yield $this->connection->notify($channel, '0'); yield $this->connection->notify($channel, '0');
yield $this->connection->notify($channel, '1'); yield $this->connection->notify($channel, '1');
});
$count = 0;
Loop::delay(200, function () use ($listener) {
$listener->unlisten();
});
while (yield $listener->advance()) {
$this->assertSame($listener->getCurrent()->payload, (string) $count++);
}
$this->assertSame(2, $count);
}); });
$count = 0;
Loop::delay(200, function () use ($listener) {
$listener->unlisten();
});
while (yield $listener->advance()) {
$this->assertSame($listener->getCurrent()->payload, (string) $count++);
}
$this->assertSame(2, $count);
} }
/** /**
* @depends testListen * @depends testListen
* @expectedException \Amp\Sql\QueryError
* @expectedExceptionMessage Already listening on channel
*/ */
public function testListenOnSameChannel() public function testListenOnSameChannel(): Promise
{ {
Loop::run(function () { $this->expectException(QueryError::class);
$channel = "test"; $this->expectExceptionMessage('Already listening on channel');
$listener = yield $this->connection->listen($channel);
$listener = yield $this->connection->listen($channel); $channel = "test";
}); return Promise\all([$this->connection->listen($channel), $this->connection->listen($channel)]);
} }
} }

View File

@ -2,8 +2,9 @@
namespace Amp\Postgres\Test; namespace Amp\Postgres\Test;
use Amp\PHPUnit\TestCase;
use Amp\Postgres\Internal\ArrayParser; use Amp\Postgres\Internal\ArrayParser;
use Amp\Postgres\ParseException;
use PHPUnit\Framework\TestCase;
class ArrayParserTest extends TestCase class ArrayParserTest extends TestCase
{ {
@ -127,42 +128,38 @@ class ArrayParserTest extends TestCase
$this->assertSame($array, $this->parser->parse($string)); $this->assertSame($array, $this->parser->parse($string));
} }
/**
* @expectedException \Amp\Postgres\ParseException
* @expectedExceptionMessage Missing opening or closing brackets
*/
public function testNoClosingBracket() public function testNoClosingBracket()
{ {
$this->expectException(ParseException::class);
$this->expectExceptionMessage('Missing opening or closing brackets');
$string = '{"one", "two"'; $string = '{"one", "two"';
$this->parser->parse($string); $this->parser->parse($string);
} }
/**
* @expectedException \Amp\Postgres\ParseException
* @expectedExceptionMessage Data left in buffer after parsing
*/
public function testTrailingData() public function testTrailingData()
{ {
$this->expectException(ParseException::class);
$this->expectExceptionMessage('Data left in buffer after parsing');
$string = '{"one", "two"} data}'; $string = '{"one", "two"} data}';
$this->parser->parse($string); $this->parser->parse($string);
} }
/**
* @expectedException \Amp\Postgres\ParseException
* @expectedExceptionMessage Could not find matching quote in quoted value
*/
public function testMissingQuote() public function testMissingQuote()
{ {
$this->expectException(ParseException::class);
$this->expectExceptionMessage('Could not find matching quote in quoted value');
$string = '{"one", "two}'; $string = '{"one", "two}';
$this->parser->parse($string); $this->parser->parse($string);
} }
/**
* @expectedException \Amp\Postgres\ParseException
* @expectedExceptionMessage Invalid delimiter
*/
public function testInvalidDelimiter() public function testInvalidDelimiter()
{ {
$this->expectException(ParseException::class);
$this->expectExceptionMessage('Invalid delimiter');
$string = '{"one"; "two"}'; $string = '{"one"; "two"}';
$this->parser->parse($string); $this->parser->parse($string);
} }

View File

@ -2,8 +2,8 @@
namespace Amp\Postgres\Test; namespace Amp\Postgres\Test;
use Amp\PHPUnit\TestCase;
use Amp\Postgres\ConnectionConfig; use Amp\Postgres\ConnectionConfig;
use PHPUnit\Framework\TestCase;
class ConnectionConfigTest extends TestCase class ConnectionConfigTest extends TestCase
{ {

View File

@ -2,7 +2,7 @@
namespace Amp\Postgres\Test; namespace Amp\Postgres\Test;
use Amp\PHPUnit\TestCase; use PHPUnit\Framework\TestCase;
use function Amp\Postgres\encode; use function Amp\Postgres\encode;
class EncodeTest extends TestCase class EncodeTest extends TestCase
@ -79,12 +79,11 @@ class EncodeTest extends TestCase
$this->assertSame($string, encode($array)); $this->assertSame($string, encode($array));
} }
/**
* @expectedException \Error
* @expectedExceptionMessage Object without a __toString() method in array
*/
public function testObjectWithoutToStringMethod() public function testObjectWithoutToStringMethod()
{ {
$this->expectException(\Error::class);
$this->expectExceptionMessage('Object without a __toString() method in array');
encode([new \stdClass]); encode([new \stdClass]);
} }
} }

View File

@ -2,36 +2,34 @@
namespace Amp\Postgres\Test; namespace Amp\Postgres\Test;
use Amp\Loop; use Amp\PHPUnit\AsyncTestCase;
use Amp\Postgres\Connection; use Amp\Postgres\Connection;
use Amp\Postgres\ConnectionConfig; use Amp\Postgres\ConnectionConfig;
use PHPUnit\Framework\TestCase; use Amp\Promise;
use Amp\Sql\FailureException;
use function Amp\Postgres\connect; use function Amp\Postgres\connect;
class FunctionsTest extends TestCase class FunctionsTest extends AsyncTestCase
{ {
public function setUp() public function setUp()
{ {
parent::setUp();
if (!\extension_loaded('pgsql') && !\extension_loaded('pq')) { if (!\extension_loaded('pgsql') && !\extension_loaded('pq')) {
$this->markTestSkipped('This test requires either ext/pgsql or pecl/pq'); $this->markTestSkipped('This test requires either ext/pgsql or pecl/pq');
} }
} }
public function testConnect() public function testConnect(): \Generator
{ {
Loop::run(function () { $connection = yield connect(ConnectionConfig::fromString('host=localhost user=postgres'));
$connection = yield connect(ConnectionConfig::fromString('host=localhost user=postgres')); $this->assertInstanceOf(Connection::class, $connection);
$this->assertInstanceOf(Connection::class, $connection);
});
} }
/** public function testConnectInvalidUser(): Promise
* @expectedException \Amp\Sql\FailureException
*/
public function testConnectInvalidUser()
{ {
Loop::run(function () { $this->expectException(FailureException::class);
$connection = yield connect(ConnectionConfig::fromString('host=localhost user=invalid'));
}); return connect(ConnectionConfig::fromString('host=localhost user=invalid'));
} }
} }