amphp / postgres

Async Postgres client for PHP based on Amp.
MIT License
96 stars 20 forks source link

Amp\Loop\InvalidWatcherError : Cannot reference an invalid watcher identifier: 'e' #48

Closed PNixx closed 1 year ago

PNixx commented 2 years ago

I try use PHPUnit with Postgres adapter. But I catch error. amphp/postgres v1.4.3 Example code:

<?php
use Amp\PHPUnit\AsyncTestCase;
use Amp\Postgres\ConnectionConfig;

$connection = \Amp\Postgres\pool(ConnectionConfig::fromString("host=localhost port=5432 dbname=rees46_test user=rails password=rails"), 5);

class BarTest extends AsyncTestCase {

    public function test() {
        global $connection;

        $result = yield $connection->execute('SELECT 1 AS c');
        if( yield $result->advance() ) {
            $this->assertSame(1, $result->getCurrent()['c']);
        }
    }
    public function test2() {
        global $connection;

        $result = yield $connection->execute('SELECT 1 AS c');
        if( yield $result->advance() ) {
            $this->assertSame(1, $result->getCurrent()['c']);
        }
    }
}

Test log:

Testing started at 23:04 ...
PHPUnit 9.5.11 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.0.12
Configuration: /project/phpunit.xml

Amp\Loop\InvalidWatcherError : Cannot reference an invalid watcher identifier: 'e'
 /project/vendor/amphp/amp/lib/Loop/Driver.php:516
 /project/vendor/amphp/amp/lib/Loop.php:322
 /project/vendor/amphp/postgres/src/PgSqlHandle.php:269
 /project/vendor/amphp/postgres/src/PgSqlHandle.php:381
 /project/vendor/amphp/amp/lib/Coroutine.php:67
 /project/vendor/amphp/amp/lib/functions.php:96
 /project/vendor/amphp/postgres/src/PgSqlHandle.php:382
 /project/vendor/amphp/postgres/src/Connection.php:79
 /project/vendor/amphp/postgres/src/Connection.php:109
 /project/vendor/amphp/postgres/src/Pool.php:83
 /project/vendor/amphp/sql-common/src/ConnectionPool.php:363
 /project/vendor/amphp/amp/lib/Coroutine.php:67
 /project/vendor/amphp/amp/lib/functions.php:96
 /project/vendor/amphp/sql-common/src/ConnectionPool.php:382
 /project/test/BarTest.php:21
 /project/vendor/amphp/amp/lib/Coroutine.php:67
 /project/vendor/amphp/phpunit-util/src/AsyncTestCase.php:278
 /project/vendor/amphp/phpunit-util/src/AsyncTestCase.php:137
 /project/vendor/amphp/amp/lib/Coroutine.php:118
 /project/vendor/amphp/amp/lib/Success.php:41
 /project/vendor/amphp/amp/lib/Coroutine.php:151
 /project/vendor/amphp/phpunit-util/src/AsyncTestCase.php:68
 /project/vendor/amphp/amp/lib/Loop/Driver.php:119
 /project/vendor/amphp/amp/lib/Loop/Driver.php:72
 /project/vendor/amphp/amp/lib/Loop/EventDriver.php:211
 /project/vendor/amphp/amp/lib/Loop.php:95
 /project/vendor/amphp/phpunit-util/src/AsyncTestCase.php:96
 /project/vendor/amphp/phpunit-util/src/AsyncTestCase.php:46

Time: 00:00.110, Memory: 10.00 MB

ERRORS!
Tests: 2, Assertions: 1, Errors: 1.

But for this example, tests works correctly:

<?php
use Amp\PHPUnit\AsyncTestCase;
use Amp\Postgres\ConnectionConfig;

class BarTest extends AsyncTestCase {

    public function test() {
        $connection = \Amp\Postgres\pool(ConnectionConfig::fromString("host=localhost port=5432 dbname=rees46_test user=rails password=rails"), 5);

        $result = yield $connection->execute('SELECT 1 AS c');
        if( yield $result->advance() ) {
            $this->assertSame(1, $result->getCurrent()['c']);
        }
    }
    public function test2() {
        $connection = \Amp\Postgres\pool(ConnectionConfig::fromString("host=localhost port=5432 dbname=rees46_test user=rails password=rails"), 5);

        $result = yield $connection->execute('SELECT 1 AS c');
        if( yield $result->advance() ) {
            $this->assertSame(1, $result->getCurrent()['c']);
        }
    }
}

Log:

Testing started at 23:06 ...
PHPUnit 9.5.11 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.0.12
Configuration: /Users/nixx/Projects/rees46-core/phpunit.xml

Time: 00:00.113, Memory: 8.00 MB

OK (2 tests, 2 assertions)
kelunik commented 2 years ago

AsyncTestCase will use a separate event loop per test for isolation purposes, but that makes previous watchers invalid that are still supposed to be active in global state. We've removed swapping the event loop instance in the new major version for that reason.

PNixx commented 2 years ago

Do I need to connect to the DB every time I run a test? This is terrible.

kelunik commented 2 years ago

Currently, that's how it is when using AsyncTestCase, yes.

trowski commented 1 year ago

The event loop is no longer discarded between each test in AMPHP v3 and therefore in v2.x of this library, so this should no longer be an issue.

That being said, be careful about sharing state between test and that you're doing it intentionally, not accidentally.