diff --git a/.github/workflows/run-tox-suite.yml b/.github/workflows/run-tox-suite.yml index d85fee7..d0c046e 100644 --- a/.github/workflows/run-tox-suite.yml +++ b/.github/workflows/run-tox-suite.yml @@ -1,5 +1,5 @@ name: Run Tox Suite -on: [push, pull_request] +on: [push, pull_request, workflow_dispatch] jobs: py310: runs-on: ubuntu-latest diff --git a/biweeklybudget/tests/acceptance/test_plaidlink.py b/biweeklybudget/tests/acceptance/test_plaidlink.py index 7bcaa3f..efbcaa8 100644 --- a/biweeklybudget/tests/acceptance/test_plaidlink.py +++ b/biweeklybudget/tests/acceptance/test_plaidlink.py @@ -133,7 +133,7 @@ def test_03_do_simple_link(self, base_url, selenium): sb.send_keys('First Platypus') # click on First Platypus Bank WebDriverWait(selenium, 10).until( - EC.element_to_be_clickable((By.ID, 'aut-First Platypus Bank')) + EC.element_to_be_clickable((By.ID, 'aut-ins_109508')) ).click() # click on the non-OAuth institution WebDriverWait(selenium, 10).until( diff --git a/biweeklybudget/tests/docker_build.py b/biweeklybudget/tests/docker_build.py index 0321acf..0730459 100755 --- a/biweeklybudget/tests/docker_build.py +++ b/biweeklybudget/tests/docker_build.py @@ -486,15 +486,14 @@ def _test_scripts(self, container): ] for cmd_info in test_cmds: logger.debug('Running: %s', cmd_info['cmd']) - res = container.exec_run(cmd_info['cmd']).decode().strip() - logger.debug('Command output:\n%s', res) - if 'output' in cmd_info: - if cmd_info['output'] not in res: - raise RuntimeError( - 'Expected %s output to include "%s" but it did not' % ( - cmd_info['cmd'], cmd_info['output'] - ) + ecode, res = container.exec_run(cmd_info['cmd']) + logger.debug('Command exited %d; output:\n%s', ecode, res) + if 'output' in cmd_info and cmd_info['output'] not in res.decode(): + raise RuntimeError( + 'Expected %s output to include "%s" but it did not' % ( + cmd_info['cmd'], cmd_info['output'] ) + ) logger.info('script tests SUCCEEDED') def _run_mysql(self): @@ -527,11 +526,12 @@ def _run_mysql(self): while count < 10: count += 1 logger.info('Creating database...') - cmd = '/usr/bin/mysql -uroot -proot -e "CREATE DATABASE budgetfoo;"' + cmd = ('/usr/bin/mysql -uroot -proot -h 127.0.0.1 ' + '-e "CREATE DATABASE budgetfoo;"') logger.debug('Running: %s', cmd) - res = cont.exec_run(cmd) - logger.debug('Command output:\n%s', res) - if 'ERROR' not in res.decode(): + ecode, res = cont.exec_run(cmd) + logger.debug('Command exited %d; output:\n%s', ecode, res) + if 'ERROR' not in res.decode() and ecode == 0: logger.info('Database creation appears successful.') break logger.warning('Database creation errored; sleep 5s and retry') @@ -555,17 +555,15 @@ def _build_image(self, tag): 'quiet': False, 'nocache': True, 'rm': True, - 'stream': True, 'pull': True, 'dockerfile': '/Dockerfile', 'buildargs': {'version': tag}, 'decode': True } logger.info('Running docker build with args: %s', kwargs) - res = self._docker.api.build(**kwargs) logger.info('Build running; output:') error = None - for line in res: + for line in self._docker.api.build(**kwargs): if 'errorDetail' in line: error = line['errorDetail'] try: diff --git a/docs/source/flask_app.rst b/docs/source/flask_app.rst index 1d4bd1a..4891dc9 100644 --- a/docs/source/flask_app.rst +++ b/docs/source/flask_app.rst @@ -9,7 +9,7 @@ Running Flask Development Server Flask comes bundled with a builtin development server for fast local development and testing. This is an easy way to take biweeklybudget for a spin, but carries some important and critical warnings if you use it with real data. For upstream documentation, see the -`Flask Development Server docs `_. Please note that +`Flask Development Server docs `_. Please note that the development server is a single process and defaults to single-threaded, and is only realistically usable by one user. diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 7e3dbff..8a33e24 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -198,29 +198,29 @@ Host-Local MySQL Example ++++++++++++++++++++++++ It is also possible to use a MySQL server on the physical (Docker) host system. To do so, -you'll need to know the host system's IP address. On Linux when using the default "bridge" -Docker networking mode, this will coorespond to a ``docker0`` interface on the host system. -The Docker documentation on `adding entries to the Container's hosts file `_ -provides a helpful snippet for this (on my systems, this results in ``172.17.0.1``): - -.. code-block:: none - - ip -4 addr show scope global dev docker0 | grep inet | awk '{print $2}' | cut -d / -f 1 - -In our ``biweeklybudget.env``, we would specify the database connection string that uses the "dockerhost" hosts file entry, created by the ``--add-host`` option: +you'll need to know the host system's IP address (as seen from the container). On Linux when +using the default "bridge" Docker networking mode, this will coorespond to the container's +gateway (the gateway of the Docker network that the container is in) and will usually be +``172.x.0.1``. Using the special ``host-gateway`` option available in the +`docker run command --add-host option `_, +we can add ``--add-host=host.docker.internal:host-gateway`` to our ``docker run`` command and +then use that as the hostname in the DB connection string: .. code-block:: none # "dockerhost" is added to /etc/hosts via the `--add-host` docker run option - DB_CONNSTRING=mysql+pymysql://USERNAME:PASSWORD@dockerhost:3306/DBNAME?charset=utf8mb4 + DB_CONNSTRING=mysql+pymysql://USERNAME:PASSWORD@host.docker.internal:3306/DBNAME?charset=utf8mb4 So using that, we could run biweeklybudget listening on port 8080 and using our host's MySQL server (on port 3306): .. code-block:: none - docker run --name biweeklybudget --env-file biweeklybudget.env \ - --add-host="dockerhost:$(ip -4 addr show scope global dev docker0 | grep inet | awk '{print $2}' | cut -d / -f 1)" \ - -p 8080:80 jantman/biweeklybudget:latest + docker run \ + --name biweeklybudget \ + --env-file biweeklybudget.env \ + --add-host="host.docker.internal:host-gateway" \ + -p 8080:80 \ + jantman/biweeklybudget:latest You may need to adjust those commands depending on your operating system, Docker networking mode, and MySQL server. @@ -236,7 +236,7 @@ Settings Module Example If you need to provide biweeklybudget with more complicated configuration, this is still possible via a Python settings module. The easiest way to inject one into the -Docker image is to `mount `_ +Docker image is to `mount `_ a python module directly into the biweeklybudget package directory. Assuming you have a custom settings module on your local machine at ``/opt/biweeklybudget-settings.py``, you would run the container as shown below to mount the custom settings module into the container and use it. @@ -252,7 +252,7 @@ MySQL running on the Docker host: Note on Locales +++++++++++++++ -biweeklybudget uses Python's `locale `_ module +biweeklybudget uses Python's `locale `_ module to format currency. This requires an appropriate locale installed on the system. The docker image distributed for this package only includes the ``en_US.UTF-8`` locale. If you need a different one, please cut a pull request against ``docker_build.py``. diff --git a/requirements.txt b/requirements.txt index 8cf73c0..94ec13f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,7 +34,7 @@ python-dateutil==2.8.1 python-editor==1.0.4 pytz requests -selenium==3.141.0 +selenium==4.2.0 six==1.14.0 versionfinder>=1.0.0 wishlist==0.2.2 diff --git a/tox.ini b/tox.ini index e788b7b..c38e50d 100644 --- a/tox.ini +++ b/tox.ini @@ -52,6 +52,7 @@ setenv = PLAID_COUNTRY_CODES=US deps = -r{toxinidir}/requirements.txt + alabaster==0.7.12 docutils==0.16 pygments==2.6.1 sphinx==1.5.5 @@ -108,7 +109,7 @@ commands = [testenv:docker] deps = -r{toxinidir}/requirements.txt - docker==2.2.1 + docker>=7.0.0,<8.0.0 passenv = {[testenv]passenv},DOCKER_TEST_TAG,DOCKER_BUILD_VER,TEST_DOCKER,GITHUB_OUTPUT setenv = {[testenv]setenv} basepython = python3.10 @@ -134,7 +135,8 @@ deps = mock freezegun pytest-flask==1.0.0 - pytest-selenium + selenium==4.2.0 + pytest-selenium==4.0.0 pytest-timeout alembic-verify retrying @@ -162,7 +164,8 @@ deps = mock freezegun pytest-flask==1.0.0 - pytest-selenium + selenium==4.2.0 + pytest-selenium==4.0.0 pytest-timeout alembic-verify retrying