1

I am trying to use pytest-xdist for running parallel tests. It works and I see improved performance.

To improve further more, I wanted to provide it multiple databases by using django_db_modify_db_settings_xdist_suffix

I override that functions in my conftest.py.

Since I have four workers, I created four databases manually. Then I use conftest to modify the settings.DATABASES to test for DBNAME against DBNAME_

I verified that my settings.DATABASES has changed and is correct.

But the queries are still going to old db DBNAME (which is no longer in my settings.DATABASES)

What could be going wrong?

Do I need to make any other change? Or change in conftest.py fixture is enough?

Thanks in advance for any help or direction.

EDIT: My conftest:py has lot of stuff. At the end of django_db_modify_db_settings_xdist_suffix if I log settings.DATABASES it shows me correct & expected info. But the queries still go to different db. conftest.py is same in both runs (pytest -n4 or pytest). Since it depends on xdist_suffix it modifies the settings.DATABASE value in "-n 4" run only. Two relevant functions which I think are important here:

@pytest.fixture(scope="session")
def django_db_setup(
    request,
    django_test_environment,
    django_db_blocker,
    django_db_use_migrations,
    django_db_keepdb,
    django_db_createdb,
    django_db_modify_db_settings,
):
    pass

And

@pytest.fixture(scope="session")
def django_db_modify_db_settings_xdist_suffix(request):
    
    from django.conf import settings

    default = settings.DATABASES["default"].copy()
    settings.DATABASES.clear()
    settings.DATABASES["default"] = default
    xdist_suffix = None
    xdist_worker_id = get_xdist_worker_id(request)
    if xdist_worker_id != 'master':
        xdist_suffix = xdist_worker_id
    if xdist_suffix:

        for db_settings in settings.DATABASES.values():
            test_name = db_settings.get("TEST", {}).get("NAME")

            if not test_name:
                test_name = "test_{}".format(db_settings["NAME"])

            db_settings.setdefault("TEST", {})
            db_settings["TEST"]["NAME"] = "{}_{}".format(test_name, xdist_suffix)
            db_settings["NAME"] = db_settings["TEST"]["NAME"]
lllrnr101
  • 2,288
  • 2
  • 4
  • 15

1 Answers1

0

I am doing something similar here to what you have done, but it may seem simpler or more elegant. To my mind, it seems that the context is more on the side of 'Django' than pytest-xdist.

I have used pytest-xdist to scale concurrent stress testing and the hook that seems most relevant for your question using gateway-id to send a setting to the remote worker which allowed distinction between nodes.

def pytest_configure_node(self, node: WorkerController) -> None:
    """set something peculiar for each node."""
    node.workerinput['SPECIAL'] = get_db_for_node(node.gateway.id)

Please try to implement the function as shown for get_db_for_node(gateway_id: str) -> str:

Then in the worker you could perhaps leverage config.workerinput to access the special mentioned above:

@pytest.fixture(scope="session")
def special(pytestconfig: Config) -> str:
    if not hasattr(pytestconfig, 'workerinput'):
        log.exception('fixture requires xdist')
        return ''
    return pytestconfig.workerinput['SPECIAL']
msudder
  • 505
  • 3
  • 14
  • following on from the first remark I made regarding the questions leaning toward Django, consider analyzing/modifying the ordering of the fixtures in your first fixture: django_db_setup. – msudder Jan 06 '22 at 20:19