diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 0db2e0b..19a76dc 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,20 +1,20 @@ [bumpversion] -current_version = 1.4.1 +current_version = 2.0.0 commit = True tag = True message = "Release {new_version}" [bumpversion:file:setup.py] search = version='{current_version}' replace = version='{new_version}' [bumpversion:file:src/pytest_postgresql/__init__.py] [bumpversion:file:README.rst] [bumpversion:file:CHANGES.rst] search = unreleased ------- replace = {new_version} ------- diff --git a/.dependabot/config.yml b/.dependabot/config.yml new file mode 100644 index 0000000..c77885a --- /dev/null +++ b/.dependabot/config.yml @@ -0,0 +1,8 @@ +version: 1 +update_configs: + - package_manager: "python" + directory: "/" + update_schedule: "daily" + automerged_updates: + - match: + dependency_name: "*" \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 0c5f18c..a4b826c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,50 +1,48 @@ dist: xenial language: python python: -- 2.7 - 3.5 - 3.6 - 3.7 -- pypy2.7-6.0 -- pypy3.5 +- pypy3 # blocklist branches branches: except: - requires-io-master install: - pip install -r requirements-test.txt - pip install -e .[tests] coveralls wheel script: - py.test -n 0 --cov src/pytest_postgresql after_success: - coveralls jobs: include: - stage: xdist python: 3.7 script: py.test -n 1 --cov src/pytest_postgresql tests - stage: linters python: 3.7 install: - pip install -r requirements-lint.txt - pip install .[tests] psycopg2-binary script: - pycodestyle - pydocstyle - pylint pytest_postgresql tests - pyroma . after_success: skip - stage: deploy python: 3.7 if: tag IS present script: skip deploy: provider: pypi user: thearoom password: secure: FAN5dMk+ktvFdfZX6OjKy9+XWwbTrJcZ4OrV6LVKNyZdsVRi0+iE6opSQXH8HjO6DCXsyHkZDD8a6f81y/Cc3j6QsRItnJwjQllu4dNce5LYHZNA/sQ9O8mgC9+DrPWzPYRlMkSgG9eVH3tI8UX1P7Wh4yuJLbQbNkWw8ZX7j+HSwZtYLPhP2uBp7xMF5rYO+9PcIA/I0QI0AkfRQtYtwSp3QAjKUVWnWXnUQOILey5wP+3ENYVojKmYSocmOtbKUUNfExgZIep8gsZXx60fuBQLRSG0XhDxud51nGKvzNegqQoN5Mpt61VslT7trS/D6zOzMCUTqNwbg/gMrebU5IMZm5ijJSKkvw5Cl30Yc5+cZ0o7N9NbepBjlEX3ByDUnDk7bfSRHukJw9lG5+mBHLi+aJ9+ZPEqUcIHuYzv6+yvjlGPkETqlxkCunU6HzwrsD5QdYwqcY4PLHf7Onx3I2Vjg4XxZO27BDbhvpOTF4SaAk45ALi9y10Gu7FSswp44/l5k54Ur1/JPhSmFGIO8XZJZ7mLGftextYLEmQuai7IKmu46rZ3ffzEpIk0lP5xi2NWyQvD9DHEJSMKxc4koVKb72lLbl69aVp+6vKRH4VtJ1E5/Hybrxe9bbz+upQ4xRdXjRAml4xAnGeBcH5hf2owbijYuoU26qOHKl68Ej0= on: tags: true all_branches: true repo: ClearcodeHQ/pytest-postgresql distributions: bdist_wheel diff --git a/AUTHORS.rst b/AUTHORS.rst index 42fdbb4..07455aa 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -1,18 +1,19 @@ Authors ======= This file contains the list of people involved in the development of pytest-postgresql along its history. * Grzegorz Śliwiński * Jonas Brunsgaard * Tomasz Karbownicki * Domen Kožar * Przemysław Spodymek * Michał Masłowski * Karolina Blümke * Paweł Wilczyński * Georg Walther * François Scala * Donald Stufft * Will Vaughn +* Hugo (hugovk) diff --git a/CHANGES.rst b/CHANGES.rst index eaac360..7476eed 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,77 +1,87 @@ CHANGELOG ========= +2.0.0 +------- + +- [feature] Drop support for python 2.7. From now on, only support python 3.5 and up +- [feature] Ability to configure database name through plugin options +- [enhancement] Use tmpdir_factory. Drop ``logsdir`` parameter +- [ehnancement] Support only Postgresql 9.0 and up +- [bugfix] Always start postgresql with LC_ALL, LC_TYPE and LANG set to C.UTF-8. + It makes postgresql start in english. + 1.4.1 ------- - [bugfix] Allow creating test databse with hyphens 1.4.0 ------- - [enhancements] Ability to configure additional options for postgresql process and connection - [bugfix] - removed hard dependency on ``psycopg2``, allowing any of its alternative packages, like ``psycopg2-binary``, to be used. - [maintenance] Drop support for python 3.4 and use 3.7 instead 1.3.4 ------- - [bugfix] properly detect if executor running and clean after executor is being stopped .. note:: Previously if a test failed, there was a possibility of the executor being removed when python was closing, causing it to print ignored errors on already unloaded modules. 1.3.3 ------- - [enhancement] use executor's context manager to start/stop postrgesql server in a fixture 1.3.2 ------- - [bugfix] version regexp to correctly catch postgresql 10 1.3.1 ------- - [enhancement] explicitly turn off logging_collector 1.3.0 ------- - [feature] pypy compatibility 1.2.0 ------- - [bugfix] - disallow connection to database before it gets dropped. .. note:: Otherwise it caused random test subprocess to connect again and this the drop was unsucessfull which resulted in many more test failes on setup. - [cleanup] - removed path.py dependency 1.1.1 ------- - [bugfix] - Fixing the default pg_ctl path creation 1.1.0 ------- - [feature] - migrate usage of getfuncargvalue to getfixturevalue. require at least pytest 3.0.0 1.0.0 ------- - create command line and pytest.ini configuration options for postgresql starting parameters - create command line and pytest.ini configuration options for postgresql username - make the port random by default - create command line and pytest.ini configuration options for executable - create command line and pytest.ini configuration options for host - create command line and pytest.ini configuration options for port - Extracted code from pytest-dbfixtures diff --git a/README.rst b/README.rst index 8dc7836..e087ca9 100644 --- a/README.rst +++ b/README.rst @@ -1,138 +1,170 @@ pytest-postgresql ================= .. image:: https://img.shields.io/pypi/v/pytest-postgresql.svg :target: https://pypi.python.org/pypi/pytest-postgresql/ :alt: Latest PyPI version .. image:: https://img.shields.io/pypi/wheel/pytest-postgresql.svg :target: https://pypi.python.org/pypi/pytest-postgresql/ :alt: Wheel Status .. image:: https://img.shields.io/pypi/pyversions/pytest-postgresql.svg :target: https://pypi.python.org/pypi/pytest-postgresql/ :alt: Supported Python Versions .. image:: https://img.shields.io/pypi/l/pytest-postgresql.svg :target: https://pypi.python.org/pypi/pytest-postgresql/ :alt: License Package status -------------- -.. image:: https://travis-ci.org/ClearcodeHQ/pytest-postgresql.svg?branch=v1.4.1 +.. image:: https://travis-ci.org/ClearcodeHQ/pytest-postgresql.svg?branch=v2.0.0 :target: https://travis-ci.org/ClearcodeHQ/pytest-postgresql :alt: Tests -.. image:: https://coveralls.io/repos/ClearcodeHQ/pytest-postgresql/badge.png?branch=v1.4.1 - :target: https://coveralls.io/r/ClearcodeHQ/pytest-postgresql?branch=v1.4.1 +.. image:: https://coveralls.io/repos/ClearcodeHQ/pytest-postgresql/badge.png?branch=v2.0.0 + :target: https://coveralls.io/r/ClearcodeHQ/pytest-postgresql?branch=v2.0.0 :alt: Coverage Status -.. image:: https://requires.io/github/ClearcodeHQ/pytest-postgresql/requirements.svg?tag=v1.4.1 - :target: https://requires.io/github/ClearcodeHQ/pytest-postgresql/requirements/?tag=v1.4.1 +.. image:: https://requires.io/github/ClearcodeHQ/pytest-postgresql/requirements.svg?tag=v2.0.0 + :target: https://requires.io/github/ClearcodeHQ/pytest-postgresql/requirements/?tag=v2.0.0 :alt: Requirements Status What is this? ============= This is a pytest plugin, that enables you to test your code that relies on a running PostgreSQL Database. It allows you to specify fixtures for PostgreSQL process and client. How to use ========== .. warning:: Tested on PostgreSQL versions > 9.x. See tests for more details. Install with: .. code-block:: sh pip install pytest-postgresql You will also need to install ``psycopg2``, or one of its alternative packagings such as ``psycopg2-binary`` (pre-compiled wheels) or ``psycopg2cffi`` (CFFI based, useful on PyPy). Plugin contains two fixtures: * **postgresql** - it's a client fixture that has functional scope. After each test it ends all leftover connections, and drops test database from PostgreSQL ensuring repeatability. * **postgresql_proc** - session scoped fixture, that starts PostgreSQL instance at it's first use and stops at the end of the tests. Simply include one of these fixtures into your tests fixture list. You can also create additional postgresql client and process fixtures if you'd need to: .. code-block:: python from pytest_postgresql import factories postgresql_my_proc = factories.postgresql_proc( - port=None, logsdir='/tmp') + port=None, unixsocketdir='/var/run') postgresql_my = factories.postgresql('postgresql_my_proc') .. note:: Each PostgreSQL process fixture can be configured in a different way than the others through the fixture factory arguments. Configuration ============= You can define your settings in three ways, it's fixture factory argument, command line option and pytest.ini configuration option. You can pick which you prefer, but remember that these settings are handled in the following order: * ``Fixture factory argument`` * ``Command line option`` * ``Configuration option in your pytest.ini file`` -+--------------------------+--------------------------+----------------------------+--------------------------+------------------------------------+ -| PostgreSQL option | Fixture factory argument | Command line option | pytest.ini option | Default | -+==========================+==========================+============================+==========================+====================================+ -| Path to executable | executable | --postgresql-exec | postgresql_exec | /usr/lib/postgresql/9.1/bin/pg_ctl | -+--------------------------+--------------------------+----------------------------+--------------------------+------------------------------------+ -| host | host | --postgresql-host | postgresql_host | 127.0.0.1 | -+--------------------------+--------------------------+----------------------------+--------------------------+------------------------------------+ -| port | port | --postgresql-port | postgresql_port | random | -+--------------------------+--------------------------+----------------------------+--------------------------+------------------------------------+ -| postgresql user | user | --postgresql-user | postgresql_user | postgres | -+--------------------------+--------------------------+----------------------------+--------------------------+------------------------------------+ -| Starting parameters | startparams | --postgresql-startparams | postgresql_startparams | -w | -+--------------------------+--------------------------+----------------------------+--------------------------+------------------------------------+ -| Log directory location | logsdir | --postgresql-logsdir | postgresql_logsdir | $TMPDIR | -+--------------------------+--------------------------+----------------------------+--------------------------+------------------------------------+ -| Log filename's prefix | logsprefix | --postgresql-logsprefix | postgresql_logsprefix | | -+--------------------------+--------------------------+----------------------------+--------------------------+------------------------------------+ -| Location for unixsockets | unixsocket | --postgresql-unixsocketdir | postgresql_unixsocketdir | $TMPDIR | -+--------------------------+--------------------------+----------------------------+--------------------------+------------------------------------+ + +.. list-table:: Configuration options + :header-rows: 1 + + * - PostgreSQL option + - Fixture factory argument + - Command line option + - pytest.ini option + - Default + * - Path to executable + - executable + - --postgresql-exec + - postgresql_exec + - /usr/lib/postgresql/9.1/bin/pg_ctl + * - host + - host + - --postgresql-host + - postgresql_host + - 127.0.0.1 + * - port + - port + - --postgresql-port + - postgresql_port + - random + * - postgresql user + - user + - --postgresql-user + - postgresql_user + - postgres + * - Starting parameters + - startparams + - --postgresql-startparams + - postgresql_startparams + - -w + * - Log filename's prefix + - logsprefix + - --postgresql-logsprefix + - postgresql_logsprefix + - + * - Location for unixsockets + - unixsocket + - --postgresql-unixsocketdir + - postgresql_unixsocketdir + - $TMPDIR + * - Database name + - db_name + - --postgresql-dbname + - postgresql_dbname + - test + + Example usage: * pass it as an argument in your own fixture .. code-block:: python postgresql_proc = factories.postgresql_proc( port=8888) * use ``--postgresql-port`` command line option when you run your tests .. code-block:: py.test tests --postgresql-port=8888 * specify your port as ``postgresql_port`` in your ``pytest.ini`` file. To do so, put a line like the following under the ``[pytest]`` section of your ``pytest.ini``: .. code-block:: ini [pytest] postgresql_port = 8888 Package resources ----------------- * Bug tracker: https://github.com/ClearcodeHQ/pytest-postgresql/issues diff --git a/docs/source/conf.py b/docs/source/conf.py index 18ed60a..28a13fd 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,312 +1,312 @@ # -*- coding: utf-8 -*- # Copyright (C) 2016 by Clearcode # and associates (see AUTHORS). # This file is part of pytest-postgresql. # pytest-postgresql is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # pytest-postgresql is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public License # along with pytest-postgresql. If not, see . # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. -project = u'pytest-postgresql' +project = 'pytest-postgresql' basename = ''.join(project.split('.')) -author = u'Clearcode - The A Room' -copyright = u'2016, ' + author +author = 'Clearcode - The A Room' +copyright = '2016, ' + author # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. from pypt import __version__ # The full version, including alpha/beta/rc tags. release = __version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = basename + 'doc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', basename + '.tex', project + ' Documentation', author, 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', basename, project + u' Documentation', + ('index', basename, project + ' Documentation', [author], 1) ] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', basename, project + u' Documentation', + ('index', basename, project + ' Documentation', author, basename, 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project epub_author = author epub_publisher = author -epub_copyright = u'2016, ' + author +epub_copyright = '2016, ' + author # The language of the text. It defaults to the language option # or en if the language is not set. # epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. # epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. # epub_identifier = '' # A unique identification for the text. # epub_uid = '' # A tuple containing the cover image and cover page html template filenames. # epub_cover = () # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. # epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. # epub_post_files = [] # A list of files that should not be packed into the epub file. # epub_exclude_files = [] # The depth of the table of contents in toc.ncx. # epub_tocdepth = 3 # Allow duplicate toc entries. # epub_tocdup = True # Autodoc configuration: autoclass_content = 'both' autodoc_default_flags = ['members', 'show-inheritance'] # Intersphinx configuration intersphinx_mapping = {'python': ('http://docs.python.org/', None)} diff --git a/requirements-lint.txt b/requirements-lint.txt index aba7974..f997e17 100644 --- a/requirements-lint.txt +++ b/requirements-lint.txt @@ -1,6 +1,6 @@ # linters pycodestyle==2.5.0 -pydocstyle==3.0.0 -pylint==2.3.1; python_version>'3.3' +pydocstyle==4.0.0 +pylint==2.3.1 pygments -pyroma==2.4 +pyroma==2.5 diff --git a/requirements-test.txt b/requirements-test.txt index 3c6db37..b77975c 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,9 +1,9 @@ # test runs requirements (versions we'll be testing against) - automatically updated by requires.io pip>=9 # minimum installation requirements setuptools>=21 # minimum installation requirements -coverage==4.5.3 # pytest-cov -pytest==4.4.1 -psycopg2-binary==2.8.2; platform_python_implementation != "PyPy" +coverage==4.5.4 # pytest-cov +pytest==5.0.1 +psycopg2-binary==2.8.3; platform_python_implementation != "PyPy" psycopg2cffi==2.8.1; platform_python_implementation == "PyPy" port-for==0.4 -mirakuru==1.1.0 +mirakuru==2.0.1 diff --git a/setup.cfg b/setup.cfg index 0b2cc00..b72fc5f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,10 +1,7 @@ -[wheel] -universal = 1 - [pycodestyle] max-line-length = 80 exclude = docs/*,build/*,venv/* [pydocstyle] ignore = D203,D212 match = '(?!docs|build|venv).*\.py' \ No newline at end of file diff --git a/setup.py b/setup.py index f5c86da..1b4ffea 100644 --- a/setup.py +++ b/setup.py @@ -1,102 +1,102 @@ # -*- coding: utf-8 -*- # Copyright (C) 2016 by Clearcode # and associates (see AUTHORS). # This file is part of pytest-postgresql. # pytest-postgresql is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # pytest-postgresql is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public License # along with pytest-postgresql. If not, see . """pytest-postgresql setup.py module.""" import os from setuptools import setup, find_packages here = os.path.dirname(__file__) def read(fname): """ Read given file's content. :param str fname: file name :returns: file contents :rtype: str """ return open(os.path.join(here, fname)).read() requirements = [ 'pytest>=3.0.0', 'port-for', - 'mirakuru' + 'mirakuru>=2.0.0' ] test_requires = [ - 'pytest-cov==2.6.1', - 'pytest-xdist==1.28.0', + 'pytest-cov==2.7.1', + 'pytest-xdist==1.29.0', ] extras_require = { 'docs': ['sphinx'], 'tests': test_requires, } setup_requires = [ 'setuptools>=21', 'pip>=9' ] setup( name='pytest-postgresql', - version='1.4.1', + version='2.0.0', description='Postgresql fixtures and fixture factories for Pytest.', long_description=( read('README.rst') + '\n\n' + read('CHANGES.rst') ), keywords='tests py.test pytest fixture postgresql', author='Clearcode - The A Room', author_email='thearoom@clearcode.cc', url='https://github.com/ClearcodeHQ/pytest-postgresql', license='LGPLv3+', + python_requires='>=3.5', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: ' 'GNU Lesser General Public License v3 or later (LGPLv3+)', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3 :: Only', 'Topic :: Software Development :: Libraries :: Python Modules', ], package_dir={'': 'src'}, packages=find_packages('src'), install_requires=requirements, tests_require=test_requires, setup_requires=setup_requires, test_suite='tests', entry_points={ 'pytest11': [ 'pytest_postgresql = pytest_postgresql.plugin' ]}, include_package_data=True, zip_safe=False, extras_require=extras_require, ) diff --git a/src/pytest_postgresql/__init__.py b/src/pytest_postgresql/__init__.py index 4e72ad2..8870fb1 100644 --- a/src/pytest_postgresql/__init__.py +++ b/src/pytest_postgresql/__init__.py @@ -1,27 +1,27 @@ # -*- coding: utf-8 -*- # Copyright (C) 2016 by Clearcode # and associates (see AUTHORS). # This file is part of pytest-postgresql. # pytest-postgresql is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # pytest-postgresql is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public License # along with pytest-postgresql. If not, see . """Main module for pytest-postgresql.""" try: import psycopg2cffi.compat # pylint:disable=import-error except ImportError: pass else: psycopg2cffi.compat.register() -__version__ = '1.4.1' +__version__ = '2.0.0' diff --git a/src/pytest_postgresql/executor.py b/src/pytest_postgresql/executor.py index c12c71c..ce962b9 100644 --- a/src/pytest_postgresql/executor.py +++ b/src/pytest_postgresql/executor.py @@ -1,126 +1,214 @@ # Copyright (C) 2013 by Clearcode # and associates (see AUTHORS). # This file is part of pytest-dbfixtures. # pytest-dbfixtures is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # pytest-dbfixtures is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public License # along with pytest-dbfixtures. If not, see . """PostgreSQL executor crafter around pg_ctl.""" import os.path import re +import shutil import subprocess +import time +from pkg_resources import parse_version from mirakuru import TCPExecutor +from mirakuru.base import ExecutorType +class PostgreSQLUnsupported(Exception): + """Exception raised when postgresql<9.0 would be detected.""" + + +# pylint:disable=too-many-instance-attributes class PostgreSQLExecutor(TCPExecutor): """ PostgreSQL executor running on pg_ctl. Based over an `pg_ctl program `_ """ BASE_PROC_START_COMMAND = ' '.join(( "{executable} start -D {datadir}", "-o \"-F -p {port} -c log_destination='stderr'", "-c logging_collector=off -c %s='{unixsocketdir}'\"", "-l {logfile} {startparams}" )) VERSION_RE = re.compile(r'.* (?P\d+\.\d)') + MIN_SUPPORTED_VERSION = parse_version('9.0') def __init__(self, executable, host, port, datadir, unixsocketdir, logfile, startparams, shell=False, timeout=60, sleep=0.1, user='postgres', options=''): """ Initialize PostgreSQLExecutor executor. :param str executable: pg_ctl location :param str host: host under which process is accessible :param int port: port under which process is accessible :param str datadir: path to postgresql datadir :param str unixsocketdir: path to socket directory - :param str logfile: path to logfile for postgresql + :param pathlib.Path logfile: path to logfile for postgresql :param str startparams: additional start parameters :param bool shell: see `subprocess.Popen` :param int timeout: time to wait for process to start or stop. if None, wait indefinitely. :param float sleep: how often to check for start/stop condition :param str user: [default] postgresql's username used to manage and access PostgreSQL """ + self._directory_initialised = False self.executable = executable self.user = user self.options = options self.datadir = datadir self.unixsocketdir = unixsocketdir + self.logfile = logfile + self.startparams = startparams command = self.proc_start_command().format( executable=self.executable, datadir=self.datadir, port=port, unixsocketdir=self.unixsocketdir, - logfile=logfile, - startparams=startparams, + logfile=self.logfile, + startparams=self.startparams, + ) + super().__init__( + command, + host, + port, + shell=shell, + timeout=timeout, + sleep=sleep, + envvars={ + 'LC_ALL': 'C.UTF-8', + 'LC_CTYPE': 'C.UTF-8', + 'LANG': 'C.UTF-8', + } + ) + + def start(self: ExecutorType) -> ExecutorType: + """Add check for postgresql version before starting process.""" + if self.version < self.MIN_SUPPORTED_VERSION: + raise PostgreSQLUnsupported( + 'Your version of PostgreSQL is not supported. ' + 'Consider updating to PostgreSQL {0} at least. ' + 'The currently installed version of PostgreSQL: {1}.' + .format(self.MIN_SUPPORTED_VERSION, self.version)) + self.init_directory() + return super().start() + + def clean_directory(self): + """Remove directory created for postgresql run.""" + if os.path.isdir(self.datadir): + shutil.rmtree(self.datadir) + self._directory_initialised = False + + def init_directory(self): + """ + Initialize postgresql data directory. + + See `Initialize postgresql data directory + `_ + """ + # only make sure it's removed if it's handled by this exact process + if self._directory_initialised: + return + # remove old one if exists first. + self.clean_directory() + init_directory = ( + self.executable, 'initdb', + '-o "--auth=trust --username=%s"' % self.user, + '-D %s' % self.datadir, ) - super(PostgreSQLExecutor, self).__init__( - command, host, port, shell=shell, timeout=timeout, sleep=sleep) + subprocess.check_output(' '.join(init_directory), shell=True) + self._directory_initialised = True + + def wait_for_postgres(self): + """Wait for postgresql being started.""" + if '-w' not in self.startparams: + return + # Cast to str since Python 3.5 however still needs string. + # Python 3.6 it's possible to pass a A Pathlike object. + logfile_path = str(self.logfile) + # wait until logfile is created + while not os.path.isfile(logfile_path): + time.sleep(1) + + start_info = 'database system is ready to accept connections' + # wait for expected message. + while 1: + with open(logfile_path, 'r') as content_file: + content = content_file.read() + if start_info in content: + break + time.sleep(1) def proc_start_command(self): """Based on postgres version return proper start command.""" - if float(self.version) > 9.2: + if self.version > parse_version('9.2'): unix_socket_dir_arg_name = 'unix_socket_directories' else: unix_socket_dir_arg_name = 'unix_socket_directory' return self.BASE_PROC_START_COMMAND % unix_socket_dir_arg_name @property def version(self): """Detect postgresql version.""" version_string = subprocess.check_output( [self.executable, '--version']).decode('utf-8') matches = self.VERSION_RE.search(version_string) - return matches.groupdict()['version'] + return parse_version(matches.groupdict()['version']) def running(self): """Check if server is still running.""" if not os.path.exists(self.datadir): return False try: output = subprocess.check_output( '{pg_ctl} status -D {datadir}'.format( pg_ctl=self.executable, datadir=self.datadir ), shell=True ).decode('utf-8') except subprocess.CalledProcessError as ex: if b'pg_ctl: no server running' in ex.output: return False raise return "pg_ctl: server is running" in output def stop(self, sig=None): """Issue a stop request to executable.""" subprocess.check_output( '{pg_ctl} stop -D {datadir} -m f'.format( pg_ctl=self.executable, datadir=self.datadir, ), shell=True) - super(PostgreSQLExecutor, self).stop(sig) + super().stop(sig) + + def __del__(self): + """Make sure the directories are properly removed at the end.""" + try: + super().__del__() + finally: + self.clean_directory() diff --git a/src/pytest_postgresql/factories.py b/src/pytest_postgresql/factories.py index ac390da..3dd0a3a 100644 --- a/src/pytest_postgresql/factories.py +++ b/src/pytest_postgresql/factories.py @@ -1,301 +1,238 @@ # Copyright (C) 2013-2016 by Clearcode # and associates (see AUTHORS). # This file is part of pytest-dbfixtures. # pytest-dbfixtures is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # pytest-dbfixtures is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public License # along with pytest-dbfixtures. If not, see . """Fixture factories for postgresql fixtures.""" import os.path -import time -import shutil import platform import subprocess from tempfile import gettempdir import pytest +from pkg_resources import parse_version + try: import psycopg2 except ImportError: psycopg2 = False from pytest_postgresql.executor import PostgreSQLExecutor from pytest_postgresql.port import get_port def get_config(request): """Return a dictionary with config options.""" config = {} options = [ - 'exec', 'host', 'port', 'user', 'options', 'startparams', 'logsdir', - 'logsprefix', 'unixsocketdir' + 'exec', 'host', 'port', 'user', 'options', 'startparams', + 'logsprefix', 'unixsocketdir', 'dbname' ] for option in options: option_name = 'postgresql_' + option conf = request.config.getoption(option_name) or \ request.config.getini(option_name) config[option] = conf return config -START_INFO = 'database system is ready to accept connections' - - -def wait_for_postgres(logfile, awaited_msg): - """ - Wait for postgresql being started. - - :param str logfile: logfile path - :param str awaited_msg: awaited message - """ - # wait until logfile is created - while not os.path.isfile(logfile): - time.sleep(1) - - # wait for expected message. - while 1: - with open(logfile, 'r') as content_file: - content = content_file.read() - if awaited_msg in content: - break - time.sleep(1) - - -def remove_postgresql_directory(datadir): - """ - Remove directory created for postgresql run. - - :param str datadir: datadir path - """ - if os.path.isdir(datadir): - shutil.rmtree(datadir) - - -def init_postgresql_directory(postgresql_ctl, user, datadir): - """ - Initialize postgresql data directory. - - See `Initialize postgresql data directory - `_ - - :param str postgresql_ctl: ctl path - :param str user: postgresql username - :param str datadir: datadir path - - """ - # remove old one if exists first. - remove_postgresql_directory(datadir) - init_directory = ( - postgresql_ctl, 'initdb', - '-o "--auth=trust --username=%s"' % user, - '-D %s' % datadir, - ) - subprocess.check_output(' '.join(init_directory), shell=True) - - def init_postgresql_database(user, host, port, db_name): """ Create database in postgresql. :param str user: postgresql username :param str host: postgresql host :param str port: postgresql port :param str db_name: database name """ conn = psycopg2.connect(user=user, host=host, port=port) conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) cur = conn.cursor() - cur.execute('CREATE DATABASE "{0}";'.format(db_name)) + cur.execute('CREATE DATABASE "{}";'.format(db_name)) cur.close() conn.close() def drop_postgresql_database(user, host, port, db_name, version): """ Drop databse in postgresql. :param str user: postgresql username :param str host: postgresql host :param str port: postgresql port :param str db_name: database name - :param str version: postgresql version number + :param packaging.version.Version version: postgresql version number """ conn = psycopg2.connect(user=user, host=host, port=port) conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) cur = conn.cursor() # We cannot drop the database while there are connections to it, so we # terminate all connections first while not allowing new connections. - if float(version) >= 9.2: + if version >= parse_version('9.2'): pid_column = 'pid' else: pid_column = 'procpid' cur.execute( 'UPDATE pg_database SET datallowconn=false WHERE datname = %s;', (db_name,)) cur.execute( - 'SELECT pg_terminate_backend(pg_stat_activity.{0})' + 'SELECT pg_terminate_backend(pg_stat_activity.{})' 'FROM pg_stat_activity WHERE pg_stat_activity.datname = %s;'.format( pid_column), (db_name,)) - cur.execute('DROP DATABASE IF EXISTS "{0}";'.format(db_name)) + cur.execute('DROP DATABASE IF EXISTS "{}";'.format(db_name)) cur.close() conn.close() def postgresql_proc( executable=None, host=None, port=-1, user=None, options='', - startparams=None, unixsocketdir=None, logsdir=None, logs_prefix='', + startparams=None, unixsocketdir=None, logs_prefix='', ): """ Postgresql process factory. :param str executable: path to postgresql_ctl :param str host: hostname :param str|int|tuple|set|list port: exact port (e.g. '8000', 8000) randomly selected port (None) - any random available port -1 - command line or pytest.ini configured port [(2000,3000)] or (2000,3000) - random available port from a given range [{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports [(2000,3000), {4002,4003}] - random of given range and set :param str user: postgresql username :param str startparams: postgresql starting parameters :param str unixsocketdir: directory to create postgresql's unixsockets - :param str logsdir: location for logs :param str logs_prefix: prefix for log filename :rtype: func :returns: function which makes a postgresql process """ @pytest.fixture(scope='session') - def postgresql_proc_fixture(request): + def postgresql_proc_fixture(request, tmpdir_factory): """ Process fixture for PostgreSQL. :param FixtureRequest request: fixture request object :rtype: pytest_dbfixtures.executors.TCPExecutor :returns: tcp executor """ config = get_config(request) postgresql_ctl = executable or config['exec'] # check if that executable exists, as it's no on system PATH # only replace if executable isn't passed manually if not os.path.exists(postgresql_ctl) and executable is None: pg_bindir = subprocess.check_output( ['pg_config', '--bindir'], universal_newlines=True ).strip() postgresql_ctl = os.path.join(pg_bindir, 'pg_ctl') pg_host = host or config['host'] pg_port = get_port(port) or get_port(config['port']) datadir = os.path.join( - gettempdir(), 'postgresqldata.{0}'.format(pg_port)) + gettempdir(), 'postgresqldata.{}'.format(pg_port)) pg_user = user or config['user'] pg_options = options or config['options'] pg_unixsocketdir = unixsocketdir or config['unixsocketdir'] pg_startparams = startparams or config['startparams'] - pg_logsdir = logsdir or config['logsdir'] - logfile_path = os.path.join( - pg_logsdir, '{prefix}postgresql.{port}.log'.format( + logfile_path = tmpdir_factory.mktemp("data").join( + '{prefix}postgresql.{port}.log'.format( prefix=logs_prefix, port=pg_port - )) - - init_postgresql_directory( - postgresql_ctl, pg_user, datadir + ) ) if platform.system() == 'FreeBSD': with (datadir / 'pg_hba.conf').open(mode='a') as conf_file: conf_file.write('host all all 0.0.0.0/0 trust\n') postgresql_executor = PostgreSQLExecutor( executable=postgresql_ctl, host=pg_host, port=pg_port, user=pg_user, options=pg_options, datadir=datadir, unixsocketdir=pg_unixsocketdir, logfile=logfile_path, startparams=pg_startparams, ) - # start server with postgresql_executor: - if '-w' in pg_startparams: - wait_for_postgres(logfile_path, START_INFO) + postgresql_executor.wait_for_postgres() yield postgresql_executor - remove_postgresql_directory(datadir) - return postgresql_proc_fixture -def postgresql(process_fixture_name, db_name='tests'): +def postgresql(process_fixture_name, db_name=None): """ Return connection fixture factory for PostgreSQL. :param str process_fixture_name: name of the process fixture :param str db_name: database name :rtype: func :returns: function which makes a connection to postgresql """ @pytest.fixture def postgresql_factory(request): """ Fixture factory for PostgreSQL. :param FixtureRequest request: fixture request object :rtype: psycopg2.connection :returns: postgresql client """ + config = get_config(request) if not psycopg2: raise ImportError( 'No module named psycopg2. Please install either ' 'psycopg2 or psycopg2-binary package for CPython ' 'or psycopg2cffi for Pypy.' ) proc_fixture = request.getfixturevalue(process_fixture_name) # _, config = try_import('psycopg2', request) pg_host = proc_fixture.host pg_port = proc_fixture.port pg_user = proc_fixture.user pg_options = proc_fixture.options - pg_db = db_name + pg_db = db_name or config['dbname'] init_postgresql_database(pg_user, pg_host, pg_port, pg_db) connection = psycopg2.connect( dbname=pg_db, user=pg_user, host=pg_host, port=pg_port, options=pg_options ) def drop_database(): connection.close() drop_postgresql_database( pg_user, pg_host, pg_port, pg_db, proc_fixture.version ) request.addfinalizer(drop_database) return connection return postgresql_factory __all__ = ('postgresql', 'postgresql_proc') diff --git a/src/pytest_postgresql/plugin.py b/src/pytest_postgresql/plugin.py index a473e5b..0549c7f 100644 --- a/src/pytest_postgresql/plugin.py +++ b/src/pytest_postgresql/plugin.py @@ -1,158 +1,158 @@ # Copyright (C) 2016 by Clearcode # and associates (see AUTHORS). # This file is part of pytest-postgresql. # pytest-dbfixtures is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # pytest-postgresql is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public License # along with pytest-postgresql. If not, see . """Plugin module of pytest-postgresql.""" from tempfile import gettempdir from pytest_postgresql import factories # pylint:disable=invalid-name _help_executable = 'Path to PostgreSQL executable' _help_host = 'Host at which PostgreSQL will accept connections' _help_port = 'Port at which PostgreSQL will accept connections' _help_user = "PostgreSQL username" _help_options = "PostgreSQL connection options" _help_startparams = "Starting parameters for the PostgreSQL" -_help_logsdir = "Logs directory location" _help_logsprefix = "Prefix for the log files" _help_unixsocketdir = "Location of the socket directory" +_help_dbname = "Default database name" def pytest_addoption(parser): """Configure options for pytest-postgresql.""" parser.addini( name='postgresql_exec', help=_help_executable, default='/usr/lib/postgresql/9.1/bin/pg_ctl' ) parser.addini( name='postgresql_host', help=_help_host, default='127.0.0.1' ) parser.addini( name='postgresql_port', help=_help_port, default=None, ) parser.addini( name='postgresql_user', help=_help_user, default='postgres' ) parser.addini( name='postgresql_options', help=_help_options, default='' ) parser.addini( name='postgresql_startparams', help=_help_startparams, default='-w' ) - parser.addini( - name='postgresql_logsdir', - help=_help_logsdir, - default=gettempdir() - ) - parser.addini( name='postgresql_logsprefix', help=_help_logsprefix, default='' ) parser.addini( name='postgresql_unixsocketdir', help=_help_unixsocketdir, default=gettempdir() ) + parser.addini( + name='postgresql_dbname', + help=_help_dbname, + default='tests' + ) + parser.addoption( '--postgresql-exec', action='store', metavar='path', dest='postgresql_exec', help=_help_executable ) parser.addoption( '--postgresql-host', action='store', dest='postgresql_host', help=_help_host, ) parser.addoption( '--postgresql-port', action='store', dest='postgresql_port', help=_help_port ) parser.addoption( '--postgresql-user', action='store', dest='postgresql_user', help=_help_user ) parser.addoption( '--postgresql-options', action='store', dest='postgresql_options', help=_help_options ) parser.addoption( '--postgresql-startparams', action='store', dest='postgresql_startparams', help=_help_startparams ) - parser.addoption( - '--postgresql-logsdir', - action='store', - dest='postgresql_logsdir', - help=_help_logsdir - ) - parser.addoption( '--postgresql-logsprefix', action='store', dest='postgresql_logsprefix', help=_help_logsprefix ) parser.addoption( '--postgresql-unixsocketdir', action='store', dest='postgresql_unixsocketdir', help=_help_unixsocketdir ) + parser.addoption( + '--postgresql-dbname', + action='store', + dest='postgresql_dbname', + help=_help_dbname + ) + postgresql_proc = factories.postgresql_proc() postgresql = factories.postgresql('postgresql_proc') diff --git a/src/pytest_postgresql/port.py b/src/pytest_postgresql/port.py index 2ee0464..01ea434 100644 --- a/src/pytest_postgresql/port.py +++ b/src/pytest_postgresql/port.py @@ -1,85 +1,85 @@ # Copyright (C) 2016 by Clearcode # and associates (see AUTHORS). # This file is part of pytest-postgresql. # pytest-postgresql is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # pytest-postgresql is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public License # along with pytest-postgresql. If not, see . """Helpers for port-for package.""" from itertools import chain import port_for class InvalidPortsDefinition(ValueError): """Exception raised if ports definition is not a valid string.""" def __init__(self, ports): """Construct InvalidPortsDefinition exception.""" - super(InvalidPortsDefinition, self).__init__( - 'Unknown format of ports: {0}.\n'.format(ports) + ( + super().__init__( + 'Unknown format of ports: {}.\n'.format(ports) + ( 'You should provide a ports range "[(4000,5000)]"' 'or "(4000,5000)" or a comma-separated ports set' '"[{4000,5000,6000}]" or list of ints "[400,5000,6000,8000]"' 'or all of them "[(20000, 30000), {48889, 50121}, 4000, 4004]"' ) ) def get_port(ports): """ Retun a random available port. If there's only one port passed (e.g. 5000 or '5000') function does not check if port is available. it there's -1 passed as an argument, function returns None. When a range or list of ports is passed `port_for` external package is used in order to find a free port. :param str|int|tuple|set|list port: exact port (e.g. '8000', 8000) randomly selected port (None) - any random available port [(2000,3000)] or (2000,3000) - random available port from a given range [{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports [(2000,3000), {4002,4003}] -random of given orange and set :returns: a random free port :raises: ValueError """ if ports == -1: return None if not ports: return port_for.select_random(None) try: return int(ports) except TypeError: pass ports_set = set() try: if not isinstance(ports, list): ports = [ports] ranges = port_for.utils.ranges_to_set(filter_by_type(ports, tuple)) nums = set(filter_by_type(ports, int)) sets = set(chain(*filter_by_type(ports, (set, frozenset)))) ports_set = ports_set.union(ranges, sets, nums) except ValueError: raise InvalidPortsDefinition return port_for.select_random(ports_set) def filter_by_type(lst, type_of): """Return a list of elements with given type.""" return [e for e in lst if isinstance(e, type_of)] diff --git a/tests/conftest.py b/tests/conftest.py index 87155e5..f0b3d54 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,27 +1,21 @@ """Tests main conftest file.""" -import sys -import warnings - from pytest_postgresql import factories -if not sys.version_info >= (3, 5): - warnings.simplefilter("error", category=DeprecationWarning) - PG_CTL = '/usr/lib/postgresql/{ver}/bin/pg_ctl' # pylint:disable=invalid-name postgresql92 = factories.postgresql_proc(PG_CTL.format(ver='9.2'), port=None) postgresql93 = factories.postgresql_proc(PG_CTL.format(ver='9.3'), port=None) postgresql94 = factories.postgresql_proc(PG_CTL.format(ver='9.4'), port=None) postgresql95 = factories.postgresql_proc(PG_CTL.format(ver='9.5'), port=None) postgresql96 = factories.postgresql_proc(PG_CTL.format(ver='9.6'), port=None) postgresql10 = factories.postgresql_proc(PG_CTL.format(ver='10'), port=None) postgresql101 = factories.postgresql_proc(PG_CTL.format(ver='10.1'), port=None) postgresql_proc2 = factories.postgresql_proc(port=9876) postgresql2 = factories.postgresql('postgresql_proc2', db_name='test-db') postgresql_rand_proc = factories.postgresql_proc(port=None) postgresql_rand = factories.postgresql('postgresql_rand_proc') # pylint:enable=invalid-name diff --git a/tests/test_executor.py b/tests/test_executor.py new file mode 100644 index 0000000..59461b2 --- /dev/null +++ b/tests/test_executor.py @@ -0,0 +1,34 @@ +"""Test various executor behaviours.""" +import pytest +from pkg_resources import parse_version + +from pytest_postgresql.executor import PostgreSQLExecutor, PostgreSQLUnsupported +from pytest_postgresql.factories import get_config +from pytest_postgresql.port import get_port + + +class PatchedPostgreSQLExecutor(PostgreSQLExecutor): + """PostgreSQLExecutor that always says it's 8.9 version.""" + + @property + def version(self): + """Overwrite version, to always return highes unsupported version.""" + return parse_version('8.9') + + +def test_unsupported_version(request): + """Check that the error gets raised on unsupported postgres version.""" + config = get_config(request) + executor = PatchedPostgreSQLExecutor( + executable=config['exec'], + host=config['host'], + port=get_port(config['port']), + datadir='/tmp/error', + unixsocketdir=config['unixsocketdir'], + logfile='/tmp/version.error.log', + startparams=config['startparams'], + + ) + + with pytest.raises(PostgreSQLUnsupported): + executor.start()