Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENHANCEMENT Ensure test DB is flushed on either DDL or transaction-disabled tests #8193

Merged

Conversation

tractorcow
Copy link
Contributor

Fixes #8182

@tractorcow
Copy link
Contributor Author

Note: We'll need to PR to other modules protected $usesTransactions = false; for tests that were failing.

@tractorcow
Copy link
Contributor Author

tractorcow commented Jun 18, 2018

ok, there's still a bug.

SapphireTest::setUpBeforeClass() has this code.

// Build DB if we have objects
if (static::getExtraDataObjects()) {
    DataObject::reset();
    static::resetDBSchema(true, true);
}

We need to occasionally do this on setUp() (not always setupBeforeClass) so it needs refactoring.

@tractorcow
Copy link
Contributor Author

Yay fixed it.

@dhensby
Copy link
Contributor

dhensby commented Jun 18, 2018

Postgres is failing for some reason :/

@tractorcow
Copy link
Contributor Author

Yeah that's ok. I'll test postgres locally.

@tractorcow
Copy link
Contributor Author

Error is in security somewhere.

@@ -232,7 +245,12 @@ public function resetDBSchema(array $extraDataObjects = [])
// pgsql doesn't allow schema updates inside transactions
// so we need to rollback any transactions before commencing a schema reset
if ($this->hasStarted()) {
$this->rollbackTransaction();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok it turns out this code doesn't work.

Trying

public function resetDBSchema(array $extraDataObjects = [])
    {
        if (!$this->isUsed()) {
            return;
        }
        try {
            $this->rebuildTables($extraDataObjects);
        } catch (DatabaseException $ex) {
            // In case of error during build force a hard reset
            // e.g. pgsql doesn't allow schema updates inside transactions
            $this->kill();
            $this->build();
            $this->rebuildTables($extraDataObjects);
        }
    }

@dhensby seem ok?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHP Fatal error:  Uncaught SilverStripe\ORM\Connect\DatabaseException: Couldn't run query:

SELECT tablename
FROM pg_catalog.pg_tables
WHERE schemaname = $1 AND tablename NOT ILIKE 'pg\\_%' AND tablename NOT ILIKE 'sql\\_%'

ERROR:  current transaction is aborted, commands ignored until end of transaction block in /Users/dmooyman/Sites/ss42test/vendor/silverstripe/framework/src/ORM/Connect/DBConnector.php:64
Stack trace:
#0 /Users/dmooyman/Sites/ss42test/vendor/silverstripe/postgresql/code/PostgreSQLConnector.php(234): SilverStripe\ORM\Connect\DBConnector->databaseError('Couldn't run qu...', 256, 'SELECT tablenam...', Array)
#1 /Users/dmooyman/Sites/ss42test/vendor/silverstripe/framework/src/ORM/Connect/Database.php(168): SilverStripe\PostgreSQL\PostgreSQLConnector->preparedQuery('SELECT tablenam...', Array, 256)
#2 /Users/dmooyman/Sites/ss42test/vendor/silverstripe/framework/src/ORM/Connect/Database.php(222): SilverStripe\ORM\Connect\Database->SilverStripe\ORM\Connect\{closure}('SELECT tablenam...')
#3 /Users/dmooyman/Sites/s in /Users/dmooyman/Sites/ss42test/vendor/silverstripe/framework/src/ORM/Connect/DBConnector.php on line 64

WHY

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need rollbackRecursive() on database.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's doing the rollback, but the rollback doesn't seem to actually rollback on postgres.

Copy link
Contributor Author

@tractorcow tractorcow Jun 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, there is like 6 levels of nesting at this error. A single rollback isn't enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok the problem is hasStarted is true sometimes when there is no transaction. After a rollback hasStarted needs to stay true, even though the transaction is rolled back. It's a badly documented var.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm dropping hasStarted() and using isUsed() instead. Between runs, there will be two states:

  • The DB Is populated, assume that it's ready and safe to use.
  • The DB is killed, assume that it requires a rebuild.

There is no "there but needs a reset state".

@tractorcow
Copy link
Contributor Author

@dhensby the last commit + silverstripe/silverstripe-postgresql#86 will fix postgres, at least for the tests that WERE failing.

I've dropped the started flag on test DB since it's not really a state of the test db, but the test fixtures. I've shifted this into a separate state in FixtureTestState.

I've also added a new API to database; databases must now report transactional nesting level, in order to enable tests to recover from incorrectly nested transactions.

This is the last hour of my last day, so I'm afraid I have to hand over to @robbieaverill + @dhensby .

@tractorcow
Copy link
Contributor Author

Local testing is VERY promising.

Only this test broke in postgres:

Time: 21.31 minutes, Memory: 124.00MB

There was 1 failure:

1) SilverStripe\ORM\Tests\DataListTest::testSortMixedCase
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
     0 => 'Bob'
