First commit, basic config (with db) and app handler
this has 100% test coverage and i intend to keep it that way. api docs have a good start but still need narrative. several more things must be added before i can seriously consider incorporating into rattail but this seemed a good save point
This commit is contained in:
		
						commit
						5c3c42d6b3
					
				
					 36 changed files with 3322 additions and 0 deletions
				
			
		
							
								
								
									
										0
									
								
								tests/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								tests/db/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/db/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										132
									
								
								tests/db/test_conf.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								tests/db/test_conf.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,132 @@
 | 
			
		|||
# -*- coding: utf-8; -*-
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import shutil
 | 
			
		||||
import tempfile
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestEngineFromConfig(TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_basic(self):
 | 
			
		||||
        engine = conf.engine_from_config({
 | 
			
		||||
            'sqlalchemy.url': 'sqlite://',
 | 
			
		||||
        })
 | 
			
		||||
        self.assertIsInstance(engine, Engine)
 | 
			
		||||
 | 
			
		||||
    def test_poolclass(self):
 | 
			
		||||
 | 
			
		||||
        engine = conf.engine_from_config({
 | 
			
		||||
            'sqlalchemy.url': 'sqlite://',
 | 
			
		||||
        })
 | 
			
		||||
        self.assertNotIsInstance(engine.pool, NullPool)
 | 
			
		||||
 | 
			
		||||
        engine = conf.engine_from_config({
 | 
			
		||||
            'sqlalchemy.url': 'sqlite://',
 | 
			
		||||
            'sqlalchemy.poolclass': 'sqlalchemy.pool:NullPool',
 | 
			
		||||
        })
 | 
			
		||||
        self.assertIsInstance(engine.pool, NullPool)
 | 
			
		||||
 | 
			
		||||
    def test_pool_pre_ping(self):
 | 
			
		||||
 | 
			
		||||
        engine = conf.engine_from_config({
 | 
			
		||||
            'sqlalchemy.url': 'sqlite://',
 | 
			
		||||
        })
 | 
			
		||||
        self.assertFalse(engine.pool._pre_ping)
 | 
			
		||||
 | 
			
		||||
        engine = conf.engine_from_config({
 | 
			
		||||
            'sqlalchemy.url': 'sqlite://',
 | 
			
		||||
            'sqlalchemy.pool_pre_ping': 'true',
 | 
			
		||||
        })
 | 
			
		||||
        self.assertTrue(engine.pool._pre_ping)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestGetEngines(TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.tempdir = tempfile.mkdtemp()
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
        shutil.rmtree(self.tempdir)
 | 
			
		||||
 | 
			
		||||
    def write_file(self, filename, content):
 | 
			
		||||
        path = os.path.join(self.tempdir, filename)
 | 
			
		||||
        with open(path, 'wt') as f:
 | 
			
		||||
            f.write(content)
 | 
			
		||||
        return path
 | 
			
		||||
 | 
			
		||||
    def test_no_default(self):
 | 
			
		||||
        myfile = self.write_file('my.conf', '')
 | 
			
		||||
        config = WuttaConfig([myfile])
 | 
			
		||||
        self.assertEqual(conf.get_engines(config, 'wuttadb'), {})
 | 
			
		||||
 | 
			
		||||
    def test_default(self):
 | 
			
		||||
        myfile = self.write_file('my.conf', """\
 | 
			
		||||
[wuttadb]
 | 
			
		||||
default.url = sqlite://
 | 
			
		||||
""")
 | 
			
		||||
        config = WuttaConfig([myfile])
 | 
			
		||||
        result = conf.get_engines(config, 'wuttadb')
 | 
			
		||||
        self.assertEqual(len(result), 1)
 | 
			
		||||
        self.assertIn('default', result)
 | 
			
		||||
        engine = result['default']
 | 
			
		||||
        self.assertEqual(engine.dialect.name, 'sqlite')
 | 
			
		||||
 | 
			
		||||
    def test_default_fallback(self):
 | 
			
		||||
        myfile = self.write_file('my.conf', """\
 | 
			
		||||
[wuttadb]
 | 
			
		||||
sqlalchemy.url = sqlite://
 | 
			
		||||
""")
 | 
			
		||||
        config = WuttaConfig([myfile])
 | 
			
		||||
        result = conf.get_engines(config, 'wuttadb')
 | 
			
		||||
        self.assertEqual(len(result), 1)
 | 
			
		||||
        self.assertIn('default', result)
 | 
			
		||||
        engine = result['default']
 | 
			
		||||
        self.assertEqual(engine.dialect.name, 'sqlite')
 | 
			
		||||
 | 
			
		||||
    def test_other(self):
 | 
			
		||||
        myfile = self.write_file('my.conf', """\
 | 
			
		||||
[otherdb]
 | 
			
		||||
keys = first, second
 | 
			
		||||
first.url = sqlite://
 | 
			
		||||
second.url = sqlite://
 | 
			
		||||
""")
 | 
			
		||||
        config = WuttaConfig([myfile])
 | 
			
		||||
        result = conf.get_engines(config, 'otherdb')
 | 
			
		||||
        self.assertEqual(len(result), 2)
 | 
			
		||||
        self.assertIn('first', result)
 | 
			
		||||
        self.assertIn('second', result)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestGetSetting(TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        Session = orm.sessionmaker()
 | 
			
		||||
        engine = sa.create_engine('sqlite://')
 | 
			
		||||
        self.session = Session(bind=engine)
 | 
			
		||||
        self.session.execute(sa.text("""
 | 
			
		||||
        create table setting (
 | 
			
		||||
                name varchar(255) primary key,
 | 
			
		||||
                value text
 | 
			
		||||
        );
 | 
			
		||||
        """))
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
        self.session.close()
 | 
			
		||||
 | 
			
		||||
    def test_basic_value(self):
 | 
			
		||||
        self.session.execute(sa.text("insert into setting values ('foo', 'bar');"))
 | 
			
		||||
        value = conf.get_setting(self.session, 'foo')
 | 
			
		||||
        self.assertEqual(value, 'bar')
 | 
			
		||||
 | 
			
		||||
    def test_missing_value(self):
 | 
			
		||||
        value = conf.get_setting(self.session, 'foo')
 | 
			
		||||
        self.assertIsNone(value)
 | 
			
		||||
							
								
								
									
										54
									
								
								tests/db/test_sess.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								tests/db/test_sess.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
# -*- coding: utf-8; -*-
 | 
			
		||||
 | 
			
		||||
from unittest import TestCase
 | 
			
		||||
from unittest.mock import MagicMock
 | 
			
		||||
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
from sqlalchemy import orm
 | 
			
		||||
 | 
			
		||||
from wuttjamaican.db import sess
 | 
			
		||||
from wuttjamaican.conf import WuttaConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestShortSession(TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_none(self):
 | 
			
		||||
        with sess.short_session() as s:
 | 
			
		||||
            self.assertIsInstance(s, sess.Session.class_)
 | 
			
		||||
 | 
			
		||||
    def test_factory(self):
 | 
			
		||||
        TestSession = orm.sessionmaker()
 | 
			
		||||
        with sess.short_session(factory=TestSession) as s:
 | 
			
		||||
            self.assertIsInstance(s, TestSession.class_)
 | 
			
		||||
 | 
			
		||||
    def test_instance(self):
 | 
			
		||||
        # nb. nothing really happens if we provide the session instance
 | 
			
		||||
        session = MagicMock()
 | 
			
		||||
        with sess.short_session(session=session) as s:
 | 
			
		||||
            pass
 | 
			
		||||
        session.commit.assert_not_called()
 | 
			
		||||
        session.close.assert_not_called()
 | 
			
		||||
 | 
			
		||||
    def test_config(self):
 | 
			
		||||
        config = MagicMock()
 | 
			
		||||
        TestSession = orm.sessionmaker()
 | 
			
		||||
        config.get_app.return_value.make_session = TestSession
 | 
			
		||||
        # nb. config may be first arg (or kwarg)
 | 
			
		||||
        with sess.short_session(config) as s:
 | 
			
		||||
            self.assertIsInstance(s, TestSession.class_)
 | 
			
		||||
 | 
			
		||||
    def test_without_commit(self):
 | 
			
		||||
        session = MagicMock()
 | 
			
		||||
        TestSession = MagicMock(return_value=session)
 | 
			
		||||
        with sess.short_session(factory=TestSession, commit=False) as s:
 | 
			
		||||
            pass
 | 
			
		||||
        session.commit.assert_not_called()
 | 
			
		||||
        session.close.assert_called_once_with()
 | 
			
		||||
 | 
			
		||||
    def test_with_commit(self):
 | 
			
		||||
        session = MagicMock()
 | 
			
		||||
        TestSession = MagicMock(return_value=session)
 | 
			
		||||
        with sess.short_session(factory=TestSession, commit=True) as s:
 | 
			
		||||
            pass
 | 
			
		||||
        session.commit.assert_called_once_with()
 | 
			
		||||
        session.close.assert_called_once_with()
 | 
			
		||||
							
								
								
									
										53
									
								
								tests/test_app.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								tests/test_app.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
# -*- coding: utf-8; -*-
 | 
			
		||||
 | 
			
		||||
from unittest import TestCase
 | 
			
		||||
from unittest.mock import patch, MagicMock
 | 
			
		||||
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
from sqlalchemy import orm
 | 
			
		||||
 | 
			
		||||
from wuttjamaican import app, db
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestAppHandler(TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.config = MagicMock()
 | 
			
		||||
        self.app = app.AppHandler(self.config)
 | 
			
		||||
 | 
			
		||||
    def test_init(self):
 | 
			
		||||
        self.assertIs(self.app.config, self.config)
 | 
			
		||||
        self.assertEqual(self.app.handlers, {})
 | 
			
		||||
 | 
			
		||||
    def test_make_session(self):
 | 
			
		||||
        session = self.app.make_session()
 | 
			
		||||
        self.assertIsInstance(session, db.Session.class_)
 | 
			
		||||
 | 
			
		||||
    def test_short_session(self):
 | 
			
		||||
        short_session = MagicMock()
 | 
			
		||||
        mockdb = MagicMock(short_session=short_session)
 | 
			
		||||
 | 
			
		||||
        with patch.dict('sys.modules', **{'wuttjamaican.db': mockdb}):
 | 
			
		||||
 | 
			
		||||
            with self.app.short_session(foo='bar') as s:
 | 
			
		||||
                short_session.assert_called_once_with(
 | 
			
		||||
                    foo='bar', factory=self.app.make_session)
 | 
			
		||||
 | 
			
		||||
    def test_get_setting(self):
 | 
			
		||||
        Session = orm.sessionmaker()
 | 
			
		||||
        engine = sa.create_engine('sqlite://')
 | 
			
		||||
        session = Session(bind=engine)
 | 
			
		||||
        session.execute(sa.text("""
 | 
			
		||||
        create table setting (
 | 
			
		||||
                name varchar(255) primary key,
 | 
			
		||||
                value text
 | 
			
		||||
        );
 | 
			
		||||
        """))
 | 
			
		||||
        session.commit()
 | 
			
		||||
 | 
			
		||||
        value = self.app.get_setting(session, 'foo')
 | 
			
		||||
        self.assertIsNone(value)
 | 
			
		||||
 | 
			
		||||
        session.execute(sa.text("insert into setting values ('foo', 'bar');"))
 | 
			
		||||
        value = self.app.get_setting(session, 'foo')
 | 
			
		||||
        self.assertEqual(value, 'bar')
 | 
			
		||||
							
								
								
									
										579
									
								
								tests/test_conf.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										579
									
								
								tests/test_conf.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,579 @@
 | 
			
		|||
# -*- coding: utf-8; -*-
 | 
			
		||||
 | 
			
		||||
import configparser
 | 
			
		||||
import os
 | 
			
		||||
import shutil
 | 
			
		||||
import tempfile
 | 
			
		||||
from unittest import TestCase
 | 
			
		||||
from unittest.mock import patch, MagicMock
 | 
			
		||||
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
 | 
			
		||||
from wuttjamaican import conf
 | 
			
		||||
from wuttjamaican.exc import ConfigurationError
 | 
			
		||||
from wuttjamaican.db import Session
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestWuttaConfig(TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.tempdir = tempfile.mkdtemp()
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
        shutil.rmtree(self.tempdir)
 | 
			
		||||
 | 
			
		||||
    def write_file(self, filename, content):
 | 
			
		||||
        path = os.path.join(self.tempdir, filename)
 | 
			
		||||
        with open(path, 'wt') as f:
 | 
			
		||||
            f.write(content)
 | 
			
		||||
        return path
 | 
			
		||||
 | 
			
		||||
    def test_contstructor_basic(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertEqual(config.appname, 'wutta')
 | 
			
		||||
        self.assertEqual(config.files_read, [])
 | 
			
		||||
 | 
			
		||||
    def test_constructor_valid_files(self):
 | 
			
		||||
        myfile = self.write_file('my.conf', '')
 | 
			
		||||
        config = conf.WuttaConfig(files=[myfile])
 | 
			
		||||
        self.assertEqual(len(config.files_read), 1)
 | 
			
		||||
        self.assertEqual(config.files_read[0], myfile)
 | 
			
		||||
 | 
			
		||||
    def test_constructor_missing_files(self):
 | 
			
		||||
        invalid = os.path.join(self.tempdir, 'invalid.conf')
 | 
			
		||||
        self.assertRaises(FileNotFoundError, conf.WuttaConfig, files=[invalid])
 | 
			
		||||
 | 
			
		||||
    def test_constructor_required_files_are_present(self):
 | 
			
		||||
        first = self.write_file('first.conf', """\
 | 
			
		||||
[foo]
 | 
			
		||||
bar = 1
 | 
			
		||||
baz = A
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
        second = self.write_file('second.conf', """\
 | 
			
		||||
[wutta.config]
 | 
			
		||||
require = %(here)s/first.conf
 | 
			
		||||
 | 
			
		||||
[foo]
 | 
			
		||||
baz = B
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
        config = conf.WuttaConfig(files=[second])
 | 
			
		||||
        self.assertEqual(len(config.files_read), 2)
 | 
			
		||||
        # nb. files_read listing is in order of "priority" which is
 | 
			
		||||
        # same the as order in which files were initially read
 | 
			
		||||
        self.assertEqual(config.files_read[0], second)
 | 
			
		||||
        self.assertEqual(config.files_read[1], first)
 | 
			
		||||
        self.assertEqual(config.get('foo.bar'), '1')
 | 
			
		||||
        self.assertEqual(config.get('foo.baz'), 'B')
 | 
			
		||||
 | 
			
		||||
    def test_constructor_required_files_are_missing(self):
 | 
			
		||||
        second = self.write_file('second.conf', """\
 | 
			
		||||
[wutta.config]
 | 
			
		||||
require = %(here)s/first.conf
 | 
			
		||||
 | 
			
		||||
[foo]
 | 
			
		||||
baz = B
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(FileNotFoundError, conf.WuttaConfig, files=[second])
 | 
			
		||||
 | 
			
		||||
    def test_constructor_included_files_are_present(self):
 | 
			
		||||
        first = self.write_file('first.conf', """\
 | 
			
		||||
[foo]
 | 
			
		||||
bar = 1
 | 
			
		||||
baz = A
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
        second = self.write_file('second.conf', """\
 | 
			
		||||
[wutta.config]
 | 
			
		||||
include = %(here)s/first.conf
 | 
			
		||||
 | 
			
		||||
[foo]
 | 
			
		||||
baz = B
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
        config = conf.WuttaConfig(files=[second])
 | 
			
		||||
        self.assertEqual(len(config.files_read), 2)
 | 
			
		||||
        # nb. files_read listing is in order of "priority" which is
 | 
			
		||||
        # same the as order in which files were initially read
 | 
			
		||||
        self.assertEqual(config.files_read[0], second)
 | 
			
		||||
        self.assertEqual(config.files_read[1], first)
 | 
			
		||||
        self.assertEqual(config.get('foo.bar'), '1')
 | 
			
		||||
        self.assertEqual(config.get('foo.baz'), 'B')
 | 
			
		||||
 | 
			
		||||
    def test_constructor_included_files_are_missing(self):
 | 
			
		||||
        second = self.write_file('second.conf', """\
 | 
			
		||||
[wutta.config]
 | 
			
		||||
include = %(here)s/first.conf
 | 
			
		||||
 | 
			
		||||
[foo]
 | 
			
		||||
baz = B
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
        config = conf.WuttaConfig(files=[second])
 | 
			
		||||
        self.assertEqual(len(config.files_read), 1)
 | 
			
		||||
        self.assertEqual(config.files_read[0], second)
 | 
			
		||||
        self.assertIsNone(config.get('foo.bar'))
 | 
			
		||||
        self.assertEqual(config.get('foo.baz'), 'B')
 | 
			
		||||
 | 
			
		||||
    def test_constructor_defaults(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertEqual(config.defaults, {})
 | 
			
		||||
        self.assertIsNone(config.get('foo'))
 | 
			
		||||
 | 
			
		||||
        config = conf.WuttaConfig(defaults={'foo': 'bar'})
 | 
			
		||||
        self.assertEqual(config.defaults, {'foo': 'bar'})
 | 
			
		||||
        self.assertEqual(config.get('foo'), 'bar')
 | 
			
		||||
 | 
			
		||||
    def test_constructor_db_flags(self):
 | 
			
		||||
        myfile = self.write_file('my.conf', """\
 | 
			
		||||
[wutta.config]
 | 
			
		||||
usedb = true
 | 
			
		||||
preferdb = true
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
        # flags are off by default
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertFalse(config.usedb)
 | 
			
		||||
        self.assertFalse(config.preferdb)
 | 
			
		||||
 | 
			
		||||
        # but may override via constructor
 | 
			
		||||
        config = conf.WuttaConfig(usedb=True, preferdb=True)
 | 
			
		||||
        self.assertTrue(config.usedb)
 | 
			
		||||
        self.assertTrue(config.preferdb)
 | 
			
		||||
 | 
			
		||||
        # and also may override via config file
 | 
			
		||||
        config = conf.WuttaConfig(files=[myfile])
 | 
			
		||||
        self.assertTrue(config.usedb)
 | 
			
		||||
        self.assertTrue(config.preferdb)
 | 
			
		||||
 | 
			
		||||
    def test_constructor_db_not_supported(self):
 | 
			
		||||
 | 
			
		||||
        # flags are off by default
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertFalse(config.usedb)
 | 
			
		||||
        self.assertFalse(config.preferdb)
 | 
			
		||||
 | 
			
		||||
        # but caller may enable the flags (if sqlalchemy available)
 | 
			
		||||
        config = conf.WuttaConfig(usedb=True, preferdb=True)
 | 
			
		||||
        self.assertTrue(config.usedb)
 | 
			
		||||
        self.assertTrue(config.preferdb)
 | 
			
		||||
 | 
			
		||||
        # but db flags are force-disabled if sqlalchemy not available,
 | 
			
		||||
        # regardless of flag values caller provides...
 | 
			
		||||
 | 
			
		||||
        orig_import = __import__
 | 
			
		||||
 | 
			
		||||
        def mock_import(name, *args, **kwargs):
 | 
			
		||||
            if name == 'db':
 | 
			
		||||
                raise ImportError
 | 
			
		||||
            return orig_import(name, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        with patch('builtins.__import__', side_effect=mock_import):
 | 
			
		||||
            config = conf.WuttaConfig(usedb=True, preferdb=True)
 | 
			
		||||
            self.assertFalse(config.usedb)
 | 
			
		||||
            self.assertFalse(config.preferdb)
 | 
			
		||||
 | 
			
		||||
    def test_constructor_may_configure_logging(self):
 | 
			
		||||
        myfile = self.write_file('my.conf', """\
 | 
			
		||||
[wutta.config]
 | 
			
		||||
configure_logging = true
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
        with patch.object(conf.WuttaConfig, '_configure_logging') as method:
 | 
			
		||||
 | 
			
		||||
            # no logging config by default
 | 
			
		||||
            config = conf.WuttaConfig()
 | 
			
		||||
            method.assert_not_called()
 | 
			
		||||
 | 
			
		||||
            # but may override via constructor
 | 
			
		||||
            method.reset_mock()
 | 
			
		||||
            config = conf.WuttaConfig(configure_logging=True)
 | 
			
		||||
            method.assert_called_once()
 | 
			
		||||
 | 
			
		||||
            # and also may override via config file
 | 
			
		||||
            method.reset_mock()
 | 
			
		||||
            config = conf.WuttaConfig(files=[myfile])
 | 
			
		||||
            method.assert_called_once()
 | 
			
		||||
 | 
			
		||||
    def test_constructor_configures_logging(self):
 | 
			
		||||
        myfile = self.write_file('my.conf', """\
 | 
			
		||||
[wutta]
 | 
			
		||||
timezone.default = America/Chicago
 | 
			
		||||
 | 
			
		||||
[wutta.config]
 | 
			
		||||
configure_logging = true
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
        with patch('wuttjamaican.conf.logging') as logging:
 | 
			
		||||
 | 
			
		||||
            # basic constructor attempts logging config
 | 
			
		||||
            config = conf.WuttaConfig(configure_logging=True)
 | 
			
		||||
            logging.config.fileConfig.assert_called_once()
 | 
			
		||||
 | 
			
		||||
            # if logging config fails, error is *not* raised
 | 
			
		||||
            logging.config.fileConfig.reset_mock()
 | 
			
		||||
            logging.config.fileConfig.side_effect = configparser.NoSectionError('logging')
 | 
			
		||||
            config = conf.WuttaConfig(configure_logging=True)
 | 
			
		||||
            logging.config.fileConfig.assert_called_once()
 | 
			
		||||
 | 
			
		||||
            # and it works if we specify config file
 | 
			
		||||
            logging.config.fileConfig.reset_mock()
 | 
			
		||||
            config = conf.WuttaConfig(files=[myfile])
 | 
			
		||||
            logging.config.fileConfig.assert_called_once()
 | 
			
		||||
 | 
			
		||||
    def test_setdefault(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
 | 
			
		||||
        # value is empty by default
 | 
			
		||||
        self.assertIsNone(config.get('foo'))
 | 
			
		||||
 | 
			
		||||
        # but we can change that by setting default
 | 
			
		||||
        config.setdefault('foo', 'bar')
 | 
			
		||||
        self.assertEqual(config.get('foo'), 'bar')
 | 
			
		||||
 | 
			
		||||
        # also, value is returned when we set default
 | 
			
		||||
        self.assertIsNone(config.get('baz'))
 | 
			
		||||
        self.assertEqual(config.setdefault('baz', 'blarg'), 'blarg')
 | 
			
		||||
 | 
			
		||||
    def test_get_require_with_default(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertRaises(ValueError, config.get, 'foo', require=True, default='bar')
 | 
			
		||||
 | 
			
		||||
    def test_get_require_missing(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertRaises(ConfigurationError, config.get, 'foo', require=True)
 | 
			
		||||
 | 
			
		||||
    def test_get_with_default(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        # nb. returns None if no default specified
 | 
			
		||||
        self.assertIsNone(config.get('foo'))
 | 
			
		||||
        self.assertEqual(config.get('foo', default='bar'), 'bar')
 | 
			
		||||
 | 
			
		||||
    def test_get_from_db(self):
 | 
			
		||||
        # minimal config, but at least it needs db cxn info
 | 
			
		||||
        config = conf.WuttaConfig(defaults={'wutta.db.default.url': 'sqlite://'})
 | 
			
		||||
 | 
			
		||||
        session = Session()
 | 
			
		||||
 | 
			
		||||
        # setup table for testing
 | 
			
		||||
        session.execute(sa.text("""
 | 
			
		||||
        create table setting (
 | 
			
		||||
                name varchar(255) primary key,
 | 
			
		||||
                value text
 | 
			
		||||
        );
 | 
			
		||||
        """))
 | 
			
		||||
        session.commit()
 | 
			
		||||
 | 
			
		||||
        # setting not yet defined
 | 
			
		||||
        self.assertIsNone(config.get_from_db('foo'))
 | 
			
		||||
 | 
			
		||||
        # insert setting value to db
 | 
			
		||||
        session.execute(sa.text("insert into setting values ('foo', 'bar')"))
 | 
			
		||||
        session.commit()
 | 
			
		||||
 | 
			
		||||
        # now setting returns a value
 | 
			
		||||
        self.assertEqual(config.get_from_db('foo'), 'bar')
 | 
			
		||||
 | 
			
		||||
        # also works if we provide the session
 | 
			
		||||
        self.assertEqual(config.get_from_db('foo', session=session), 'bar')
 | 
			
		||||
 | 
			
		||||
        session.close()
 | 
			
		||||
 | 
			
		||||
    def test_get_default(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertIsNone(config.get('foo'))
 | 
			
		||||
        self.assertEqual(config.get('foo', default='bar'), 'bar')
 | 
			
		||||
 | 
			
		||||
    def test_get_require(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertIsNone(config.get('foo'))
 | 
			
		||||
        self.assertRaises(ConfigurationError, config.get, 'foo', require=True)
 | 
			
		||||
 | 
			
		||||
    def test_get_require_message(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertIsNone(config.get('foo'))
 | 
			
		||||
        try:
 | 
			
		||||
            config.get('foo', require=True, message="makin stuff up")
 | 
			
		||||
        except ConfigurationError as error:
 | 
			
		||||
            self.assertIn("makin stuff up", str(error))
 | 
			
		||||
 | 
			
		||||
    def test_get_preferdb(self):
 | 
			
		||||
 | 
			
		||||
        # start out with a default value
 | 
			
		||||
        config = conf.WuttaConfig(defaults={'wutta.db.default.url': 'sqlite://',
 | 
			
		||||
                                            'foo': 'bar'})
 | 
			
		||||
        self.assertEqual(config.get('foo'), 'bar')
 | 
			
		||||
 | 
			
		||||
        session = Session()
 | 
			
		||||
 | 
			
		||||
        # setup table for testing
 | 
			
		||||
        session.execute(sa.text("""
 | 
			
		||||
        create table setting (
 | 
			
		||||
                name varchar(255) primary key,
 | 
			
		||||
                value text
 | 
			
		||||
        );
 | 
			
		||||
        """))
 | 
			
		||||
        session.execute(sa.text("insert into setting values ('foo', 'baz')"))
 | 
			
		||||
        session.commit()
 | 
			
		||||
 | 
			
		||||
        # we did not specify usedb=True, so original default is still returned
 | 
			
		||||
        self.assertFalse(config.usedb)
 | 
			
		||||
        self.assertEqual(config.get('foo'), 'bar')
 | 
			
		||||
 | 
			
		||||
        # usedb but no preferdb means original default is still returned
 | 
			
		||||
        self.assertEqual(config.get('foo', usedb=True), 'bar')
 | 
			
		||||
 | 
			
		||||
        # but preferdb should mean newer db value is returned
 | 
			
		||||
        self.assertEqual(config.get('foo', usedb=True, preferdb=True), 'baz')
 | 
			
		||||
 | 
			
		||||
        # try a different key to ensure db fallback works if no default present
 | 
			
		||||
        session.execute(sa.text("insert into setting values ('blarg', 'blitz')"))
 | 
			
		||||
        session.commit()
 | 
			
		||||
        self.assertIsNone(config.get('blarg'))
 | 
			
		||||
        self.assertEqual(config.get('blarg', usedb=True), 'blitz')
 | 
			
		||||
 | 
			
		||||
        session.close()
 | 
			
		||||
 | 
			
		||||
    def test_require(self):
 | 
			
		||||
        config = conf.WuttaConfig()
 | 
			
		||||
        self.assertRaises(ConfigurationError, config.require, 'foo')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestGenericDefaultFiles(TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_linux(self):
 | 
			
		||||
        files = conf.generic_default_files('wuttatest')
 | 
			
		||||
        self.assertIsInstance(files, list)
 | 
			
		||||
        self.assertTrue(len(files) > 1)
 | 
			
		||||
        self.assertIn('/etc/wuttatest.conf', files)
 | 
			
		||||
 | 
			
		||||
    def test_win32(self):
 | 
			
		||||
        win32com = MagicMock()
 | 
			
		||||
        win32com.shell.SHGetSpecialFolderPath.return_value = r'C:' + os.sep
 | 
			
		||||
        with patch.dict('sys.modules', **{'win32com.shell': win32com}):
 | 
			
		||||
            with patch('wuttjamaican.conf.sys', platform='win32'):
 | 
			
		||||
 | 
			
		||||
                files = conf.generic_default_files('wuttatest')
 | 
			
		||||
                self.assertIsInstance(files, list)
 | 
			
		||||
                self.assertTrue(len(files) > 1)
 | 
			
		||||
                self.assertIn(os.path.join('C:', 'wuttatest.conf'), files)
 | 
			
		||||
 | 
			
		||||
    def test_win32_broken(self):
 | 
			
		||||
        orig_import = __import__
 | 
			
		||||
 | 
			
		||||
        def mock_import(name, *args, **kwargs):
 | 
			
		||||
            if name == 'win32com.shell':
 | 
			
		||||
                raise ImportError
 | 
			
		||||
            return orig_import(name, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        with patch('builtins.__import__', side_effect=mock_import):
 | 
			
		||||
            with patch('wuttjamaican.conf.sys', platform='win32'):
 | 
			
		||||
 | 
			
		||||
                files = conf.generic_default_files('wuttatest')
 | 
			
		||||
                self.assertIsInstance(files, list)
 | 
			
		||||
                self.assertEqual(len(files), 0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestMakeConfig(TestCase):
 | 
			
		||||
 | 
			
		||||
    # nb. we use appname='wuttatest' in this suite to avoid any
 | 
			
		||||
    # "valid" default config files, env vars etc. which may be present
 | 
			
		||||
    # on the dev machine
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.tempdir = tempfile.mkdtemp()
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
        shutil.rmtree(self.tempdir)
 | 
			
		||||
 | 
			
		||||
    def write_file(self, filename, content):
 | 
			
		||||
        path = os.path.join(self.tempdir, filename)
 | 
			
		||||
        with open(path, 'wt') as f:
 | 
			
		||||
            f.write(content)
 | 
			
		||||
        return path
 | 
			
		||||
 | 
			
		||||
    def test_generic_default_files(self):
 | 
			
		||||
        generic = self.write_file('generic.conf', '')
 | 
			
		||||
 | 
			
		||||
        with patch('wuttjamaican.conf.generic_default_files') as generic_default_files:
 | 
			
		||||
            with patch('wuttjamaican.conf.WuttaConfig') as WuttaConfig:
 | 
			
		||||
 | 
			
		||||
                # generic files are used if nothing is specified
 | 
			
		||||
                generic_default_files.return_value = [generic]
 | 
			
		||||
                config = conf.make_config(appname='wuttatest')
 | 
			
		||||
                generic_default_files.assert_called_once_with('wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([generic], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # make sure empty defaults works too
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                generic_default_files.return_value = []
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wuttatest')
 | 
			
		||||
                generic_default_files.assert_called_once_with('wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
    def test_specify_default_files(self):
 | 
			
		||||
        generic = self.write_file('generic.conf', '')
 | 
			
		||||
        myfile = self.write_file('my.conf', '')
 | 
			
		||||
 | 
			
		||||
        with patch('wuttjamaican.conf.generic_default_files') as generic_default_files:
 | 
			
		||||
            with patch('wuttjamaican.conf.WuttaConfig') as WuttaConfig:
 | 
			
		||||
 | 
			
		||||
                # generic defaults are used if nothing specified
 | 
			
		||||
                generic_default_files.return_value = [generic]
 | 
			
		||||
                config = conf.make_config(appname='wuttatest')
 | 
			
		||||
                generic_default_files.assert_called_once_with('wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([generic], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # can specify single default file
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wuttatest', default_files=myfile)
 | 
			
		||||
                generic_default_files.assert_not_called()
 | 
			
		||||
                WuttaConfig.assert_called_once_with([myfile], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # can specify default files as list
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wuttatest', default_files=[myfile])
 | 
			
		||||
                generic_default_files.assert_not_called()
 | 
			
		||||
                WuttaConfig.assert_called_once_with([myfile], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # can specify default files as callable
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wuttatest', default_files=lambda appname: [myfile])
 | 
			
		||||
                generic_default_files.assert_not_called()
 | 
			
		||||
                WuttaConfig.assert_called_once_with([myfile], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
    def test_specify_plus_files(self):
 | 
			
		||||
        generic = self.write_file('generic.conf', '')
 | 
			
		||||
        myfile = self.write_file('my.conf', '')
 | 
			
		||||
 | 
			
		||||
        with patch('wuttjamaican.conf.generic_default_files') as generic_default_files:
 | 
			
		||||
            with patch('wuttjamaican.conf.WuttaConfig') as WuttaConfig:
 | 
			
		||||
 | 
			
		||||
                generic_default_files.return_value = [generic]
 | 
			
		||||
 | 
			
		||||
                # no plus files by default
 | 
			
		||||
                config = conf.make_config(appname='wuttatest')
 | 
			
		||||
                generic_default_files.assert_called_once_with('wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([generic], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # can specify single plus file
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wuttatest', plus_files=myfile)
 | 
			
		||||
                generic_default_files.assert_called_once_with('wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([generic, myfile], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # can specify plus files as list
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wuttatest', plus_files=[myfile])
 | 
			
		||||
                generic_default_files.assert_called_once_with('wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([generic, myfile], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # can specify plus files via env
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wuttatest',
 | 
			
		||||
                                          env={'WUTTATEST_CONFIG_PLUS_FILES': myfile})
 | 
			
		||||
                generic_default_files.assert_called_once_with('wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([generic, myfile], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
    def test_specify_primary_files(self):
 | 
			
		||||
        generic = self.write_file('generic.conf', '')
 | 
			
		||||
        myfile = self.write_file('my.conf', '')
 | 
			
		||||
 | 
			
		||||
        with patch('wuttjamaican.conf.generic_default_files') as generic_default_files:
 | 
			
		||||
            with patch('wuttjamaican.conf.WuttaConfig') as WuttaConfig:
 | 
			
		||||
 | 
			
		||||
                generic_default_files.return_value = [generic]
 | 
			
		||||
 | 
			
		||||
                # generic files by default
 | 
			
		||||
                config = conf.make_config(appname='wuttatest')
 | 
			
		||||
                generic_default_files.assert_called_once_with('wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([generic], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # can specify single primary file (nb. no default files)
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(myfile, appname='wuttatest')
 | 
			
		||||
                generic_default_files.assert_not_called()
 | 
			
		||||
                WuttaConfig.assert_called_once_with([myfile], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # can specify primary files as list
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config([myfile], appname='wuttatest')
 | 
			
		||||
                generic_default_files.assert_not_called()
 | 
			
		||||
                WuttaConfig.assert_called_once_with([myfile], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
                # can specify primary files via env
 | 
			
		||||
                generic_default_files.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wuttatest',
 | 
			
		||||
                                          env={'WUTTATEST_CONFIG_FILES': myfile})
 | 
			
		||||
                generic_default_files.assert_not_called()
 | 
			
		||||
                WuttaConfig.assert_called_once_with([myfile], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
 | 
			
		||||
    def test_extensions(self):
 | 
			
		||||
        generic = self.write_file('generic.conf', '')
 | 
			
		||||
        myfile = self.write_file('my.conf', '')
 | 
			
		||||
 | 
			
		||||
        with patch('wuttjamaican.conf.WuttaConfig') as WuttaConfig:
 | 
			
		||||
            with patch('wuttjamaican.conf.load_entry_points') as load_entry_points:
 | 
			
		||||
 | 
			
		||||
                # no entry points loaded if extend=False
 | 
			
		||||
                config = conf.make_config(appname='wuttatest', extend=False)
 | 
			
		||||
                WuttaConfig.assert_called_once_with([], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
                load_entry_points.assert_not_called()
 | 
			
		||||
 | 
			
		||||
                # confirm entry points for default appname
 | 
			
		||||
                load_entry_points.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wutta')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([], appname='wutta',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
                load_entry_points.assert_called_once_with('wutta.config.extensions')
 | 
			
		||||
 | 
			
		||||
                # confirm entry points for custom appname
 | 
			
		||||
                load_entry_points.reset_mock()
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                config = conf.make_config(appname='wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
                load_entry_points.assert_called_once_with('wuttatest.config.extensions')
 | 
			
		||||
 | 
			
		||||
                # confirm extensions are invoked
 | 
			
		||||
                load_entry_points.reset_mock()
 | 
			
		||||
                foo_obj = MagicMock()
 | 
			
		||||
                foo_cls = MagicMock(return_value=foo_obj)
 | 
			
		||||
                load_entry_points.return_value = {'foo': foo_cls}
 | 
			
		||||
                WuttaConfig.reset_mock()
 | 
			
		||||
                testconfig = MagicMock()
 | 
			
		||||
                WuttaConfig.return_value = testconfig
 | 
			
		||||
                config = conf.make_config(appname='wuttatest')
 | 
			
		||||
                WuttaConfig.assert_called_once_with([], appname='wuttatest',
 | 
			
		||||
                                                    usedb=None, preferdb=None)
 | 
			
		||||
                load_entry_points.assert_called_once_with('wuttatest.config.extensions')
 | 
			
		||||
                foo_cls.assert_called_once_with()
 | 
			
		||||
                foo_obj.configure.assert_called_once_with(testconfig)
 | 
			
		||||
							
								
								
									
										216
									
								
								tests/test_util.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								tests/test_util.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,216 @@
 | 
			
		|||
# -*- coding: utf-8; -*-
 | 
			
		||||
 | 
			
		||||
from unittest import TestCase
 | 
			
		||||
from unittest.mock import patch, MagicMock
 | 
			
		||||
 | 
			
		||||
# nb. setuptools must be imported before distutils, else weird
 | 
			
		||||
# behavior may ensue within some of the tests below
 | 
			
		||||
import setuptools
 | 
			
		||||
 | 
			
		||||
from wuttjamaican import util
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestLoadEntryPoints(TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_empty(self):
 | 
			
		||||
        # empty set returned for unknown group
 | 
			
		||||
        result = util.load_entry_points('this_should_never_exist!!!!!!')
 | 
			
		||||
        self.assertEqual(result, {})
 | 
			
		||||
 | 
			
		||||
    def test_basic(self):
 | 
			
		||||
        # load some entry points which should "always" be present,
 | 
			
		||||
        # even in a testing environment.  basic sanity check
 | 
			
		||||
        result = util.load_entry_points('console_scripts')
 | 
			
		||||
        self.assertTrue(len(result) >= 1)
 | 
			
		||||
        self.assertIn('pip', result)
 | 
			
		||||
 | 
			
		||||
    def test_error(self):
 | 
			
		||||
 | 
			
		||||
        entry_point = MagicMock()
 | 
			
		||||
        entry_point.load.side_effect = NotImplementedError("just a testin")
 | 
			
		||||
 | 
			
		||||
        entry_points = MagicMock()
 | 
			
		||||
        entry_points.select.return_value = [entry_point]
 | 
			
		||||
 | 
			
		||||
        importlib = MagicMock()
 | 
			
		||||
        importlib.metadata.entry_points.return_value = entry_points
 | 
			
		||||
 | 
			
		||||
        with patch.dict('sys.modules', **{'importlib': importlib}):
 | 
			
		||||
 | 
			
		||||
            # empty set returned if errors suppressed
 | 
			
		||||
            result = util.load_entry_points('wuttatest.thingers', ignore_errors=True)
 | 
			
		||||
            self.assertEqual(result, {})
 | 
			
		||||
            importlib.metadata.entry_points.assert_called_once_with()
 | 
			
		||||
            entry_points.select.assert_called_once_with(group='wuttatest.thingers')
 | 
			
		||||
            entry_point.load.assert_called_once_with()
 | 
			
		||||
 | 
			
		||||
            # error is raised, if not suppressed
 | 
			
		||||
            importlib.metadata.entry_points.reset_mock()
 | 
			
		||||
            entry_points.select.reset_mock()
 | 
			
		||||
            entry_point.load.reset_mock()
 | 
			
		||||
            self.assertRaises(NotImplementedError, util.load_entry_points, 'wuttatest.thingers')
 | 
			
		||||
            importlib.metadata.entry_points.assert_called_once_with()
 | 
			
		||||
            entry_points.select.assert_called_once_with(group='wuttatest.thingers')
 | 
			
		||||
            entry_point.load.assert_called_once_with()
 | 
			
		||||
 | 
			
		||||
    def test_pkg_resources_empty(self):
 | 
			
		||||
        orig_import = __import__
 | 
			
		||||
 | 
			
		||||
        def mock_import(name, *args, **kwargs):
 | 
			
		||||
            if name == 'importlib.metadata':
 | 
			
		||||
                raise ImportError
 | 
			
		||||
            return orig_import(name, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        with patch('builtins.__import__', side_effect=mock_import):
 | 
			
		||||
 | 
			
		||||
            # empty set returned for unknown group
 | 
			
		||||
            result = util.load_entry_points('this_should_never_exist!!!!!!')
 | 
			
		||||
            self.assertEqual(result, {})
 | 
			
		||||
 | 
			
		||||
    def test_pkg_resources_basic(self):
 | 
			
		||||
        orig_import = __import__
 | 
			
		||||
 | 
			
		||||
        def mock_import(name, *args, **kwargs):
 | 
			
		||||
            if name == 'importlib.metadata':
 | 
			
		||||
                raise ImportError
 | 
			
		||||
            return orig_import(name, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        with patch('builtins.__import__', side_effect=mock_import):
 | 
			
		||||
 | 
			
		||||
            # load some entry points which should "always" be present,
 | 
			
		||||
            # even in a testing environment.  basic sanity check
 | 
			
		||||
            result = util.load_entry_points('console_scripts')
 | 
			
		||||
            self.assertTrue(len(result) >= 1)
 | 
			
		||||
            self.assertIn('pip', result)
 | 
			
		||||
 | 
			
		||||
    def test_pkg_resources_error(self):
 | 
			
		||||
        orig_import = __import__
 | 
			
		||||
 | 
			
		||||
        entry_point = MagicMock()
 | 
			
		||||
        entry_point.load.side_effect = NotImplementedError("just a testin")
 | 
			
		||||
 | 
			
		||||
        iter_entry_points = MagicMock(return_value=[entry_point])
 | 
			
		||||
        pkg_resources = MagicMock(iter_entry_points=iter_entry_points)
 | 
			
		||||
 | 
			
		||||
        def mock_import(name, *args, **kwargs):
 | 
			
		||||
            if name == 'importlib.metadata':
 | 
			
		||||
                raise ImportError
 | 
			
		||||
            return orig_import(name, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
        with patch('builtins.__import__', side_effect=mock_import):
 | 
			
		||||
            with patch.dict('sys.modules', **{'pkg_resources': pkg_resources}):
 | 
			
		||||
 | 
			
		||||
                # empty set returned if errors suppressed
 | 
			
		||||
                result = util.load_entry_points('wuttatest.thingers', ignore_errors=True)
 | 
			
		||||
                self.assertEqual(result, {})
 | 
			
		||||
                iter_entry_points.assert_called_once_with('wuttatest.thingers')
 | 
			
		||||
                entry_point.load.assert_called_once_with()
 | 
			
		||||
 | 
			
		||||
                # error is raised, if not suppressed
 | 
			
		||||
                iter_entry_points.reset_mock()
 | 
			
		||||
                entry_point.load.reset_mock()
 | 
			
		||||
                self.assertRaises(NotImplementedError, util.load_entry_points, 'wuttatest.thingers')
 | 
			
		||||
                iter_entry_points.assert_called_once_with('wuttatest.thingers')
 | 
			
		||||
                entry_point.load.assert_called_once_with()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestLoadObject(TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_missing_spec(self):
 | 
			
		||||
        self.assertRaises(ValueError, util.load_object, None)
 | 
			
		||||
 | 
			
		||||
    def test_basic(self):
 | 
			
		||||
        result = util.load_object('unittest:TestCase')
 | 
			
		||||
        self.assertIs(result, TestCase)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestParseBool(TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_null(self):
 | 
			
		||||
        self.assertIsNone(util.parse_bool(None))
 | 
			
		||||
 | 
			
		||||
    def test_bool(self):
 | 
			
		||||
        self.assertTrue(util.parse_bool(True))
 | 
			
		||||
        self.assertFalse(util.parse_bool(False))
 | 
			
		||||
 | 
			
		||||
    def test_string_true(self):
 | 
			
		||||
        self.assertTrue(util.parse_bool('true'))
 | 
			
		||||
        self.assertTrue(util.parse_bool('yes'))
 | 
			
		||||
        self.assertTrue(util.parse_bool('y'))
 | 
			
		||||
        self.assertTrue(util.parse_bool('on'))
 | 
			
		||||
        self.assertTrue(util.parse_bool('1'))
 | 
			
		||||
 | 
			
		||||
    def test_string_false(self):
 | 
			
		||||
        self.assertFalse(util.parse_bool('false'))
 | 
			
		||||
        self.assertFalse(util.parse_bool('no'))
 | 
			
		||||
        self.assertFalse(util.parse_bool('n'))
 | 
			
		||||
        self.assertFalse(util.parse_bool('off'))
 | 
			
		||||
        self.assertFalse(util.parse_bool('0'))
 | 
			
		||||
        # nb. assume false for unrecognized input
 | 
			
		||||
        self.assertFalse(util.parse_bool('whatever-else'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestParseList(TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_null(self):
 | 
			
		||||
        value = util.parse_list(None)
 | 
			
		||||
        self.assertIsInstance(value, list)
 | 
			
		||||
        self.assertEqual(len(value), 0)
 | 
			
		||||
 | 
			
		||||
    def test_single_value(self):
 | 
			
		||||
        value = util.parse_list('foo')
 | 
			
		||||
        self.assertEqual(len(value), 1)
 | 
			
		||||
        self.assertEqual(value[0], 'foo')
 | 
			
		||||
 | 
			
		||||
    def test_single_value_padded_by_spaces(self):
 | 
			
		||||
        value = util.parse_list('   foo   ')
 | 
			
		||||
        self.assertEqual(len(value), 1)
 | 
			
		||||
        self.assertEqual(value[0], 'foo')
 | 
			
		||||
 | 
			
		||||
    def test_slash_is_not_a_separator(self):
 | 
			
		||||
        value = util.parse_list('/dev/null')
 | 
			
		||||
        self.assertEqual(len(value), 1)
 | 
			
		||||
        self.assertEqual(value[0], '/dev/null')
 | 
			
		||||
 | 
			
		||||
    def test_multiple_values_separated_by_whitespace(self):
 | 
			
		||||
        value = util.parse_list('foo bar baz')
 | 
			
		||||
        self.assertEqual(len(value), 3)
 | 
			
		||||
        self.assertEqual(value[0], 'foo')
 | 
			
		||||
        self.assertEqual(value[1], 'bar')
 | 
			
		||||
        self.assertEqual(value[2], 'baz')
 | 
			
		||||
 | 
			
		||||
    def test_multiple_values_separated_by_commas(self):
 | 
			
		||||
        value = util.parse_list('foo,bar,baz')
 | 
			
		||||
        self.assertEqual(len(value), 3)
 | 
			
		||||
        self.assertEqual(value[0], 'foo')
 | 
			
		||||
        self.assertEqual(value[1], 'bar')
 | 
			
		||||
        self.assertEqual(value[2], 'baz')
 | 
			
		||||
 | 
			
		||||
    def test_multiple_values_separated_by_whitespace_and_commas(self):
 | 
			
		||||
        value = util.parse_list('  foo,   bar   baz')
 | 
			
		||||
        self.assertEqual(len(value), 3)
 | 
			
		||||
        self.assertEqual(value[0], 'foo')
 | 
			
		||||
        self.assertEqual(value[1], 'bar')
 | 
			
		||||
        self.assertEqual(value[2], 'baz')
 | 
			
		||||
 | 
			
		||||
    def test_multiple_values_separated_by_whitespace_and_commas_with_some_quoting(self):
 | 
			
		||||
        value = util.parse_list("""
 | 
			
		||||
        foo
 | 
			
		||||
        "C:\\some path\\with spaces\\and, a comma",
 | 
			
		||||
        baz
 | 
			
		||||
        """)
 | 
			
		||||
        self.assertEqual(len(value), 3)
 | 
			
		||||
        self.assertEqual(value[0], 'foo')
 | 
			
		||||
        self.assertEqual(value[1], 'C:\\some path\\with spaces\\and, a comma')
 | 
			
		||||
        self.assertEqual(value[2], 'baz')
 | 
			
		||||
 | 
			
		||||
    def test_multiple_values_separated_by_whitespace_and_commas_with_single_quotes(self):
 | 
			
		||||
        value = util.parse_list("""
 | 
			
		||||
        foo
 | 
			
		||||
        'C:\\some path\\with spaces\\and, a comma',
 | 
			
		||||
        baz
 | 
			
		||||
        """)
 | 
			
		||||
        self.assertEqual(len(value), 3)
 | 
			
		||||
        self.assertEqual(value[0], 'foo')
 | 
			
		||||
        self.assertEqual(value[1], 'C:\\some path\\with spaces\\and, a comma')
 | 
			
		||||
        self.assertEqual(value[2], 'baz')
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue