From f302862e3a7c297e1e1c22f01c554912d5a76799 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula <42547589+terabytesoftw@users.noreply.github.com> Date: Sat, 2 Oct 2021 15:24:28 -0300 Subject: [PATCH] Adjust last changes yiisoft/db. (#80) * Adjust last changes yiisoft/db. * Remove duplicate code. * Add scrutinizer tests. Co-authored-by: Wilmer Arambula --- .editorconfig | 3 + .github/workflows/build.yml | 6 +- .github/workflows/mutation.yml | 6 +- .scrutinizer.yml | 44 ++-- composer.json | 3 +- src/Connection.php | 25 ++- tests/ConnectionTest.php | 64 +----- tests/{Data => Fixture}/postgres.sql | 0 tests/{Data => Fixture}/postgres10.sql | 0 tests/{Data => Fixture}/postgres12.sql | 0 tests/QueryBuilderTest.php | 2 +- tests/Runtime/.gitignore | 0 tests/SchemaTest.php | 4 +- tests/TestCase.php | 290 +------------------------ 14 files changed, 85 insertions(+), 362 deletions(-) rename tests/{Data => Fixture}/postgres.sql (100%) rename tests/{Data => Fixture}/postgres10.sql (100%) rename tests/{Data => Fixture}/postgres12.sql (100%) create mode 100644 tests/Runtime/.gitignore diff --git a/.editorconfig b/.editorconfig index 257221d23..5e9a93ea5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,3 +12,6 @@ trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false + +[*.yml] +indent_size = 2 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d1a1da913..4b1fe8c50 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,9 +36,9 @@ jobs: postgres: image: postgres:${{ matrix.pgsql }} env: - POSTGRES_USER: root - POSTGRES_PASSWORD: root - POSTGRES_DB: yiitest + POSTGRES_USER: scrutinizer + POSTGRES_PASSWORD: scrutinizer + POSTGRES_DB: scrutinizer ports: - 5432:5432 options: --name=postgres --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3 diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 2415d249c..05bd72397 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -27,9 +27,9 @@ jobs: postgres: image: postgres:13 env: - POSTGRES_USER: root - POSTGRES_PASSWORD: root - POSTGRES_DB: yiitest + POSTGRES_USER: scrutinizer + POSTGRES_PASSWORD: scrutinizer + POSTGRES_DB: scrutinizer ports: - 5432:5432 options: --name=postgres --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3 diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 019b32378..4a544f797 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,20 +1,36 @@ checks: - php: true + php: true filter: - paths: - - "src/*" - -tools: - external_code_coverage: - timeout: 660 + paths: + - "src/*" build: - nodes: - analysis: - environment: - php: 7.4.12 + environment: + php: + version: 8.0.11 + ini: + "xdebug.mode": coverage + + nodes: + analysis: + tests: + override: + - php-scrutinizer-run + + tests-and-coverage: + services: + postgres: 13 + + dependencies: + override: + - composer self-update + - composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - tests: - override: - - php-scrutinizer-run + tests: + override: + - command: "./vendor/bin/phpunit --coverage-clover ./coverage.xml" + on_node: 1 + coverage: + file: coverage.xml + format: php-clover diff --git a/composer.json b/composer.json index 20d40db37..5294e3a5f 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "ext-json": "*", "ext-pdo": "*", "yiisoft/arrays": "^1.0", - "yiisoft/db": "^3.0@dev", + "yiisoft/db": "^3.0", "yiisoft/json": "^1.0", "yiisoft/strings": "^2.0" }, @@ -33,7 +33,6 @@ "vimeo/psalm": "^4.4", "yiisoft/aliases": "^1.1|^2.0", "yiisoft/cache": "^1.0", - "yiisoft/di": "^3.0@dev", "yiisoft/log": "^1.0" }, "autoload": { diff --git a/src/Connection.php b/src/Connection.php index 30f3ba3d1..7b62058d3 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -7,12 +7,25 @@ use PDO; use Yiisoft\Db\Command\Command; use Yiisoft\Db\Connection\Connection as AbstractConnection; +use Yiisoft\Db\Cache\QueryCache; +use Yiisoft\Db\Cache\SchemaCache; /** * The class Connection represents a connection to a database via [PDO](https://secure.php.net/manual/en/book.pdo.php). */ final class Connection extends AbstractConnection { + private QueryCache $queryCache; + private SchemaCache $schemaCache; + + public function __construct(string $dsn, QueryCache $queryCache, SchemaCache $schemaCache) + { + $this->queryCache = $queryCache; + $this->schemaCache = $schemaCache; + + parent::__construct($dsn, $queryCache); + } + /** * Creates a command for execution. * @@ -27,7 +40,15 @@ public function createCommand(string $sql = null, array $params = []): Command $sql = $this->quoteSql($sql); } - $command = new Command($this, $sql); + $command = new Command($this, $this->queryCache, $sql); + + if ($this->logger !== null) { + $command->setLogger($this->logger); + } + + if ($this->profiler !== null) { + $command->setProfiler($this->profiler); + } return $command->bindValues($params); } @@ -39,7 +60,7 @@ public function createCommand(string $sql = null, array $params = []): Command */ public function getSchema(): Schema { - return new Schema($this); + return new Schema($this, $this->schemaCache); } /** diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php index c0eba89dc..93183de50 100644 --- a/tests/ConnectionTest.php +++ b/tests/ConnectionTest.php @@ -28,7 +28,7 @@ public function testConstruct(): void { $db = $this->getConnection(); - $this->assertEquals($this->params()['yiisoft/db-pgsql']['dsn'], $db->getDsn()); + $this->assertEquals(self::DB_DSN, $db->getDsn()); } public function testGetDriverName(): void @@ -68,7 +68,7 @@ public function testOpenClose(): void $this->assertFalse($db->isActive()); $this->assertNull($db->getPDO()); - $db = new Connection('unknown::memory:', $this->dependencies); + $db = $this->createConnection('unknown::memory:'); $this->expectException(Exception::class); $this->expectExceptionMessage('could not find driver'); @@ -182,17 +182,7 @@ public function testGetPdoAfterClose(): void { $db = $this->getConnection(); - $db->setSlaves( - '1', - [ - 'class' => Connection::class, - '__construct()' => [ - 'dsn' => $this->params()['yiisoft/db-pgsql']['dsn'], - ], - 'setUsername()' => [$db->getUsername()], - 'setPassword()' => [$db->getPassword()], - ] - ); + $db->setSlave('1', $this->createConnection(self::DB_DSN)); $this->assertNotNull($db->getSlavePdo(false)); @@ -216,17 +206,7 @@ public function testServerStatusCacheWorks(): void $db = $this->getConnection(true); - $db->setMasters( - '1', - [ - 'class' => Connection::class, - '__construct()' => [ - 'dsn' => $this->params()['yiisoft/db-pgsql']['dsn'], - ], - 'setUsername()' => [$db->getUsername()], - 'setPassword()' => [$db->getPassword()], - ] - ); + $db->setMaster('1', $this->createConnection(self::DB_DSN)); $db->setShuffleMasters(false); @@ -251,17 +231,7 @@ public function testServerStatusCacheWorks(): void ['Yiisoft\Db\Connection\Connection::openFromPoolSequentially', 'host:invalid'] ); - $db->setMasters( - '1', - [ - 'class' => Connection::class, - '__construct()' => [ - 'dsn' => 'host:invalid', - ], - 'setUsername()' => [$db->getUsername()], - 'setPassword()' => [$db->getPassword()], - ] - ); + $db->setMaster('1', $this->createConnection('host:invalid')); $db->setShuffleMasters(true); @@ -284,17 +254,7 @@ public function testServerStatusCacheCanBeDisabled(): void $db = $this->getConnection(); - $db->setMasters( - '1', - [ - 'class' => Connection::class, - '__construct()' => [ - 'dsn' => $this->params()['yiisoft/db-pgsql']['dsn'], - ], - 'setUsername()' => [$db->getUsername()], - 'setPassword()' => [$db->getPassword()], - ] - ); + $db->setMaster('1', $this->createConnection(self::DB_DSN)); $this->schemaCache->setEnable(false); @@ -316,17 +276,7 @@ public function testServerStatusCacheCanBeDisabled(): void ['Yiisoft\Db\Connection\Connection::openFromPoolSequentially', 'host:invalid'] ); - $db->setMasters( - '1', - [ - 'class' => Connection::class, - '__construct()' => [ - 'dsn' => 'host:invalid', - ], - 'setUsername()' => [$db->getUsername()], - 'setPassword()' => [$db->getPassword()], - ] - ); + $db->setMaster('1', $this->createConnection('host:invalid')); try { $db->open(); diff --git a/tests/Data/postgres.sql b/tests/Fixture/postgres.sql similarity index 100% rename from tests/Data/postgres.sql rename to tests/Fixture/postgres.sql diff --git a/tests/Data/postgres10.sql b/tests/Fixture/postgres10.sql similarity index 100% rename from tests/Data/postgres10.sql rename to tests/Fixture/postgres10.sql diff --git a/tests/Data/postgres12.sql b/tests/Fixture/postgres12.sql similarity index 100% rename from tests/Data/postgres12.sql rename to tests/Fixture/postgres12.sql diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index e96c6d9fc..089409153 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -157,7 +157,7 @@ public function testResetSequencePostgres12(): void $this->markTestSkipped('PostgreSQL < 12.0 does not support GENERATED AS IDENTITY columns.'); } - $this->prepareDatabase('@data/postgres12.sql'); + $this->prepareDatabase(self::DB_DSN, __DIR__ . '/Fixture/postgres12.sql'); $qb = $this->getQueryBuilder(); diff --git a/tests/Runtime/.gitignore b/tests/Runtime/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php index 15229c37e..f2260599b 100644 --- a/tests/SchemaTest.php +++ b/tests/SchemaTest.php @@ -392,7 +392,7 @@ public function testGeneratedValues(): void $this->markTestSkipped('PostgreSQL < 12.0 does not support GENERATED AS IDENTITY columns.'); } - $this->prepareDatabase('@data/postgres12.sql'); + $this->prepareDatabase(self::DB_DSN, __DIR__ . '/Fixture/postgres12.sql'); $table = $this->getConnection()->getSchema()->getTableSchema('generated'); @@ -408,7 +408,7 @@ public function testPartitionedTable(): void $this->markTestSkipped('PostgreSQL < 10.0 does not support PARTITION BY clause.'); } - $this->prepareDatabase('@data/postgres10.sql'); + $this->prepareDatabase(self::DB_DSN, __DIR__ . '/Fixture/postgres10.sql'); $this->assertNotNull($this->getConnection()->getSchema()->getTableSchema('partitioned')); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 6e39f0a87..33aea0c34 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -4,310 +4,44 @@ namespace Yiisoft\Db\Pgsql\Tests; -use Exception; use PHPUnit\Framework\TestCase as AbstractTestCase; -use Psr\Container\ContainerInterface; -use Psr\Log\LoggerInterface; -use ReflectionClass; -use ReflectionException; -use ReflectionObject; -use Yiisoft\Aliases\Aliases; -use Yiisoft\Cache\ArrayCache; -use Yiisoft\Cache\Cache; -use Yiisoft\Cache\CacheInterface; -use Yiisoft\Db\Cache\QueryCache; -use Yiisoft\Db\Cache\SchemaCache; -use Yiisoft\Db\Connection\ConnectionInterface; -use Yiisoft\Db\Connection\Dsn; -use Yiisoft\Db\Connection\LazyConnectionDependencies; -use Yiisoft\Db\Factory\DatabaseFactory; use Yiisoft\Db\Pgsql\Connection; -use Yiisoft\Db\TestUtility\IsOneOfAssert; -use Yiisoft\Di\Container; -use Yiisoft\Definitions\Reference; -use Yiisoft\Log\Logger; -use Yiisoft\Profiler\Profiler; -use Yiisoft\Profiler\ProfilerInterface; - -use function explode; -use function file_get_contents; -use function str_replace; -use function trim; +use Yiisoft\Db\TestUtility\TestTrait; class TestCase extends AbstractTestCase { + use TestTrait; + + protected const DB_CONNECTION_CLASS = \Yiisoft\Db\Pgsql\Connection::class; + protected const DB_DRIVERNAME = 'pgsql'; + protected const DB_DSN = 'pgsql:host=127.0.0.1;dbname=scrutinizer;port=5432'; + protected const DB_FIXTURES_PATH = __DIR__ . '/Fixture/postgres.sql'; + protected const DB_USERNAME = 'scrutinizer'; + protected const DB_PASSWORD = 'scrutinizer'; + protected const DB_CHARSET = 'UTF8'; protected array $dataProvider; protected array $expectedSchemas = ['public']; protected string $likeEscapeCharSql = ''; protected array $likeParameterReplacements = []; - protected Aliases $aliases; - protected CacheInterface $cache; protected Connection $connection; - protected ContainerInterface $container; - protected LazyConnectionDependencies $dependencies; - protected LoggerInterface $logger; - protected ProfilerInterface $profiler; - protected QueryCache $queryCache; - protected SchemaCache $schemaCache; protected function setUp(): void { parent::setUp(); - - $this->configContainer(); + $this->connection = $this->createConnection(self::DB_DSN); } protected function tearDown(): void { parent::tearDown(); - - $this->getConnection()->close(); - + $this->connection->close(); unset( - $this->aliases, $this->cache, $this->connection, - $this->container, - $this->dataProvider, $this->logger, $this->queryCache, $this->schemaCache, $this->profiler ); } - - /** - * Asserting two strings equality ignoring line endings. - * - * @param string $expected - * @param string $actual - * @param string $message - */ - protected function assertEqualsWithoutLE(string $expected, string $actual, string $message = ''): void - { - $expected = str_replace("\r\n", "\n", $expected); - $actual = str_replace("\r\n", "\n", $actual); - - $this->assertEquals($expected, $actual, $message); - } - - /** - * Asserts that value is one of expected values. - * - * @param mixed $actual - * @param array $expected - * @param string $message - */ - protected function assertIsOneOf($actual, array $expected, $message = ''): void - { - self::assertThat($actual, new IsOneOfAssert($expected), $message); - } - - protected function configContainer(): void - { - $this->container = new Container($this->config()); - - DatabaseFactory::initialize($this->container, []); - - $this->aliases = $this->container->get(Aliases::class); - $this->cache = $this->container->get(CacheInterface::class); - $this->connection = $this->container->get(ConnectionInterface::class); - $this->dependencies = $this->container->get(LazyConnectionDependencies::class); - $this->logger = $this->container->get(LoggerInterface::class); - $this->profiler = $this->container->get(ProfilerInterface::class); - $this->queryCache = $this->container->get(QueryCache::class); - $this->schemaCache = $this->container->get(SchemaCache::class); - } - - /** - * Invokes a inaccessible method. - * - * @param object $object - * @param string $method - * @param array $args - * @param bool $revoke whether to make method inaccessible after execution. - * - * @throws ReflectionException - * - * @return mixed - */ - protected function invokeMethod(object $object, string $method, array $args = [], bool $revoke = true) - { - $reflection = new ReflectionObject($object); - - $method = $reflection->getMethod($method); - - $method->setAccessible(true); - - $result = $method->invokeArgs($object, $args); - - if ($revoke) { - $method->setAccessible(false); - } - return $result; - } - - /** - * @param bool $reset whether to clean up the test database. - * - * @return Connection - */ - protected function getConnection($reset = false): Connection - { - if ($reset === false && isset($this->connection)) { - return $this->connection; - } - - if ($reset === false) { - $this->configContainer(); - return $this->connection; - } - - try { - $this->prepareDatabase(); - } catch (Exception $e) { - $this->markTestSkipped('Something wrong when preparing database: ' . $e->getMessage()); - } - - return $this->connection; - } - - protected function prepareDatabase(?string $fixture = null): void - { - if ($fixture === null) { - $fixture = $this->params()['yiisoft/db-pgsql']['fixture']; - } - - $this->connection->open(); - - if ($fixture !== null) { - $lines = explode(';', file_get_contents($this->aliases->get($fixture))); - - foreach ($lines as $line) { - if (trim($line) !== '') { - $this->connection->getPDO()->exec($line); - } - } - } - } - - /** - * Gets an inaccessible object property. - * - * @param object $object - * @param string $propertyName - * @param bool $revoke whether to make property inaccessible after getting. - * - * @return mixed - */ - protected function getInaccessibleProperty(object $object, string $propertyName, bool $revoke = true) - { - $class = new ReflectionClass($object); - - while (!$class->hasProperty($propertyName)) { - $class = $class->getParentClass(); - } - - $property = $class->getProperty($propertyName); - - $property->setAccessible(true); - - $result = $property->getValue($object); - - if ($revoke) { - $property->setAccessible(false); - } - - return $result; - } - - /** - * Adjust dbms specific escaping. - * - * @param array|string $sql - * - * @return array|string - */ - protected function replaceQuotes($sql) - { - return str_replace(['\\[', '\\]'], ['[', ']'], preg_replace('/(\[\[)|((?hasProperty($propertyName)) { - $class = $class->getParentClass(); - } - - $property = $class->getProperty($propertyName); - - $property->setAccessible(true); - - $property->setValue($object, $value); - - if ($revoke) { - $property->setAccessible(false); - } - } - - protected function params(): array - { - return [ - 'yiisoft/db-pgsql' => [ - 'dsn' => (new Dsn('pgsql', '127.0.0.1', 'yiitest', '5432'))->asString(), - 'username' => 'root', - 'password' => 'root', - 'charset' => 'UTF8', - 'fixture' => __DIR__ . '/Data/postgres.sql', - ], - ]; - } - - private function config(): array - { - $params = $this->params(); - - return [ - Aliases::class => [ - '__construct()' => [ - [ - '@root' => dirname(__DIR__, 1), - '@data' => '@root/tests/Data', - '@runtime' => '@data/runtime', - ], - ], - ], - - CacheInterface::class => [ - 'class' => Cache::class, - '__construct()' => [ - Reference::to(ArrayCache::class), - ], - ], - - LoggerInterface::class => Logger::class, - - ProfilerInterface::class => Profiler::class, - - ConnectionInterface::class => [ - 'class' => Connection::class, - '__construct()' => [ - 'dsn' => $params['yiisoft/db-pgsql']['dsn'], - ], - 'setUsername()' => [$params['yiisoft/db-pgsql']['username']], - 'setPassword()' => [$params['yiisoft/db-pgsql']['password']], - 'setCharset()' => [$params['yiisoft/db-pgsql']['charset']], - ], - ]; - } }