1
0
mirror of https://github.com/danog/postgres.git synced 2024-12-02 17:37:57 +01:00
postgres/test/AbstractPoolTest.php

244 lines
7.2 KiB
PHP
Raw Normal View History

<?php
2016-09-14 16:27:39 +02:00
namespace Amp\Postgres\Test;
2017-11-06 06:06:17 +01:00
use Amp\Delayed;
use Amp\Loop;
use Amp\Postgres\CommandResult;
use Amp\Postgres\Connection;
use Amp\Postgres\Listener;
2017-11-06 06:06:17 +01:00
use Amp\Postgres\Pool;
use Amp\Postgres\ResultSet;
2017-12-03 02:56:40 +01:00
use Amp\Postgres\Transaction;
use Amp\Promise;
2017-05-26 17:47:44 +02:00
use PHPUnit\Framework\TestCase;
use function Amp\call;
2016-09-14 16:27:39 +02:00
2017-05-26 17:47:44 +02:00
abstract class AbstractPoolTest extends TestCase {
2016-09-14 16:27:39 +02:00
/**
* @param array $connections
*
* @return \Amp\Postgres\Pool
*/
2017-11-06 06:06:17 +01:00
abstract protected function createPool(array $connections): Pool;
2016-09-14 16:27:39 +02:00
/**
* @return \PHPUnit_Framework_MockObject_MockObject|\Amp\Postgres\Connection
2016-09-14 16:27:39 +02:00
*/
2017-11-06 06:06:17 +01:00
protected function createConnection(): Connection {
$mock = $this->createMock(Connection::class);
$mock->method('isAlive')
2017-11-06 06:06:17 +01:00
->willReturnCallback(static function () {
static $count = 0;
return $count++ < 3; // Force defunct connection after 3 operations.
});
return $mock;
2016-09-14 16:27:39 +02:00
}
/**
* @param int $count
*
* @return \Amp\Postgres\Connection[]|\PHPUnit_Framework_MockObject_MockObject[]
*/
private function makeConnectionSet(int $count) {
2016-09-14 16:27:39 +02:00
$connections = [];
for ($i = 0; $i < $count; ++$i) {
$connections[] = $this->createConnection();
}
return $connections;
}
/**
* @return array
*/
public function getMethodsAndResults() {
return [
[3, 'query', ResultSet::class, ["SELECT * FROM test"]],
[2, 'query', CommandResult::class, ["INSERT INTO test VALUES (1, 7)"]],
[5, 'listen', Listener::class, ["test"]],
[4, 'execute', ResultSet::class, ["SELECT * FROM test WHERE id=\$1 AND time>\$2", [1, time()]]],
[4, 'notify', CommandResult::class, ["test", "payload"]],
2016-09-14 16:27:39 +02:00
];
}
/**
* @dataProvider getMethodsAndResults
*
* @param int $count
* @param string $method
* @param string $resultClass
* @param mixed[] $params
2016-09-14 16:27:39 +02:00
*/
public function testSingleQuery(int $count, string $method, string $resultClass, array $params = []) {
2016-09-14 16:27:39 +02:00
$result = $this->getMockBuilder($resultClass)
->disableOriginalConstructor()
->getMock();
$connections = $this->makeConnectionSet($count);
$connection = $connections[0];
$connection->expects($this->once())
->method($method)
->with(...$params)
2017-11-06 06:06:17 +01:00
->will($this->returnValue(new Delayed(10, $result)));
2016-09-14 16:27:39 +02:00
$pool = $this->createPool($connections);
2017-05-16 06:28:37 +02:00
Loop::run(function () use ($method, $pool, $params, $result, $resultClass) {
2016-09-14 16:27:39 +02:00
$return = yield $pool->{$method}(...$params);
$this->assertInstanceOf($resultClass, $return);
});
2016-09-14 16:27:39 +02:00
}
/**
* @dataProvider getMethodsAndResults
*
* @param int $count
* @param string $method
* @param string $resultClass
* @param mixed[] $params
2016-09-14 16:27:39 +02:00
*/
public function testConsecutiveQueries(int $count, string $method, string $resultClass, array $params = []) {
2016-09-14 16:27:39 +02:00
$rounds = 3;
$result = $this->getMockBuilder($resultClass)
->disableOriginalConstructor()
->getMock();
$connections = $this->makeConnectionSet($count);
foreach ($connections as $connection) {
$connection->method($method)
->with(...$params)
2017-11-06 06:06:17 +01:00
->will($this->returnValue(new Delayed(10, $result)));
2016-09-14 16:27:39 +02:00
}
$pool = $this->createPool($connections);
2017-05-16 06:28:37 +02:00
2017-05-26 17:47:44 +02:00
Loop::run(function () use ($resultClass, $count, $rounds, $pool, $method, $params) {
2016-11-15 18:06:21 +01:00
$promises = [];
2017-05-16 06:28:37 +02:00
2016-09-14 16:27:39 +02:00
for ($i = 0; $i < $count * $rounds; ++$i) {
2016-11-15 18:06:21 +01:00
$promises[] = $pool->{$method}(...$params);
2016-09-14 16:27:39 +02:00
}
2017-05-26 17:47:44 +02:00
$results = yield Promise\all($promises);
foreach ($results as $result) {
$this->assertInstanceOf($resultClass, $result);
}
});
2016-09-14 16:27:39 +02:00
}
/**
* @return array
*/
public function getConnectionCounts() {
return array_map(function ($count) { return [$count]; }, range(1, 10));
}
/**
* @dataProvider getConnectionCounts
*
* @param int $count
*/
public function testTransaction(int $count) {
2016-09-14 16:27:39 +02:00
$connections = $this->makeConnectionSet($count);
$connection = $connections[0];
$result = $this->getMockBuilder(Transaction::class)
->disableOriginalConstructor()
->getMock();
$connection->expects($this->once())
->method('transaction')
->with(Transaction::COMMITTED)
2017-11-06 06:06:17 +01:00
->will($this->returnValue(new Delayed(10, $result)));
2016-09-14 16:27:39 +02:00
$pool = $this->createPool($connections);
2017-05-16 06:28:37 +02:00
Loop::run(function () use ($pool, $result) {
2016-09-14 16:27:39 +02:00
$return = yield $pool->transaction(Transaction::COMMITTED);
$this->assertInstanceOf(Transaction::class, $return);
yield $return->rollback();
});
2016-09-14 16:27:39 +02:00
}
/**
* @dataProvider getConnectionCounts
*
* @param int $count
*/
public function testConsecutiveTransactions(int $count) {
2016-09-14 16:27:39 +02:00
$rounds = 3;
$result = $this->getMockBuilder(Transaction::class)
->disableOriginalConstructor()
->getMock();
$connections = $this->makeConnectionSet($count);
foreach ($connections as $connection) {
$connection->method('transaction')
->with(Transaction::COMMITTED)
->will($this->returnCallback(function () use ($result) {
2017-11-06 06:06:17 +01:00
return new Delayed(10, $result);
2016-09-14 16:27:39 +02:00
}));
}
$pool = $this->createPool($connections);
2017-05-16 06:28:37 +02:00
Loop::run(function () use ($count, $rounds, $pool) {
2016-11-15 18:06:21 +01:00
$promises = [];
2017-05-26 17:47:44 +02:00
for ($i = 0; $i < $count; ++$i) {
2016-11-15 18:06:21 +01:00
$promises[] = $pool->transaction(Transaction::COMMITTED);
2016-09-14 16:27:39 +02:00
}
2017-05-26 17:47:44 +02:00
$results = yield Promise\all(\array_map(function (Promise $promise) {
2017-05-16 06:14:02 +02:00
return call(function () use ($promise) {
$transaction = yield $promise;
2017-05-26 17:47:44 +02:00
$this->assertInstanceOf(Transaction::class, $transaction);
return yield $transaction->rollback();
});
2016-11-15 18:06:21 +01:00
}, $promises));
2017-05-26 17:47:44 +02:00
foreach ($results as $result) {
$this->assertInstanceof(CommandResult::class, $result);
}
});
2016-09-14 16:27:39 +02:00
}
/**
* @dataProvider getConnectionCounts
*
* @param int $count
*/
public function testExtractConnection(int $count) {
$connections = $this->makeConnectionSet($count);
$query = "SELECT * FROM test";
foreach ($connections as $connection) {
$connection->expects($this->once())
->method('query')
->with($query);
}
$pool = $this->createPool($connections);
Loop::run(function () use ($pool, $query, $count) {
$promises = [];
for ($i = 0; $i < $count; ++$i) {
$promises[] = $pool->extractConnection();
}
$results = yield Promise\all($promises);
foreach ($results as $result) {
$this->assertInstanceof(Connection::class, $result);
$result->query($query);
}
});
}
2016-09-14 16:27:39 +02:00
}