1

我正在尝试使用 wercker 的 dockerized 版本在 python 应用程序中运行单元测试,但我的大多数单元测试都因错误而失败sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) could not connect to server: No route to host。wercker 文档缺少建立此连接的配置。

也许我错过了一些简单的东西,但是在花费了比我应该拥有的更多时间之后,我无法建立这个数据库连接来运行我的测试。无论如何,Rails 应用程序有类似的问题,但答案没有帮助,所以也许问题会帮助其他人使用 python 应用程序。寻求帮助!

以下是我当前的 wercker.yml:

# http://devcenter.wercker.com/docs/containers/index.html

box: python:3.4.4-onbuild

# You can also use services such as databases. Read more on our dev center:
# http://devcenter.wercker.com/docs/services/index.html

services:
    # http://devcenter.wercker.com/docs/services/postgresql.html
    - id: postgres:9.4
      env:
        POSTGRES_PASSWORD: mylittlesecret
        POSTGRES_USER: postgres  # optional

# This is the build pipeline. Pipelines are the core of wercker
# Read more about pipelines on our dev center
# http://devcenter.wercker.com/docs/pipelines/index.html

build:
  # The steps that will be executed on build
  # Steps make up the actions in your pipeline
  # Read more about steps on our dev center:
  # http://devcenter.wercker.com/docs/steps/index.html
  steps:
    # A step that sets up the python virtual environment
    - script:
        name: virtualenv install
        code: |
          pip install virtualenv

    - virtualenv:
        name: venv

    - pip-install:
        requirements_file: "requirements.txt"

    # A custom script step, name value is used in the UI
    # and the code value contains the command that get executed
    - script:
        name: echo python information
        code: |
          echo "python version $(python --version) running"
          echo "pip version $(pip --version) running"



    # A step that loads the database schema in order to run the tests - perhaps not needed!!
    - script:
        name: Set up db
        code: |
          echo "Start postgresql server ..."
          echo "Create test db ..."
          echo "Created test db ..."

    # Debug lines I've used in above script
    # export PATH=/usr/pgsql-9.4.6/bin:$PATH  ==> no impact
    # export PATH=/usr/lib/postgresql/9.4/bin:$PATH  ==> no impact
    # psql -c "CREATE DATABASE scrdbtest;"  ==> ERROR: psql command not found
    # postgres -D /var/lib/postgresql/data ==> ERROR: postgres not found

    - script:
        name: run aoscrdb tests
        code: |
          /root/venv/bin/python -m pytest ./tests

这是我的应用程序测试配置:

class TestConfig(Config):
    TESTING = True
    DEBUG = True
    # wercker
    SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://postgres:mylittlesecret@{}:5432/postgres'\
.format(os.environ.get('POSTGRES_PORT_5432_TCP_ADDR'))

最后,其中之一是来自 wercker 的失败测试:

 ============================= test session starts ==============================
platform linux -- Python 3.4.4, pytest-2.8.7, py-1.4.31, pluggy-0.3.1
rootdir: /pipeline/source/tests, inifile: 
collected 39 items

tests/test_config.py ..
tests/test_forms.py EEEEEEEEEEEEEEE
tests/test_functional.py EEEEEEE
tests/test_models.py EEEEEEEEEEEEEEE

==================================== ERRORS ====================================
___ ERROR at setup of TestRegisterForm.test_validate_user_already_registered ___

app = <Flask 'aoscrdb_app.app'>

    @pytest.yield_fixture(scope='function')
    def db(app):
        """A database for the tests."""
        _db.app = app
        with app.app_context():
>           _db.create_all()

tests/conftest.py:36: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/venv/lib/python3.4/site-packages/flask_sqlalchemy/__init__.py:972: in create_all
    self._execute_for_all_tables(app, bind, 'create_all')
/root/venv/lib/python3.4/site-packages/flask_sqlalchemy/__init__.py:964: in _execute_for_all_tables
    op(bind=self.get_engine(app, bind), **extra)
/root/venv/lib/python3.4/site-packages/sqlalchemy/sql/schema.py:3695: in create_all
    tables=tables)
/root/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py:1855: in _run_visitor
    with self._optional_conn_ctx_manager(connection) as conn:
/usr/local/lib/python3.4/contextlib.py:59: in __enter__
    return next(self.gen)
/root/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py:1848: in _optional_conn_ctx_manager
    with self.contextual_connect() as conn:
/root/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py:2039: in contextual_connect
    self._wrap_pool_connect(self.pool.connect, None),
/root/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py:2078: in _wrap_pool_connect
    e, dialect, self)
