tk0miya / testing.postgresql

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Issue closing down instance on Windows

adelosa opened this issue · comments

I'm working with Python 3.5.2 on WIndows 10.
Code like the following:

if __name__ == '__main__':
    with testing.postgresql.Postgresql() as postgresql:
        print("url={}".format(postgresql.url()))
        print("data directory={}".format(postgresql.get_data_directory()))
        run(postgresql.url())

run does nothing..

Receiving the following error:

Traceback (most recent call last):
  File "C:/Users/adelo/IdeaProjects/pr_data/test_orm.py", line 66, in <module>
    run(postgresql.url())
  File "C:\Users\adelo\venv\paymentrouter\lib\site-packages\testing\common\database.py", line 257, in __exit__
url=postgresql://postgres@127.0.0.1:57380/test
data directory=C:\Users\adelo\AppData\Local\Temp\tmpbnndk7ie\data
    self.stop()
  File "C:\Users\adelo\venv\paymentrouter\lib\site-packages\testing\common\database.py", line 197, in stop
    self.terminate(_signal)
  File "C:\Users\adelo\venv\paymentrouter\lib\site-packages\testing\postgresql.py", line 116, in terminate
    super(Postgresql, self).terminate(signal.SIGINT)
  File "C:\Users\adelo\venv\paymentrouter\lib\site-packages\testing\common\database.py", line 212, in terminate
    self.child_process.send_signal(_signal)
  File "c:\users\adelo\appdata\local\programs\python\python35-32\Lib\subprocess.py", line 1351, in send_signal
    raise ValueError("Unsupported signal: {}".format(sig))
ValueError: Unsupported signal: 2
ERROR: testing.common.database: failed to shutdown the server automatically.
Any server processes and files might have been leaked. Please remove them and call the stop() certainly
Process finished with exit code 1

So its saying that signal.SIGINT is not supported.. is that a Windows thing??

Hi, I'm unable to get this to work still with the latest testing.postgresql build. Getting unsupported signal 2 still, is this fixed?

I'm still getting this error on Windows with version 1.3.0. Any ideas?

Using the master branch fixes the issue for me. 👍

Yes, master branch works for me as well! Would be great if the pypi version could be updated to include the windows-fix!

Is there any danger in killing the process manually on windows instead of using postgresql.stop()? I rather use the pypi version if possible.

if platform.system() == 'Windows':
  os.system("taskkill /f /pid " + str(postgresql.server_pid))
else:
  postgresql.stop()

To chime in as well, I had the same issue as above and cloning from the master branch in the repo via pip install git+https://github.com/tk0miya/testing.postgresql.git also fixed it for me.

Would be nice to get this fix into the PyPI version!

EDIT - add the -e flag and subsequent pip freeze > requirements.txt to update your virtualenv appropriately (if you are using one; you should be!).

The full command is
pip install -e git+https://github.com/tk0miya/testing.postgresql.git#egg=testing.postgresql

@tk0miya How can we get this fix into PyPi?

Just FYI, I have long since given up on this module. I was happy to remove this as it was adding a lot of overhead (read time) to my tests, especially on Windows.
I just created my own testcase subclass that creates and destroys the database schema for each test.
It assumes an empty database and specific connection string for the purpose of testing. To me, this is not a massive impact for the speed increases. It also has the benefit of allowing me to dynamically change the database type based on an envvar.. I can now run the same tests against different database types with no code changes.
See https://gist.github.com/adelosa/a2293f2130ceb00a12d17a9c08114c0f if your are interested in the approach. Have posted by testcase subclass. Any questions, comment on the gist.

What's going on is that the process termination signal being used to call stop() is always 2. Yes, the top level api function allows you to specify the signal int value, but this is ignored in the call chain deep down. In Windows you always get int val 2, no matter what you pass in.

The hack-workaround is to monkey patch signal.SIGINT = signal.SIGTERM for the scope of stop. This is only necessary in windows. Then to clean up you restore the signal.SIGINT back to what it was. This is my fix that's being used for a production app:

db_test_env.py

# pylint: disable=global-statement

import atexit
import os
import platform
import signal
from threading import Lock

import testing.postgresql

_IS_WINDOWS = platform.system() == "Windows"
_INITIALIZED = False
_LOCK = Lock()


def _db_test_env_teardown(postgresql: testing.postgresql.Postgresql) -> None:
    """Clears test database."""
    global _INITIALIZED
    with _LOCK:
        assert _INITIALIZED
        prev_sig_int = signal.SIGINT
        try:
            if _IS_WINDOWS:
                # Hack for windows. Int signal is always 2 deep down in the
                # call chain. So we monkey patch the SIGINT to SIGTERM for the
                # duration of the call.
                signal.SIGINT = signal.SIGTERM
            postgresql.stop()
            _INITIALIZED = False
        finally:
            if _IS_WINDOWS:
                signal.SIGINT = prev_sig_int


def db_test_env_init(strict: bool = False) -> str:
    """Initializes test database."""
    global _INITIALIZED
    with _LOCK:
        if _INITIALIZED:
            if strict:
                raise RuntimeError("Test database already initialized")
            return os.environ["DB_URL"] or ""
        postgresql = testing.postgresql.Postgresql()
        url = postgresql.url()
        os.environ["DB_URL"] = url
        _INITIALIZED = True
        atexit.register(_db_test_env_teardown, postgresql)
        return url