Skip to content

Conversation

@khaeru
Copy link
Member

@khaeru khaeru commented Nov 19, 2025

#601 added code to the ixmp.testing.pytest_sessionstart() hook that connects to a PostgreSQL server for testing IXMP4Backend. The added code always runs, even if there is no PostgreSQL server available at the hard-coded URL.

This led to failures today in the scheduled message_ix, message-ix-models, and message_data workflows that use ixmp main:

INTERNALERROR> sqlalchemy.exc.OperationalError: (psycopg.OperationalError) connection failed: connection to server at "127.0.0.1", port 5432 failed: Connection refused
INTERNALERROR> 	Is the server running on that host and accepting TCP/IP connections?

To resolve:

  • Wrap the connection step in a try:/except: block.
  • Add a --ixmp-postgres pytest command-line option to control the connection parameters, in case downstream test suites wish to use different configuration.

Also:

  • Don't parametrize tests for IXMP4Backend if no server is available.
  • Show a message after collection.
  • Per the SQLAlchemy docs, psycopg2 is the default engine for PostgreSQL. Use URLs starting with postgresql:// instead of postgresql+psycopg2:// where possible.

How to review

  • Read the diff.
  • Note that the CI checks all pass.
  • Run a test suite that uses ixmp.testing as a plugin, e.g. the message-ix test suite.

PR checklist

  • Continuous integration checks all ✅
  • Add or expand tests; coverage checks both ✅
  • Add, expand, or update documentation. Test changes only.
  • Update release notes.

@khaeru khaeru self-assigned this Nov 19, 2025
@khaeru khaeru added bug enh New features & functionality ci Continuous integration backend.ixmp4 Interaction with ixmp4 via IXMP4Backend labels Nov 19, 2025
@codecov
Copy link

codecov bot commented Nov 19, 2025

Codecov Report

❌ Patch coverage is 95.34884% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.3%. Comparing base (1bf6d34) to head (c92b9c7).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
ixmp/testing/__init__.py 93.5% 2 Missing ⚠️
Additional details and impacted files
@@          Coverage Diff          @@
##            main    #611   +/-   ##
=====================================
  Coverage   98.2%   98.3%           
=====================================
  Files         51      51           
  Lines       6557    6577   +20     
=====================================
+ Hits        6444    6466   +22     
+ Misses       113     111    -2     
Files with missing lines Coverage Δ
ixmp/_config.py 94.5% <ø> (ø)
ixmp/tests/test_tutorials.py 100.0% <100.0%> (ø)
ixmp/util/ixmp4.py 97.2% <100.0%> (+1.2%) ⬆️
ixmp/testing/__init__.py 94.1% <93.5%> (+1.1%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@khaeru khaeru force-pushed the fix/test-ixmp4-postgres branch 2 times, most recently from 9403171 to 27d4ba3 Compare November 19, 2025 10:16
- Protect database connection in pytest_session{start,finish} hooks in a
  try/except block.
- Don't parametrize the "backend" fixture for "ixmp4" if no database
  server is available.
- Add pytest_report_collectionfinish() hook to display message if
  connection fails.
- Drop any existing "ixmp_test_..." database when connecting.
- Add .util.ixmp4.format_url() to adjust URLs to those supported by
  ixmp4.
@khaeru khaeru force-pushed the fix/test-ixmp4-postgres branch from 27d4ba3 to 529430c Compare November 19, 2025 10:37
khaeru added a commit that referenced this pull request Nov 19, 2025
- This ensures the tests in test_tutorials will connect to the database
  server and specific database established for the pytest-xdist worker
  by pytest_sessionstart().
- Drop "pytest" workflow step to manually establish "template1" and
  "ixmp_test" databases.
Don't include the "ixmp_test" value used in the test suite as part of
the default configuration for users.
@khaeru khaeru force-pushed the fix/test-ixmp4-postgres branch from c2510e6 to c92b9c7 Compare November 19, 2025 11:04
@khaeru khaeru marked this pull request as ready for review November 19, 2025 11:57
@khaeru
Copy link
Member Author

khaeru commented Nov 19, 2025

The codecov/patch check failure leads me to see (here) that the pytest_sessionstart() hook is not run.

I'm not sure why this is, but in order to fix CI for other repos, will merge. We should investigate this later.

@khaeru khaeru merged commit dacb3c5 into main Nov 19, 2025
20 of 21 checks passed
@khaeru khaeru deleted the fix/test-ixmp4-postgres branch November 19, 2025 11:59
Copy link
Member

@glatterf42 glatterf42 left a comment

Choose a reason for hiding this comment

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

Thanks for these fixes and sorry that I didn't test message_ix against this branch (or note this requirement as a todo before merging).

_backend._backend.teardown()
if is_sqlalchemybackend(_backend._backend):
_backend._backend.close()
# TODO Properly isinstance check and remove when Python 3.9 is dropped
Copy link
Member

Choose a reason for hiding this comment

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

I guess this line could have been removed now thanks to the new typeguard :)

