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

Make Postgres provider test idempotent #45418

Merged
merged 11 commits into from
Oct 13, 2021

Conversation

strk
Copy link
Contributor

@strk strk commented Oct 5, 2021

See #45417

TODO:

  • testGeneratedFields
  • testNonPkBigintField
  • testPktComposite
  • testPktCompositeFloat
  • testPktFloatingPoint
  • testPktUpdateBigintPk
  • testPktUpdateBigintPkNonFirst
  • testJson
  • testNestedInsert

@strk strk self-assigned this Oct 5, 2021
@github-actions github-actions bot added this to the 3.22.0 milestone Oct 5, 2021
@strk strk changed the title idempotent postgresprovider test Make Postgres provider test idempotent Oct 5, 2021
@strk strk changed the title Make Postgres provider test idempotent WIP: Make Postgres provider test idempotent Oct 5, 2021
@strk strk marked this pull request as draft October 5, 2021 20:40
@strk strk force-pushed the 45417-idempotent-postgresprovider-test branch from 36d65ab to bc63748 Compare October 5, 2021 20:42
@strk
Copy link
Contributor Author

strk commented Oct 5, 2021

Interestingly, it takes 4 runs of TestPyQgsPostgresProvider.testNonPkBigintField to get a failure:

======================================================================
FAIL: testNonPkBigintField (__main__.TestPyQgsPostgresProvider)
Test if we can correctly insert, read and change attributes(fields) of type bigint and which are not PKs.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/src/python/test_provider_postgres.py", line 652, in testNonPkBigintField
    self.assertEqual(f.attributes()[bigint_with_default_idx], 42)
AssertionError: 43 != 42

----------------------------------------------------------------------

@strk strk force-pushed the 45417-idempotent-postgresprovider-test branch from 3cf0008 to 884e3ce Compare October 5, 2021 20:58
@strk strk added PostGIS data provider testsuite Issue related to testsuite labels Oct 5, 2021
@strk
Copy link
Contributor Author

strk commented Oct 5, 2021

The TestPyQgsPostgresProvider.testPktUpdateBigintPkNonFirst test for me fails on first run so I cannot confirm there's an idempotency problem there:

======================================================================
FAIL: testPktUpdateBigintPkNonFirst (__main__.TestPyQgsPostgresProvider)
Test if we can update objects with positive, zero and negative bigint PKs in tables whose PK is not the first field
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/src/python/test_provider_postgres.py", line 803, in testPktUpdateBigintPkNonFirst
    self.assertTrue(all(x == 0 for x in statuses))
AssertionError: False is not true

I'll file a separate ticket for that one, tomorrow

@strk strk requested a review from nyalldawson October 5, 2021 21:17
@strk strk linked an issue Oct 5, 2021 that may be closed by this pull request
@elpaso
Copy link
Contributor

elpaso commented Oct 6, 2021

I think that the best approach is to get rid of the external SQL file and drop/create/populate tables in each test like in

@strk
Copy link
Contributor Author

strk commented Oct 6, 2021

I think that the best approach is to get rid of the external SQL file and drop/create/populate tables in each test like in

I'd prefer actually reverting changes while still keeping an upfront load of things, or a bug in the creation of data tables would result in failing all tests. And also to reduce the cost of running multiple tests at once (some read-only test would not need to create again and again the same tables)

@strk
Copy link
Contributor Author

strk commented Oct 6, 2021

Interestingly, CI is getting my own failure: https://github.com/qgis/QGIS/pull/45418/checks?check_run_id=3808276429#step:13:834
but only after the commit changing testPktUpdateBigintPk, so it looks like testPktUpdateBigintPkNonFirst EXPECTS that testPktUpdateBigintPk runs first and leaves the database MODIFIED. This should be fixed too

@strk
Copy link
Contributor Author

strk commented Oct 7, 2021

Great: the testPktUpdateBigintPkNonFirst test was actually BOGUS in that it changed values in one table and checked if they were changed in ANOTHER table (typo).

@strk strk changed the title WIP: Make Postgres provider test idempotent Make Postgres provider test idempotent Oct 7, 2021
@strk strk requested a review from elpaso October 7, 2021 08:57
@strk strk force-pushed the 45417-idempotent-postgresprovider-test branch from 3d2f017 to aedc711 Compare October 7, 2021 09:26
@strk
Copy link
Contributor Author

strk commented Oct 7, 2021

Ok CI is now happy, but locally I still have failures on SECOND run in testOrderBy and testOrderByCompiled, as if some of the tests run after those, somehow change the data for next invocation of those tests. I'm trying to figure how which tests do that.

@strk
Copy link
Contributor Author

strk commented Oct 7, 2021

It's actually the 3rd run which fails and I suspect it has to do with sequences not being reset, as the failure on 3rd run is an additional row with identifier 6:

AssertionError: Lists differ: [6, 5, 4, 3, 2, 1] != [5, 4, 3, 2, 1]

And the 4th run fails with an additional row with identifier 8:

AssertionError: Lists differ: [8, 5, 4, 3, 2, 1] != [5, 4, 3, 2, 1]

@strk
Copy link
Contributor Author

strk commented Oct 7, 2021

The "someData_pk_seq" sequence starts as uncalled, with lastVal being 1, while the table contains values from 1 to 5.
This possibly explains why the second run still pass because there must be some test that is incrementing that sequence and things will only start failing once the lastVal reaches 5 ... (fails starting at 6 as shown above).

@strk
Copy link
Contributor Author

strk commented Oct 7, 2021

TestPyQgsPostgresProvider.testNestedInsert is responsible to increment that sequence (at least: one of the responsibles)

@strk strk force-pushed the 45417-idempotent-postgresprovider-test branch from f992a6a to aedc711 Compare October 7, 2021 18:02
@strk
Copy link
Contributor Author

strk commented Oct 7, 2021

The testNestedInsert not only increments that sequence, but is also BROKEN in that it never succeeds at adding the feature to the layer, due to the sequence returning already-used primary keys. This is probably worth another ticket. When fixing the sequence to make it succeed in adding a new feature, the test DEADLOCKS, which was supposedly waht the test was about (preventing the deadlock)

@strk
Copy link
Contributor Author

strk commented Oct 7, 2021

@m-kuhn I saw the test for deadlocks with transactions was yours (in 07fcf24)

You will notice that the addFeature() there fails (try asserting True there). Is that line meant to fail ? Beacuse when it succeeds (after properly initializing the sequence) I do get a deadlock...

@strk
Copy link
Contributor Author

strk commented Oct 7, 2021

It looks like adding a commitChanges (or rollback) fixes the deadlock. Pushed.

@strk
Copy link
Contributor Author

strk commented Oct 7, 2021

In it's current state, this PR gives me a fully idempotent TestPyQgsPostgresProvider run, fixing #45417

@strk strk marked this pull request as ready for review October 7, 2021 19:00
@m-kuhn
Copy link
Member

m-kuhn commented Oct 7, 2021

@m-kuhn I saw the test for deadlocks with transactions was yours (in 07fcf24)

You will notice that the addFeature() there fails (try asserting True there). Is that line meant to fail ? Beacuse when it succeeds (after properly initializing the sequence) I do get a deadlock...

I don't recall the details of it, looking in retrospective the interest was to get no deadlock. Regardless if the action itself fails or succeeds.

@strk strk requested a review from m-kuhn October 7, 2021 22:03
@strk strk force-pushed the 45417-idempotent-postgresprovider-test branch from 96902ad to 8dbc7d2 Compare October 9, 2021 12:46
@strk strk requested a review from timlinux October 12, 2021 14:03
Comment on lines +108 to +123
def scopedTableBackup(self, schema, table):

class ScopedBackup():
def __init__(self, tester, schema, table):
self.schema = schema
self.table = table
self.tester = tester
tester.execSQLCommand('DROP TABLE IF EXISTS {s}.{t}_edit CASCADE'.format(s=schema, t=table))
tester.execSQLCommand('CREATE TABLE {s}.{t}_edit AS SELECT * FROM {s}.{t}'.format(s=schema, t=table))

def __del__(self):
self.tester.execSQLCommand('TRUNCATE TABLE {s}.{t}'.format(s=self.schema, t=self.table))
self.tester.execSQLCommand('INSERT INTO {s}.{t} SELECT * FROM {s}.{t}_edit'.format(s=self.schema, t=self.table))
self.tester.execSQLCommand('DROP TABLE {s}.{t}_edit'.format(s=self.schema, t=self.table))

return ScopedBackup(self, schema, table)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I like this approach! I can't help but feel like it's only a few tweaks away from being a real context manager though. E.g. it would be cleaner/more pythonic to be able to directly call:

    def my_test(self):
        # ...
        with self.backup_table('schema','my_table'):
            # some sql

        # ...

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 thought about that but then some tests use more than a single table, so the with would need multiple tables to be backed up

Copy link
Collaborator

Choose a reason for hiding this comment

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

potentially we could nest the contexts... it's not super nice though: 😛

    with self.backup_table('....'):
          with self.backup_table('....'):
               ....

Copy link
Member

Choose a reason for hiding this comment

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

Or provide a list of tables?

@strk strk merged commit 51d728b into qgis:master Oct 13, 2021
@strk strk deleted the 45417-idempotent-postgresprovider-test branch October 13, 2021 22:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PostGIS data provider testsuite Issue related to testsuite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TestPyQgsPostgresProvider is not idempotent
4 participants