-    1 => 'bonny'
-    2 => 'jane'
-    3 => 'John'
-    4 => 'sam'
-    5 => 'Steve'
+    1 => 'John'
+    2 => 'Steve'
+    3 => 'bonny'
+    4 => 'jane'
+    5 => 'sam'
     6 => 'steven'
 )

/Users/dmooyman/Sites/ss42test/vendor/silverstripe/framework/tests/php/ORM/DataListTest.php:627
/Users/dmooyman/Sites/ss42test/vendor/phpunit/phpunit/phpunit:52

FAILURES!
Tests: 2149, Assertions: 7858, Failures: 1, Skipped: 14, Incomplete: 2.
Damians-Macbook:ss42test dmooyman$ 

@tractorcow
Copy link
Contributor Author

Wow green.

This story was SO hard to get working properly... sorry in advance @dhensby if the new logic is hard to follow. =(

public function transactionDepth()
{
// Placeholder error for transactional DBs that don't expose depth
if ($this->supportsTransactions()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this logic be the opposite, i.e. if the DB doesn't support transactions, generate a user error.

Assume this hasn't surfaced because this method is overloaded in MySQL and Postgres

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, its an error because even though you support transactions, the depth is hard coded to 0.it's a placeholder for making this api abstract.

protected function setUp()
{
parent::setUp();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the benefit of this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops. That was my var dump holder lol

public function hasStarted()
{
return $this->hasStarted;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a semver break - perhaps we should leave it there but deprecate it? I realise it won't be doing anything any more other than always returning false, which could be misleading to people using this API

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too concerned about this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't in a stable tag so I'm un-api ing it.

@dhensby
Copy link
Contributor

dhensby commented Jun 19, 2018

Do we know how or why we were getting to so many levels of transaction nesting? It seems like we really shouldn't get more than 2 or 3 levels of transactions deep during a test...

@dhensby
Copy link
Contributor

dhensby commented Jun 19, 2018

A point worth making, but not something I think needs specifically addressing as we've likely covered 99% of usecases, but the commands that cause "implicit commits" aren't necassarily just DDL queries - https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html

@dhensby
Copy link
Contributor

dhensby commented Jun 19, 2018

I've addressed some of the feedback and made some changes I felt were appropriate

@dhensby
Copy link
Contributor

dhensby commented Jun 19, 2018

I'm wondering if the nested transaction changes will mean we need to go and update all our DB drivers to match

@robbieaverill
Copy link
Contributor

Ok we lost the 💚 😞

if ($this->transactionNesting <= 0) {
$this->transactionNesting = 0;
$this->query('COMMIT AND ' . ($chain ? '' : 'NO ') . 'CHAIN');
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like maybe this logic should remain, could explain the test breakages

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this back locally and re-tested and it fixes the new failures, pushed a fix to add this back

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

derp

@maxime-rainville maxime-rainville self-assigned this Jun 20, 2018
@maxime-rainville maxime-rainville merged commit df25768 into silverstripe:4.2 Jun 20, 2018
@tractorcow
Copy link
Contributor Author

@dhensby the logic on the nesting method was correct before you changed it. It's ment to error if not overridden eg sqlite. Can you revert.

@dhensby
Copy link
Contributor

dhensby commented Jun 21, 2018

@dhensby the logic on the nesting method was correct before you changed it. It's ment to error if not overridden eg sqlite. Can you revert.

ah, will do

@dhensby
Copy link
Contributor

dhensby commented Jun 21, 2018

I've pushed the change straight into the repo with 27b60ae

@dhensby
Copy link
Contributor

dhensby commented Jul 23, 2018

@maxime-rainville did you use "rebase merge" on this PR? I can't find the merge commit anywhere...

dhensby added a commit to dhensby/silverstripe-framework that referenced this pull request Jul 23, 2018
…et-on-ddl

This is a cherry-picked PR from 4.2 -> 4.2.0
dhensby added a commit to dhensby/silverstripe-framework that referenced this pull request Jul 23, 2018
…et-on-ddl

This is a cherry-picked PR from 4.2 -> 4.2.0
@maxime-rainville
Copy link
Contributor

@dhensby Probably.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants