test: add 'nodb' test runner
ensure things work as expected if sqlalchemy is not installed
This commit is contained in:
parent
132073177c
commit
f5825e964c
|
@ -5,128 +5,131 @@ import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy import orm
|
|
||||||
from sqlalchemy.engine import Engine
|
|
||||||
from sqlalchemy.pool import NullPool
|
|
||||||
|
|
||||||
from wuttjamaican.db import conf
|
|
||||||
from wuttjamaican.conf import WuttaConfig
|
from wuttjamaican.conf import WuttaConfig
|
||||||
|
|
||||||
|
try:
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
from sqlalchemy.engine import Engine
|
||||||
|
from sqlalchemy.pool import NullPool
|
||||||
|
from wuttjamaican.db import conf
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
|
||||||
class TestGetEngines(TestCase):
|
class TestGetEngines(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.tempdir = tempfile.mkdtemp()
|
self.tempdir = tempfile.mkdtemp()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
shutil.rmtree(self.tempdir)
|
shutil.rmtree(self.tempdir)
|
||||||
|
|
||||||
def write_file(self, filename, content):
|
def write_file(self, filename, content):
|
||||||
path = os.path.join(self.tempdir, filename)
|
path = os.path.join(self.tempdir, filename)
|
||||||
with open(path, 'wt') as f:
|
with open(path, 'wt') as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def test_no_default(self):
|
def test_no_default(self):
|
||||||
myfile = self.write_file('my.conf', '')
|
myfile = self.write_file('my.conf', '')
|
||||||
config = WuttaConfig([myfile])
|
config = WuttaConfig([myfile])
|
||||||
self.assertEqual(conf.get_engines(config, 'wuttadb'), {})
|
self.assertEqual(conf.get_engines(config, 'wuttadb'), {})
|
||||||
|
|
||||||
def test_default(self):
|
def test_default(self):
|
||||||
myfile = self.write_file('my.conf', """\
|
myfile = self.write_file('my.conf', """\
|
||||||
[wuttadb]
|
[wuttadb]
|
||||||
default.url = sqlite://
|
default.url = sqlite://
|
||||||
""")
|
""")
|
||||||
config = WuttaConfig([myfile])
|
config = WuttaConfig([myfile])
|
||||||
result = conf.get_engines(config, 'wuttadb')
|
result = conf.get_engines(config, 'wuttadb')
|
||||||
self.assertEqual(len(result), 1)
|
self.assertEqual(len(result), 1)
|
||||||
self.assertIn('default', result)
|
self.assertIn('default', result)
|
||||||
engine = result['default']
|
engine = result['default']
|
||||||
self.assertEqual(engine.dialect.name, 'sqlite')
|
self.assertEqual(engine.dialect.name, 'sqlite')
|
||||||
|
|
||||||
def test_default_fallback(self):
|
def test_default_fallback(self):
|
||||||
myfile = self.write_file('my.conf', """\
|
myfile = self.write_file('my.conf', """\
|
||||||
[wuttadb]
|
[wuttadb]
|
||||||
sqlalchemy.url = sqlite://
|
sqlalchemy.url = sqlite://
|
||||||
""")
|
""")
|
||||||
config = WuttaConfig([myfile])
|
config = WuttaConfig([myfile])
|
||||||
result = conf.get_engines(config, 'wuttadb')
|
result = conf.get_engines(config, 'wuttadb')
|
||||||
self.assertEqual(len(result), 1)
|
self.assertEqual(len(result), 1)
|
||||||
self.assertIn('default', result)
|
self.assertIn('default', result)
|
||||||
engine = result['default']
|
engine = result['default']
|
||||||
self.assertEqual(engine.dialect.name, 'sqlite')
|
self.assertEqual(engine.dialect.name, 'sqlite')
|
||||||
|
|
||||||
def test_other(self):
|
def test_other(self):
|
||||||
myfile = self.write_file('my.conf', """\
|
myfile = self.write_file('my.conf', """\
|
||||||
[otherdb]
|
[otherdb]
|
||||||
keys = first, second
|
keys = first, second
|
||||||
first.url = sqlite://
|
first.url = sqlite://
|
||||||
second.url = sqlite://
|
second.url = sqlite://
|
||||||
""")
|
""")
|
||||||
config = WuttaConfig([myfile])
|
config = WuttaConfig([myfile])
|
||||||
result = conf.get_engines(config, 'otherdb')
|
result = conf.get_engines(config, 'otherdb')
|
||||||
self.assertEqual(len(result), 2)
|
self.assertEqual(len(result), 2)
|
||||||
self.assertIn('first', result)
|
self.assertIn('first', result)
|
||||||
self.assertIn('second', result)
|
self.assertIn('second', result)
|
||||||
|
|
||||||
|
|
||||||
class TestGetSetting(TestCase):
|
class TestGetSetting(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
Session = orm.sessionmaker()
|
Session = orm.sessionmaker()
|
||||||
engine = sa.create_engine('sqlite://')
|
engine = sa.create_engine('sqlite://')
|
||||||
self.session = Session(bind=engine)
|
self.session = Session(bind=engine)
|
||||||
self.session.execute(sa.text("""
|
self.session.execute(sa.text("""
|
||||||
create table setting (
|
create table setting (
|
||||||
name varchar(255) primary key,
|
name varchar(255) primary key,
|
||||||
value text
|
value text
|
||||||
);
|
);
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.session.close()
|
self.session.close()
|
||||||
|
|
||||||
def test_basic_value(self):
|
def test_basic_value(self):
|
||||||
self.session.execute(sa.text("insert into setting values ('foo', 'bar');"))
|
self.session.execute(sa.text("insert into setting values ('foo', 'bar');"))
|
||||||
value = conf.get_setting(self.session, 'foo')
|
value = conf.get_setting(self.session, 'foo')
|
||||||
self.assertEqual(value, 'bar')
|
self.assertEqual(value, 'bar')
|
||||||
|
|
||||||
def test_missing_value(self):
|
def test_missing_value(self):
|
||||||
value = conf.get_setting(self.session, 'foo')
|
value = conf.get_setting(self.session, 'foo')
|
||||||
self.assertIsNone(value)
|
self.assertIsNone(value)
|
||||||
|
|
||||||
|
|
||||||
class TestMakeEngineFromConfig(TestCase):
|
class TestMakeEngineFromConfig(TestCase):
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
engine = conf.make_engine_from_config({
|
engine = conf.make_engine_from_config({
|
||||||
'sqlalchemy.url': 'sqlite://',
|
'sqlalchemy.url': 'sqlite://',
|
||||||
})
|
})
|
||||||
self.assertIsInstance(engine, Engine)
|
self.assertIsInstance(engine, Engine)
|
||||||
|
|
||||||
def test_poolclass(self):
|
def test_poolclass(self):
|
||||||
|
|
||||||
engine = conf.make_engine_from_config({
|
engine = conf.make_engine_from_config({
|
||||||
'sqlalchemy.url': 'sqlite://',
|
'sqlalchemy.url': 'sqlite://',
|
||||||
})
|
})
|
||||||
self.assertNotIsInstance(engine.pool, NullPool)
|
self.assertNotIsInstance(engine.pool, NullPool)
|
||||||
|
|
||||||
engine = conf.make_engine_from_config({
|
engine = conf.make_engine_from_config({
|
||||||
'sqlalchemy.url': 'sqlite://',
|
'sqlalchemy.url': 'sqlite://',
|
||||||
'sqlalchemy.poolclass': 'sqlalchemy.pool:NullPool',
|
'sqlalchemy.poolclass': 'sqlalchemy.pool:NullPool',
|
||||||
})
|
})
|
||||||
self.assertIsInstance(engine.pool, NullPool)
|
self.assertIsInstance(engine.pool, NullPool)
|
||||||
|
|
||||||
def test_pool_pre_ping(self):
|
def test_pool_pre_ping(self):
|
||||||
|
|
||||||
engine = conf.make_engine_from_config({
|
engine = conf.make_engine_from_config({
|
||||||
'sqlalchemy.url': 'sqlite://',
|
'sqlalchemy.url': 'sqlite://',
|
||||||
})
|
})
|
||||||
self.assertFalse(engine.pool._pre_ping)
|
self.assertFalse(engine.pool._pre_ping)
|
||||||
|
|
||||||
engine = conf.make_engine_from_config({
|
engine = conf.make_engine_from_config({
|
||||||
'sqlalchemy.url': 'sqlite://',
|
'sqlalchemy.url': 'sqlite://',
|
||||||
'sqlalchemy.pool_pre_ping': 'true',
|
'sqlalchemy.pool_pre_ping': 'true',
|
||||||
})
|
})
|
||||||
self.assertTrue(engine.pool._pre_ping)
|
self.assertTrue(engine.pool._pre_ping)
|
||||||
|
|
|
@ -3,52 +3,55 @@
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy import orm
|
|
||||||
|
|
||||||
from wuttjamaican.db import sess
|
|
||||||
from wuttjamaican.conf import WuttaConfig
|
from wuttjamaican.conf import WuttaConfig
|
||||||
|
|
||||||
|
try:
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
from wuttjamaican.db import sess
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
|
||||||
class TestShortSession(TestCase):
|
class TestShortSession(TestCase):
|
||||||
|
|
||||||
def test_none(self):
|
def test_none(self):
|
||||||
with sess.short_session() as s:
|
with sess.short_session() as s:
|
||||||
self.assertIsInstance(s, sess.Session.class_)
|
self.assertIsInstance(s, sess.Session.class_)
|
||||||
|
|
||||||
def test_factory(self):
|
def test_factory(self):
|
||||||
TestSession = orm.sessionmaker()
|
TestSession = orm.sessionmaker()
|
||||||
with sess.short_session(factory=TestSession) as s:
|
with sess.short_session(factory=TestSession) as s:
|
||||||
self.assertIsInstance(s, TestSession.class_)
|
self.assertIsInstance(s, TestSession.class_)
|
||||||
|
|
||||||
def test_instance(self):
|
def test_instance(self):
|
||||||
# nb. nothing really happens if we provide the session instance
|
# nb. nothing really happens if we provide the session instance
|
||||||
session = MagicMock()
|
session = MagicMock()
|
||||||
with sess.short_session(session=session) as s:
|
with sess.short_session(session=session) as s:
|
||||||
pass
|
pass
|
||||||
session.commit.assert_not_called()
|
session.commit.assert_not_called()
|
||||||
session.close.assert_not_called()
|
session.close.assert_not_called()
|
||||||
|
|
||||||
def test_config(self):
|
def test_config(self):
|
||||||
config = MagicMock()
|
config = MagicMock()
|
||||||
TestSession = orm.sessionmaker()
|
TestSession = orm.sessionmaker()
|
||||||
config.get_app.return_value.make_session = TestSession
|
config.get_app.return_value.make_session = TestSession
|
||||||
# nb. config may be first arg (or kwarg)
|
# nb. config may be first arg (or kwarg)
|
||||||
with sess.short_session(config) as s:
|
with sess.short_session(config) as s:
|
||||||
self.assertIsInstance(s, TestSession.class_)
|
self.assertIsInstance(s, TestSession.class_)
|
||||||
|
|
||||||
def test_without_commit(self):
|
def test_without_commit(self):
|
||||||
session = MagicMock()
|
session = MagicMock()
|
||||||
TestSession = MagicMock(return_value=session)
|
TestSession = MagicMock(return_value=session)
|
||||||
with sess.short_session(factory=TestSession, commit=False) as s:
|
with sess.short_session(factory=TestSession, commit=False) as s:
|
||||||
pass
|
pass
|
||||||
session.commit.assert_not_called()
|
session.commit.assert_not_called()
|
||||||
session.close.assert_called_once_with()
|
session.close.assert_called_once_with()
|
||||||
|
|
||||||
def test_with_commit(self):
|
def test_with_commit(self):
|
||||||
session = MagicMock()
|
session = MagicMock()
|
||||||
TestSession = MagicMock(return_value=session)
|
TestSession = MagicMock(return_value=session)
|
||||||
with sess.short_session(factory=TestSession, commit=True) as s:
|
with sess.short_session(factory=TestSession, commit=True) as s:
|
||||||
pass
|
pass
|
||||||
session.commit.assert_called_once_with()
|
session.commit.assert_called_once_with()
|
||||||
session.close.assert_called_once_with()
|
session.close.assert_called_once_with()
|
||||||
|
|
|
@ -7,10 +7,9 @@ import warnings
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import pytest
|
||||||
from sqlalchemy import orm
|
|
||||||
|
|
||||||
from wuttjamaican import app, db
|
from wuttjamaican import app
|
||||||
from wuttjamaican.conf import WuttaConfig
|
from wuttjamaican.conf import WuttaConfig
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,6 +45,11 @@ class TestAppHandler(TestCase):
|
||||||
shutil.rmtree(tempdir)
|
shutil.rmtree(tempdir)
|
||||||
|
|
||||||
def test_make_session(self):
|
def test_make_session(self):
|
||||||
|
try:
|
||||||
|
from wuttjamaican import db
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("test is not relevant without sqlalchemy")
|
||||||
|
|
||||||
session = self.app.make_session()
|
session = self.app.make_session()
|
||||||
self.assertIsInstance(session, db.Session.class_)
|
self.assertIsInstance(session, db.Session.class_)
|
||||||
|
|
||||||
|
@ -60,6 +64,12 @@ class TestAppHandler(TestCase):
|
||||||
foo='bar', factory=self.app.make_session)
|
foo='bar', factory=self.app.make_session)
|
||||||
|
|
||||||
def test_get_setting(self):
|
def test_get_setting(self):
|
||||||
|
try:
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("test is not relevant without sqlalchemy")
|
||||||
|
|
||||||
Session = orm.sessionmaker()
|
Session = orm.sessionmaker()
|
||||||
engine = sa.create_engine('sqlite://')
|
engine = sa.create_engine('sqlite://')
|
||||||
session = Session(bind=engine)
|
session = Session(bind=engine)
|
||||||
|
|
|
@ -5,12 +5,10 @@ import os
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import pytest
|
||||||
|
|
||||||
from wuttjamaican import conf
|
from wuttjamaican import conf
|
||||||
from wuttjamaican.exc import ConfigurationError
|
from wuttjamaican.exc import ConfigurationError
|
||||||
from wuttjamaican.db import Session
|
|
||||||
from wuttjamaican.db.conf import make_engine_from_config
|
|
||||||
from wuttjamaican.app import AppHandler
|
from wuttjamaican.app import AppHandler
|
||||||
from wuttjamaican.testing import FileConfigTestCase
|
from wuttjamaican.testing import FileConfigTestCase
|
||||||
|
|
||||||
|
@ -133,6 +131,13 @@ require = %(here)s/first.conf
|
||||||
self.assertEqual(config.get('foo'), 'bar')
|
self.assertEqual(config.get('foo'), 'bar')
|
||||||
|
|
||||||
def test_constructor_db_flags(self):
|
def test_constructor_db_flags(self):
|
||||||
|
try:
|
||||||
|
# nb. we don't need this import but the test will not
|
||||||
|
# behave correctly unless the lib is installed
|
||||||
|
import sqlalchemy
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("test is not relevant without sqlalchemy")
|
||||||
|
|
||||||
myfile = self.write_file('my.conf', """\
|
myfile = self.write_file('my.conf', """\
|
||||||
[wutta.config]
|
[wutta.config]
|
||||||
usedb = true
|
usedb = true
|
||||||
|
@ -155,6 +160,12 @@ preferdb = true
|
||||||
self.assertTrue(config.preferdb)
|
self.assertTrue(config.preferdb)
|
||||||
|
|
||||||
def test_constructor_db_not_supported(self):
|
def test_constructor_db_not_supported(self):
|
||||||
|
try:
|
||||||
|
# nb. we don't need this import but the test will not
|
||||||
|
# behave correctly unless the lib is installed
|
||||||
|
import sqlalchemy
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("test is not relevant without sqlalchemy")
|
||||||
|
|
||||||
# flags are off by default
|
# flags are off by default
|
||||||
config = conf.WuttaConfig()
|
config = conf.WuttaConfig()
|
||||||
|
@ -269,6 +280,12 @@ configure_logging = true
|
||||||
self.assertEqual(config.get('foo', default='bar'), 'bar')
|
self.assertEqual(config.get('foo', default='bar'), 'bar')
|
||||||
|
|
||||||
def test_get_from_db(self):
|
def test_get_from_db(self):
|
||||||
|
try:
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from wuttjamaican.db import Session
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("test is not relevant without sqlalchemy")
|
||||||
|
|
||||||
# minimal config, but at least it needs db cxn info
|
# minimal config, but at least it needs db cxn info
|
||||||
config = conf.WuttaConfig(defaults={'wutta.db.default.url': 'sqlite://'})
|
config = conf.WuttaConfig(defaults={'wutta.db.default.url': 'sqlite://'})
|
||||||
|
|
||||||
|
@ -317,6 +334,11 @@ configure_logging = true
|
||||||
self.assertIn("makin stuff up", str(error))
|
self.assertIn("makin stuff up", str(error))
|
||||||
|
|
||||||
def test_get_preferdb(self):
|
def test_get_preferdb(self):
|
||||||
|
try:
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from wuttjamaican.db import Session
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("test is not relevant without sqlalchemy")
|
||||||
|
|
||||||
# start out with a default value
|
# start out with a default value
|
||||||
config = conf.WuttaConfig(defaults={'wutta.db.default.url': 'sqlite://',
|
config = conf.WuttaConfig(defaults={'wutta.db.default.url': 'sqlite://',
|
||||||
|
@ -403,6 +425,10 @@ configure_logging = true
|
||||||
self.assertIsInstance(app, CustomAppHandler)
|
self.assertIsInstance(app, CustomAppHandler)
|
||||||
|
|
||||||
def test_get_engine_maker(self):
|
def test_get_engine_maker(self):
|
||||||
|
try:
|
||||||
|
from wuttjamaican.db.conf import make_engine_from_config
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("test is not relevant without sqlalchemy")
|
||||||
|
|
||||||
# default func
|
# default func
|
||||||
config = conf.WuttaConfig()
|
config = conf.WuttaConfig()
|
||||||
|
@ -421,7 +447,7 @@ class CustomAppHandler(AppHandler):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def custom_make_engine_from_config(*args, **kwargs):
|
def custom_make_engine_from_config():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
5
tox.ini
5
tox.ini
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
[tox]
|
[tox]
|
||||||
envlist = py36, py37, py38, py39, py310, py311
|
envlist = py36, py37, py38, py39, py310, py311, nodb
|
||||||
|
|
||||||
# TODO: can remove this when we drop py36 support
|
# TODO: can remove this when we drop py36 support
|
||||||
# nb. need this for testing older python versions
|
# nb. need this for testing older python versions
|
||||||
|
@ -15,6 +15,9 @@ commands = pytest {posargs}
|
||||||
# nb. newer coverage is causing segfault for this one, so must avoid that
|
# nb. newer coverage is causing segfault for this one, so must avoid that
|
||||||
deps = coverage<6.5
|
deps = coverage<6.5
|
||||||
|
|
||||||
|
[testenv:nodb]
|
||||||
|
extras = tests
|
||||||
|
|
||||||
[testenv:coverage]
|
[testenv:coverage]
|
||||||
basepython = python3.11
|
basepython = python3.11
|
||||||
extras = db,tests
|
extras = db,tests
|
||||||
|
|
Loading…
Reference in a new issue