Comment on lines -122 to -127
- name: Setup template & default-ixmp4-local Postgres schema
if: matrix.python-version != '3.9'
run: |
ixmp4 platforms add --dsn "postgresql+psycopg://postgres:postgres@localhost:5432/template1" template1
ixmp4 platforms add --dsn "postgresql+psycopg://postgres:postgres@localhost:5432/ixmp_test" ixmp_test
IXMP4_MANAGED=false ixmp4 platforms upgrade
Copy link
Member

Choose a reason for hiding this comment

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

I'm a bit confused about how we ensure the testing DB is running the latest state of the migrations, I thought setup() alone was not enough for that. But the passing tests indicate it works :)

Copy link
Member Author

Choose a reason for hiding this comment

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

I looked for documentation for setup(), but it seems there isn't any. As far as I can guess, the setup() of a new backend sets it up using the schema corresponding to the ixmp4 version in use.

If the underlying database schema changes between ixmp4 versions, and the user accesses the same database with first one ixmp4 version and then a different version, then that package should do things like:

  • apply migrations (from older to newer schemas, maybe in some configurable way), or
  • raise appropriate exceptions (e.g. if it's not possible to go backwards from newer to older schemas)

The Java ixmp_source code does this. If the ixmp4 package itself doesn't do that yet, we can just advertise that as a limitation on using ixmp/message_ix with IXMP4Backend, for the time being. If it won't ever do that (considered out of scope), then it should be handled by IXMP4Backend itself, automatically and transparency, and shouldn't require any extra steps.

session.config.stash[KEY_ENGINE] = engine
try:
with engine.connect() as connection:
connection.execute(text(f"DROP DATABASE IF EXISTS {db_name}"))
Copy link
Member

Choose a reason for hiding this comment

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

One more thing I just thought of here: we should make sure that no one accidentally runs the tests with WRITE permissions on a production DB to avoid deleting the whole DB. Though I'm not sure how we guard against that. Maybe once we have a URL for that, we can hardcode a check that this is not the DB we're about to drop?

Copy link
Member Author

Choose a reason for hiding this comment

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

once we have a URL for that, we can hardcode a check that this is not the DB we're about to drop?

Yes, that sounds like a great safeguard. IOW before pytestconfig.options.ixmp_postgres is used, we can compare it to some fixed list and abort if it matches.

I think the production DBs should also be configured such that no users or very limited (admin) users have permission to use the SQL DROP DATABASE; and then tightly limit who can connect and authenticate as those users. That way, anyone (person or CI worker) trying to run the test suite will not have the right credentials/permissions, and this would fail even if they managed to connect.

Finally, we could also:

  • Avoid using the name ixmp_test_.* for any production database. The code will only construct such names.
  • Maybe change the constructed name to something like __ixmp_test, with the prefix underscore(s) indicating a non-production/special case.

That would be at least four kinds of protection.

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

Labels

backend.ixmp4 Interaction with ixmp4 via IXMP4Backend bug ci Continuous integration enh New features & functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants