From 0adba51aed0401123115c36248b9441ec4ee704c Mon Sep 17 00:00:00 2001 From: Kaiser Dandangi Date: Wed, 5 Dec 2018 23:52:43 -0500 Subject: [PATCH 1/7] Attempting multi db testing --- .travis.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index af3fed2..5b0f32e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,17 +10,41 @@ python: - '3.6' env: - - TEST_DATABASE_URL=postgresql://postgres@localhost:5432/pytest_test + - DB=sqlite + - DB=mysql + - DB=pgsql addons: postgresql: '9.6' +before_script: + - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'DROP DATABASE IF EXISTS pytest_test;' -U postgres; fi" + - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'CREATE DATABASE pytest_test;' -U postgres; fi" + - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE IF NOT EXISTS pytest_test;'; fi" + install: - pip install --upgrade pip - pip install -e .[tests] script: pytest +jobs: + include: + - stage: Test PostgresSQL + env: DB=pgsql TEST_DATABASE_URL=postgresql://postgres@localhost:5432/pytest_test + addons: + postgresql: '9.6' + + - stage: Test MySQL + env: DB=mysql TEST_DATABASE_URL=mysql+mysqldb://root@127.0.0.1/pytest_test + addons: + mysql: '5.7' + + - stage: Test SQLite + env: DB=sqlite TEST_DATABASE_URL=sqlite:///:memory:/pytest_test + addons: + sqlite: '9.6' + deploy: provider: pypi distributions: 'sdist bdist_wheel' From e1791928a8a7ed9438f7bd03f0ea953973437192 Mon Sep 17 00:00:00 2001 From: Kaiser Dandangi Date: Sat, 22 Dec 2018 12:36:13 -0500 Subject: [PATCH 2/7] only one python to test multi db feature --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5b0f32e..61797cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,6 @@ branches: language: python python: - - '3.4' - - '3.5' - '3.6' env: From aeb15c8f26c93d997c1fbdd876832da5162c1cf8 Mon Sep 17 00:00:00 2001 From: Kaiser Dandangi Date: Sat, 22 Dec 2018 13:03:35 -0500 Subject: [PATCH 3/7] just trying to make pg work --- .travis.yml | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 61797cb..f9e98a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,7 @@ python: - '3.6' env: - - DB=sqlite - - DB=mysql - - DB=pgsql + - DB=pgsql TEST_DATABASE_URL=postgresql://postgres@localhost:5432/pytest_test addons: postgresql: '9.6' @@ -26,23 +24,6 @@ install: script: pytest -jobs: - include: - - stage: Test PostgresSQL - env: DB=pgsql TEST_DATABASE_URL=postgresql://postgres@localhost:5432/pytest_test - addons: - postgresql: '9.6' - - - stage: Test MySQL - env: DB=mysql TEST_DATABASE_URL=mysql+mysqldb://root@127.0.0.1/pytest_test - addons: - mysql: '5.7' - - - stage: Test SQLite - env: DB=sqlite TEST_DATABASE_URL=sqlite:///:memory:/pytest_test - addons: - sqlite: '9.6' - deploy: provider: pypi distributions: 'sdist bdist_wheel' From 90a37c91b4b521e3db4a4b85e0d89ac6dcede13f Mon Sep 17 00:00:00 2001 From: Kaiser Dandangi Date: Sat, 22 Dec 2018 13:06:34 -0500 Subject: [PATCH 4/7] added mysql --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index f9e98a7..1d06470 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,11 @@ python: env: - DB=pgsql TEST_DATABASE_URL=postgresql://postgres@localhost:5432/pytest_test + - DB=mysql TEST_DATABASE_URL=mysql+mysqldb://root@127.0.0.1/pytest_test addons: postgresql: '9.6' + mysql: '5.7' before_script: - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'DROP DATABASE IF EXISTS pytest_test;' -U postgres; fi" From cbe1306f8dab482387bae69889226a6117a77398 Mon Sep 17 00:00:00 2001 From: Kaiser Dandangi Date: Thu, 3 Jan 2019 22:02:22 -0500 Subject: [PATCH 5/7] Updated db fixtures to also work with MySQL Also updated dependencies and tests for fixtures --- pytest_flask_sqlalchemy/fixtures.py | 3 ++ setup.py | 2 +- tests/_conftest.py | 33 +++++++++++++----- tests/test_fixtures.py | 52 +++++++++++++++++++++-------- 4 files changed, 66 insertions(+), 24 deletions(-) diff --git a/pytest_flask_sqlalchemy/fixtures.py b/pytest_flask_sqlalchemy/fixtures.py index c38951b..45c045d 100644 --- a/pytest_flask_sqlalchemy/fixtures.py +++ b/pytest_flask_sqlalchemy/fixtures.py @@ -102,6 +102,9 @@ def _engine(pytestconfig, request, _transaction, mocker): # the Engine dialect to reflect tables) engine.dialect = connection.dialect + # Necessary for branching db test code + engine.name = connection.engine.name + @contextlib.contextmanager def begin(): ''' diff --git a/setup.py b/setup.py index aff550c..5e53d55 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ def readme(): 'pytest-mock>=1.6.2', 'SQLAlchemy>=1.2.2', 'Flask-SQLAlchemy>=2.3'], - extras_require={'tests': ['pytest-postgresql']}, + extras_require={'tests': ['pytest-postgresql', 'pytest-mysql']}, classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Plugins', diff --git a/tests/_conftest.py b/tests/_conftest.py index e6b84f9..dcc992a 100644 --- a/tests/_conftest.py +++ b/tests/_conftest.py @@ -6,6 +6,7 @@ import sqlalchemy as sa from flask import Flask from flask_sqlalchemy import SQLAlchemy +from pytest_mysql.factories import mysql from pytest_postgresql.factories import (init_postgresql_database, drop_postgresql_database) @@ -17,7 +18,8 @@ 'connection string to the environmental variable ' + 'TEST_DATABASE_URL in order to run tests.') else: - DB_OPTS = sa.engine.url.make_url(DB_CONN).translate_connect_args() + DB_URL = sa.engine.url.make_url(DB_CONN) + DB_OPTS = DB_URL.translate_connect_args() pytest_plugins = ['pytest-flask-sqlalchemy'] @@ -27,16 +29,28 @@ def database(request): ''' Create a Postgres database for the tests, and drop it when the tests are done. ''' - pg_host = DB_OPTS.get("host") - pg_port = DB_OPTS.get("port") - pg_user = DB_OPTS.get("username") - pg_db = DB_OPTS["database"] + db_host = DB_OPTS.get("host") + db_port = DB_OPTS.get("port") + db_user = DB_OPTS.get("username") + db_name = DB_OPTS["database"] - init_postgresql_database(pg_user, pg_host, pg_port, pg_db) + BACKEND = DB_URL.get_backend_name() - @request.addfinalizer - def drop_database(): - drop_postgresql_database(pg_user, pg_host, pg_port, pg_db, 9.6) + if BACKEND == 'mysql': + mysql('dummy_mysql_fixture', db=db_name) + + elif BACKEND == 'postgresql': + init_postgresql_database(db_user, db_host, db_port, db_name) + + @request.addfinalizer + def drop_database(): + drop_postgresql_database(db_user, db_host, db_port, db_name, 9.6) + + else: + raise ValueError( + 'Unsupported database type ({}) requested in ' + 'TEST_DATABASE_URL: {}'.format(BACKEND, DB_URL) + ) @pytest.fixture(scope='session') @@ -47,6 +61,7 @@ def app(database): app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = DB_CONN + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True return app diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index d1e953f..e802d4a 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -212,33 +212,57 @@ def test_drop_table(db_testdir): ''' Make sure that we can drop tables and verify they do not exist in the context of a test. + + NOTE: For MySQL `DROP TABLE ...` statements "cause an implicit commit after + executing. The intent is to handle each such statement in its own special + transaction because it cannot be rolled back anyway." + https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html + + So this test is skipped for 'mysql' engines ''' + db_testdir.makepyfile(""" def test_drop_table(person, db_engine): + if db_engine.name == 'mysql': + return # Drop the raw table db_engine.execute(''' - DROP TABLE "person" + DROP TABLE person ''') # Check if the raw table exists - existing_tables = db_engine.execute(''' - SELECT relname - FROM pg_catalog.pg_class - WHERE relkind in ('r', 'm') - AND relname = 'person' - ''').first() + if db_engine.name == 'postgresql': + existing_tables = db_engine.execute(''' + SELECT relname + FROM pg_catalog.pg_class + WHERE relkind in ('r', 'm') + AND relname = 'person' + ''').first() + + else: + raise ValueError( + 'unsupported database engine type: ' + db_engine.name + ) assert not existing_tables def test_drop_table_changes_dont_persist(person, db_engine): - - existing_tables = db_engine.execute(''' - SELECT relname - FROM pg_catalog.pg_class - WHERE relkind in ('r', 'm') - AND relname = 'person' - ''').first() + if db_engine.name == 'mysql': + return + + if db_engine.name == 'postgresql': + existing_tables = db_engine.execute(''' + SELECT relname + FROM pg_catalog.pg_class + WHERE relkind in ('r', 'm') + AND relname = 'person' + ''').first() + + else: + raise ValueError( + 'unsupported database engine type: ' + db_engine.name + ) assert existing_tables """) From db4de7a1a0e057b1f216fd08c21787ca9d53b90b Mon Sep 17 00:00:00 2001 From: Kaiser Dandangi Date: Thu, 3 Jan 2019 22:13:32 -0500 Subject: [PATCH 6/7] re-added python 3.4 and 3.5 to travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1d06470..04420af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,8 @@ branches: language: python python: + - '3.4' + - '3.5' - '3.6' env: From 7608cf48ea59c10d8db62cab70bb7c47299999f4 Mon Sep 17 00:00:00 2001 From: Kaiser Dandangi Date: Sun, 6 Jan 2019 10:38:27 -0500 Subject: [PATCH 7/7] Switched from pytest-mysql to bare PyMySQL connector --- .travis.yml | 3 +-- setup.py | 2 +- tests/_conftest.py | 25 ++++++++++++++++++++++--- tests/test_fixtures.py | 1 - 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 04420af..31e434e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,8 +19,7 @@ addons: before_script: - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'DROP DATABASE IF EXISTS pytest_test;' -U postgres; fi" - - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'CREATE DATABASE pytest_test;' -U postgres; fi" - - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE IF NOT EXISTS pytest_test;'; fi" + - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'DROP DATABASE IF EXISTS pytest_test;'; fi" install: - pip install --upgrade pip diff --git a/setup.py b/setup.py index 5e53d55..4c9c084 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ def readme(): 'pytest-mock>=1.6.2', 'SQLAlchemy>=1.2.2', 'Flask-SQLAlchemy>=2.3'], - extras_require={'tests': ['pytest-postgresql', 'pytest-mysql']}, + extras_require={'tests': ['pytest-postgresql', 'mysqlclient']}, classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Plugins', diff --git a/tests/_conftest.py b/tests/_conftest.py index dcc992a..2f86380 100644 --- a/tests/_conftest.py +++ b/tests/_conftest.py @@ -6,7 +6,7 @@ import sqlalchemy as sa from flask import Flask from flask_sqlalchemy import SQLAlchemy -from pytest_mysql.factories import mysql +import MySQLdb from pytest_postgresql.factories import (init_postgresql_database, drop_postgresql_database) @@ -24,6 +24,26 @@ pytest_plugins = ['pytest-flask-sqlalchemy'] +def _init_mysql_database(request, db_user, db_host, db_name, db_pass=''): + + mysql_conn = MySQLdb.connect( + host=db_host, + user=db_user, + passwd=db_pass + ) + + mysql_conn.query("CREATE DATABASE IF NOT EXISTS {name}".format(name=db_name)) + + mysql_conn.query("USE {name}".format(name=db_name)) + + @request.addfinalizer + def drop_database(): + mysql_conn.query("DROP DATABASE IF EXISTS {name}".format(name=db_name)) + mysql_conn.close() + + return mysql_conn + + @pytest.fixture(scope='session') def database(request): ''' @@ -37,7 +57,7 @@ def database(request): BACKEND = DB_URL.get_backend_name() if BACKEND == 'mysql': - mysql('dummy_mysql_fixture', db=db_name) + _init_mysql_database(request, db_user, db_host, db_name) elif BACKEND == 'postgresql': init_postgresql_database(db_user, db_host, db_port, db_name) @@ -61,7 +81,6 @@ def app(database): app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = DB_CONN - app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True return app diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index e802d4a..61447ca 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -40,7 +40,6 @@ def test_db_session_changes_dont_persist(person, db_engine, db_session): assert not db_session.query(person).first() """) - # Run tests result = db_testdir.runpytest() result.assert_outcomes(passed=2)