/root/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py:1405: in _handle_dbapi_exception_noconnection
    exc_info
/root/venv/lib/python3.4/site-packages/sqlalchemy/util/compat.py:189: in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=exc_value)
/root/venv/lib/python3.4/site-packages/sqlalchemy/util/compat.py:182: in reraise
    raise value.with_traceback(tb)
/root/venv/lib/python3.4/site-packages/sqlalchemy/engine/base.py:2074: in _wrap_pool_connect
    return fn()
/root/venv/lib/python3.4/site-packages/sqlalchemy/pool.py:376: in connect
    return _ConnectionFairy._checkout(self)
/root/venv/lib/python3.4/site-packages/sqlalchemy/pool.py:713: in _checkout
    fairy = _ConnectionRecord.checkout(pool)
/root/venv/lib/python3.4/site-packages/sqlalchemy/pool.py:480: in checkout
    rec = pool._do_get()
/root/venv/lib/python3.4/site-packages/sqlalchemy/pool.py:1060: in _do_get
    self._dec_overflow()
/root/venv/lib/python3.4/site-packages/sqlalchemy/util/langhelpers.py:60: in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
/root/venv/lib/python3.4/site-packages/sqlalchemy/util/compat.py:183: in reraise
    raise value
/root/venv/lib/python3.4/site-packages/sqlalchemy/pool.py:1057: in _do_get
    return self._create_connection()
/root/venv/lib/python3.4/site-packages/sqlalchemy/pool.py:323: in _create_connection
    return _ConnectionRecord(self)
/root/venv/lib/python3.4/site-packages/sqlalchemy/pool.py:449: in __init__
    self.connection = self.__connect()
/root/venv/lib/python3.4/site-packages/sqlalchemy/pool.py:607: in __connect
    connection = self.__pool._invoke_creator(self)
/root/venv/lib/python3.4/site-packages/sqlalchemy/engine/strategies.py:97: in connect
    return dialect.connect(*cargs, **cparams)
/root/venv/lib/python3.4/site-packages/sqlalchemy/engine/default.py:385: in connect
    return self.dbapi.connect(*cargs, **cparams)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

dsn = 'dbname=postgres user=postgres password=mysecretpassword host=172.17.0.10'
database = 'postgres', user = 'postgres', password = 'mysecretpassword'
host = '172.17.0.10', port = None, connection_factory = None
cursor_factory = None, async = False, kwargs = {}
items = [('dbname', 'postgres'), ('user', 'postgres'), ('password', 'mysecretpassword'), ('host', '172.17.0.10')]

    def connect(dsn=None,
            database=None, user=None, password=None, host=None, port=None,
            connection_factory=None, cursor_factory=None, async=False, **kwargs):
        """
        Create a new database connection.

        The connection parameters can be specified either as a string:

            conn = psycopg2.connect("dbname=test user=postgres password=secret")

        or using a set of keyword arguments:

            conn = psycopg2.connect(database="test", user="postgres", password="secret")

        The basic connection parameters are:

        - *dbname*: the database name (only in dsn string)
        - *database*: the database name (only as keyword argument)
        - *user*: user name used to authenticate
        - *password*: password used to authenticate
        - *host*: database host address (defaults to UNIX socket if not provided)
        - *port*: connection port number (defaults to 5432 if not provided)

        Using the *connection_factory* parameter a different class or connections
        factory can be specified. It should be a callable object taking a dsn
        argument.

        Using the *cursor_factory* parameter, a new default cursor factory will be
        used by cursor().

        Using *async*=True an asynchronous connection will be created.

        Any other keyword parameter will be passed to the underlying client
        library: the list of supported parameters depends on the library version.

        """
        items = []
        if database is not None:
            items.append(('dbname', database))
        if user is not None:
            items.append(('user', user))
        if password is not None:
            items.append(('password', password))
        if host is not None:
            items.append(('host', host))
        if port is not None:
            items.append(('port', port))

        items.extend([(k, v) for (k, v) in kwargs.items() if v is not None])

        if dsn is not None and items:
            raise TypeError(
                "'%s' is an invalid keyword argument when the dsn is specified"
                    % items[0][0])

        if dsn is None:
            if not items:
                raise TypeError('missing dsn and no parameters')
            else:
                dsn = " ".join(["%s=%s" % (k, _param_escape(str(v)))
                    for (k, v) in items])

>       conn = _connect(dsn, connection_factory=connection_factory, async=async)
E       sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) could not connect to server: No route to host
E           Is the server running on host "172.17.0.10" and accepting
E           TCP/IP connections on port 5432?
4

0 回答 0