Фляга-сокетио, фляга-sqlalchemy и pytest-селен

Я пытаюсь добавить тесты Selenium в приложение Flask, которое сильно зависит от Flask-SocketIO. Однако при доступе к странице из браузера Selenium, который выполняет запрос к базе данных, в окне браузера появляется следующее сообщение об ошибке:

Traceback (most recent call last):
  File "/home/bbbart/.virtualenvs/heistmanager/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 346, in connection
    return self.__connection
AttributeError: 'Connection' object has no attribute '_Connection__connection'

During handling of the above exception, another exception occurred:
[...]
 File "/home/bbbart/.virtualenvs/heistmanager/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 429, in _revalidate_connection
    raise exc.ResourceClosedError("This Connection is closed")
sqlalchemy.exc.ResourceClosedError: This Connection is closed
  • bbbart мое имя пользователя
  • heistmanager это название приложения
  • Я использую следующий пакет PyPI (среди прочих):
    • Колба == 0.12.2
    • SQLAlchemy == 1.1.13
    • Колба-SQLAlchemy==2.2
    • Колба-SocketIO==2.9.2
    • Колба-Script == 2.0.5
    • eventlet == 0.21.0
    • pytest == 3.2.1
    • pytest-колбу == 0.10.0
    • pytest-селен ==1.11.0

У меня есть обширный набор pytest для этого приложения, который уже работает отлично, включая тесты, основанные на базе данных, и тесты с использованием client крепеж из пытест-колбы. Эта ошибка появляется только при внешнем запуске сервера для Selenium.

Чтобы приложение правильно запускалось с поддержкой веб-сокетов, я переопределил класс LiveServer и фикстуру live_server из pytest_flask следующим образом (это необходимо?) В conftest.py:

class LiveSocketIOServer(LiveServer):
    """The helper class to manage live socketio server. Handles creation and
    stopping of the application in a separate process.

    :param app: The application to run.
    :param port: The port to run application.
    """

    def start(self, socketio):
        """Start application in a separate process."""
        def worker(app, port):
            return socketio.run(app, port=port, use_reloader=False)

        self._process = multiprocessing.Process(
            target=worker,
            args=(self.app, self.port)
        )   
        self._process.start()

        # We must wait for the server to start listening with a maximum
        # timeout of 5 seconds.
        timeout = 5 
        while timeout > 0:
            time.sleep(1)
            try:
                urlopen(self.url())
                timeout = 0 
            except BaseException:
                timeout -= 1

    def __repr__(self):
        return '<LiveSocketIOServer listening at %s>' % self.url()

а также

@pytest.yield_fixture(scope='function')
def live_server(request, app, monkeypatch):
    """Run application in a separate process.

    When the ``live_server`` fixture is applied, the ``url_for`` function
    works as expected::

        def test_server_is_up_and_running(live_server):
            index_url = url_for('index', _external=True)
            assert index_url == 'http://localhost:5000/'

            res = urllib2.urlopen(index_url)
            assert res.code == 200

    """
    # Find an open port
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('', 0))
    port = sock.getsockname()[1]
    sock.close()

    server_name = app.config['SERVER_NAME'] or 'localhost'
    monkeypatch.setitem(app.config, 'SERVER_NAME',
                        _rewrite_server_name(server_name, str(port)))

    server = LiveSocketIOServer(app, port)
    if request.config.getvalue('start_live_server'):
        server.start(SOCKETIO)

    yield server

    server.stop()

Мой тест выглядит так:

@pytest.mark.usefixtures('live_server')
class TestSockets:

    """Tests for socket.io (with selenium)."""

    @pytest.mark.nondestructive
    def test_admin_login(self, config, selenium):
        selenium.get(url_for('main.index', _external=True))
        assert 'Hello stranger!' in selenium.page_source

        selenium.find_element_by_link_text('Log in to administer').click()
        assert '<h1>Login</h1>' in selenium.page_source

        selenium.find_element_by_name('username').send_keys(
            config['USERNAME_ADMIN'])
        selenium.find_element_by_name('password').send_keys('*******')
        selenium.find_element_by_name('submit').click()
        assert 'Logged in as %s' % config['USERNAME_ADMIN'] in selenium.page_source

(Вы можете узнать некоторые элементы из отличной демонстрации Flasky Мигеля Гринберга.:-))

Ошибка выше поднимается после второго click позвоните в предпоследнюю строку теста. Это впоследствии, конечно, делает assert утверждение провалилось, но дело не в этом.

Тесты запускаются из команды диспетчера флеш-скриптов:

APP = create_app(os.getenv('HEIST_CONFIG') or 'default')
MANAGER = Manager(APP)

@MANAGER.command
def test():
    """Run the tests."""
    import pytest
    pytest.main(['--driver', 'Chrome',
                 os.path.join(basedir, 'tests')])

Я потратил несколько часов, пытаясь выяснить, почему соединение SQLAlchemy закрыто (или даже не открыто?). Я добавил в приборы все виды БД, но это никогда не казалось правильным, а также никогда не работало.

Я заблудился и был бы признателен за любой указатель здесь на решение. Спасибо!

0 ответов

Другие вопросы по тегам