1import os 2import sys 3import tempfile 4import unittest 5 6from six import b as b_ 7from webtest import TestApp 8 9import pecan 10from pecan.tests import PecanTestCase 11 12 13__here__ = os.path.dirname(__file__) 14 15 16class TestConf(PecanTestCase): 17 18 def test_update_config_fail_identifier(self): 19 """Fail when naming does not pass correctness""" 20 from pecan import configuration 21 bad_dict = {'bad name': 'value'} 22 self.assertRaises(ValueError, configuration.Config, bad_dict) 23 24 def test_update_set_config(self): 25 """Update an empty configuration with the default values""" 26 from pecan import configuration 27 28 conf = configuration.initconf() 29 conf.update(configuration.conf_from_file(os.path.join( 30 __here__, 31 'config_fixtures/config.py' 32 ))) 33 34 self.assertEqual(conf.app.root, None) 35 self.assertEqual(conf.app.template_path, 'myproject/templates') 36 self.assertEqual(conf.app.static_root, 'public') 37 38 self.assertEqual(conf.server.host, '1.1.1.1') 39 self.assertEqual(conf.server.port, '8081') 40 41 def test_update_set_default_config(self): 42 """Update an empty configuration with the default values""" 43 from pecan import configuration 44 45 conf = configuration.initconf() 46 conf.update(configuration.conf_from_file(os.path.join( 47 __here__, 48 'config_fixtures/empty.py' 49 ))) 50 51 self.assertEqual(conf.app.root, None) 52 self.assertEqual(conf.app.template_path, '') 53 self.assertEqual(conf.app.static_root, 'public') 54 55 self.assertEqual(conf.server.host, '0.0.0.0') 56 self.assertEqual(conf.server.port, '8080') 57 58 def test_update_force_dict(self): 59 """Update an empty configuration with the default values""" 60 from pecan import configuration 61 conf = configuration.initconf() 62 conf.update(configuration.conf_from_file(os.path.join( 63 __here__, 64 'config_fixtures/forcedict.py' 65 ))) 66 67 self.assertEqual(conf.app.root, None) 68 self.assertEqual(conf.app.template_path, '') 69 self.assertEqual(conf.app.static_root, 'public') 70 71 self.assertEqual(conf.server.host, '0.0.0.0') 72 self.assertEqual(conf.server.port, '8080') 73 74 self.assertTrue(isinstance(conf.beaker, dict)) 75 self.assertEqual(conf.beaker['session.key'], 'key') 76 self.assertEqual(conf.beaker['session.type'], 'cookie') 77 self.assertEqual( 78 conf.beaker['session.validate_key'], 79 '1a971a7df182df3e1dec0af7c6913ec7' 80 ) 81 self.assertEqual(conf.beaker.get('__force_dict__'), None) 82 83 def test_update_config_with_dict(self): 84 from pecan import configuration 85 conf = configuration.initconf() 86 d = {'attr': True} 87 conf['attr'] = d 88 self.assertTrue(conf.attr.attr) 89 90 def test_config_repr(self): 91 from pecan import configuration 92 conf = configuration.Config({'a': 1}) 93 self.assertEqual(repr(conf), "Config({'a': 1})") 94 95 def test_config_from_dict(self): 96 from pecan import configuration 97 conf = configuration.conf_from_dict({}) 98 conf['path'] = '%(confdir)s' 99 self.assertTrue(os.path.samefile(conf['path'], os.getcwd())) 100 101 def test_config_from_file(self): 102 from pecan import configuration 103 path = os.path.join( 104 os.path.dirname(__file__), 'config_fixtures', 'config.py' 105 ) 106 configuration.conf_from_file(path) 107 108 def test_config_illegal_ids(self): 109 from pecan import configuration 110 conf = configuration.Config({}) 111 conf.update(configuration.conf_from_file(os.path.join( 112 __here__, 113 'config_fixtures/bad/module_and_underscore.py' 114 ))) 115 self.assertEqual([], list(conf)) 116 117 def test_config_missing_file(self): 118 from pecan import configuration 119 path = ('doesnotexist.py',) 120 configuration.Config({}) 121 self.assertRaises( 122 RuntimeError, 123 configuration.conf_from_file, 124 os.path.join(__here__, 'config_fixtures', *path) 125 ) 126 127 def test_config_missing_file_on_path(self): 128 from pecan import configuration 129 path = ('bad', 'bad', 'doesnotexist.py',) 130 configuration.Config({}) 131 132 self.assertRaises( 133 RuntimeError, 134 configuration.conf_from_file, 135 os.path.join(__here__, 'config_fixtures', *path) 136 ) 137 138 def test_config_with_syntax_error(self): 139 from pecan import configuration 140 with tempfile.NamedTemporaryFile('wb') as f: 141 f.write(b_('\n'.join(['if false', 'var = 3']))) 142 f.flush() 143 configuration.Config({}) 144 145 self.assertRaises( 146 SyntaxError, 147 configuration.conf_from_file, 148 f.name 149 ) 150 151 def test_config_with_non_package_relative_import(self): 152 from pecan import configuration 153 with tempfile.NamedTemporaryFile('wb', suffix='.py') as f: 154 f.write(b_('\n'.join(['from . import variables']))) 155 f.flush() 156 configuration.Config({}) 157 158 try: 159 configuration.conf_from_file(f.name) 160 except (ValueError, SystemError, ImportError) as e: 161 assert 'relative import' in str(e) 162 else: 163 raise AssertionError( 164 "A relative import-related error should have been raised" 165 ) 166 167 def test_config_with_bad_import(self): 168 from pecan import configuration 169 path = ('bad', 'importerror.py') 170 configuration.Config({}) 171 172 self.assertRaises( 173 ImportError, 174 configuration.conf_from_file, 175 os.path.join( 176 __here__, 177 'config_fixtures', 178 *path 179 ) 180 ) 181 182 def test_config_dir(self): 183 from pecan import configuration 184 conf = configuration.Config({}) 185 self.assertEqual([], dir(conf)) 186 conf = configuration.Config({'a': 1}) 187 self.assertEqual(['a'], dir(conf)) 188 189 def test_config_bad_key(self): 190 from pecan import configuration 191 conf = configuration.Config({'a': 1}) 192 assert conf.a == 1 193 self.assertRaises(AttributeError, getattr, conf, 'b') 194 195 def test_config_get_valid_key(self): 196 from pecan import configuration 197 conf = configuration.Config({'a': 1}) 198 assert conf.get('a') == 1 199 200 def test_config_get_invalid_key(self): 201 from pecan import configuration 202 conf = configuration.Config({'a': 1}) 203 assert conf.get('b') is None 204 205 def test_config_get_invalid_key_return_default(self): 206 from pecan import configuration 207 conf = configuration.Config({'a': 1}) 208 assert conf.get('b', True) is True 209 210 def test_config_to_dict(self): 211 from pecan import configuration 212 conf = configuration.initconf() 213 214 assert isinstance(conf, configuration.Config) 215 216 to_dict = conf.to_dict() 217 218 assert isinstance(to_dict, dict) 219 assert to_dict['server']['host'] == '0.0.0.0' 220 assert to_dict['server']['port'] == '8080' 221 assert to_dict['app']['modules'] == [] 222 assert to_dict['app']['root'] is None 223 assert to_dict['app']['static_root'] == 'public' 224 assert to_dict['app']['template_path'] == '' 225 226 def test_config_to_dict_nested(self): 227 from pecan import configuration 228 """have more than one level nesting and convert to dict""" 229 conf = configuration.initconf() 230 nested = {'one': {'two': 2}} 231 conf['nested'] = nested 232 233 to_dict = conf.to_dict() 234 235 assert isinstance(to_dict, dict) 236 assert to_dict['server']['host'] == '0.0.0.0' 237 assert to_dict['server']['port'] == '8080' 238 assert to_dict['app']['modules'] == [] 239 assert to_dict['app']['root'] is None 240 assert to_dict['app']['static_root'] == 'public' 241 assert to_dict['app']['template_path'] == '' 242 assert to_dict['nested']['one']['two'] == 2 243 244 def test_config_to_dict_prefixed(self): 245 from pecan import configuration 246 """Add a prefix for keys""" 247 conf = configuration.initconf() 248 249 assert isinstance(conf, configuration.Config) 250 251 to_dict = conf.to_dict('prefix_') 252 253 assert isinstance(to_dict, dict) 254 assert to_dict['prefix_server']['prefix_host'] == '0.0.0.0' 255 assert to_dict['prefix_server']['prefix_port'] == '8080' 256 assert to_dict['prefix_app']['prefix_modules'] == [] 257 assert to_dict['prefix_app']['prefix_root'] is None 258 assert to_dict['prefix_app']['prefix_static_root'] == 'public' 259 assert to_dict['prefix_app']['prefix_template_path'] == '' 260 261 262class TestGlobalConfig(PecanTestCase): 263 264 def tearDown(self): 265 from pecan import configuration 266 configuration.set_config( 267 dict(configuration.initconf()), 268 overwrite=True 269 ) 270 271 def test_paint_from_dict(self): 272 from pecan import configuration 273 configuration.set_config({'foo': 'bar'}) 274 assert dict(configuration._runtime_conf) != {'foo': 'bar'} 275 self.assertEqual(configuration._runtime_conf.foo, 'bar') 276 277 def test_overwrite_from_dict(self): 278 from pecan import configuration 279 configuration.set_config({'foo': 'bar'}, overwrite=True) 280 assert dict(configuration._runtime_conf) == {'foo': 'bar'} 281 282 def test_paint_from_file(self): 283 from pecan import configuration 284 configuration.set_config(os.path.join( 285 __here__, 286 'config_fixtures/foobar.py' 287 )) 288 assert dict(configuration._runtime_conf) != {'foo': 'bar'} 289 assert configuration._runtime_conf.foo == 'bar' 290 291 def test_overwrite_from_file(self): 292 from pecan import configuration 293 configuration.set_config( 294 os.path.join( 295 __here__, 296 'config_fixtures/foobar.py', 297 ), 298 overwrite=True 299 ) 300 assert dict(configuration._runtime_conf) == {'foo': 'bar'} 301 302 def test_set_config_none_type(self): 303 from pecan import configuration 304 self.assertRaises(RuntimeError, configuration.set_config, None) 305 306 def test_set_config_to_dir(self): 307 from pecan import configuration 308 self.assertRaises(RuntimeError, configuration.set_config, '/') 309 310 311class TestConfFromEnv(PecanTestCase): 312 # 313 # Note that there is a good chance of pollution if ``tearDown`` does not 314 # reset the configuration like this class does. If implementing new classes 315 # for configuration this tearDown **needs to be implemented** 316 # 317 318 def setUp(self): 319 super(TestConfFromEnv, self).setUp() 320 self.addCleanup(self._remove_config_key) 321 322 from pecan import configuration 323 self.get_conf_path_from_env = configuration.get_conf_path_from_env 324 325 def _remove_config_key(self): 326 os.environ.pop('PECAN_CONFIG', None) 327 328 def test_invalid_path(self): 329 os.environ['PECAN_CONFIG'] = '/' 330 msg = "PECAN_CONFIG was set to an invalid path: /" 331 self.assertRaisesRegexp( 332 RuntimeError, 333 msg, 334 self.get_conf_path_from_env 335 ) 336 337 def test_is_not_set(self): 338 msg = "PECAN_CONFIG is not set and " \ 339 "no config file was passed as an argument." 340 self.assertRaisesRegexp( 341 RuntimeError, 342 msg, 343 self.get_conf_path_from_env 344 ) 345 346 def test_return_valid_path(self): 347 __here__ = os.path.abspath(__file__) 348 os.environ['PECAN_CONFIG'] = __here__ 349 assert self.get_conf_path_from_env() == __here__ 350 351 352class TestConfigCleanup(unittest.TestCase): 353 354 def setUp(self): 355 class RootController(object): 356 @pecan.expose() 357 def index(self): 358 return 'Hello, World!' 359 self.app = TestApp(pecan.Pecan(RootController())) 360 361 def tearDown(self): 362 pecan.configuration.set_config(pecan.configuration.DEFAULT, 363 overwrite=True) 364 365 def test_conf_default(self): 366 assert pecan.conf.server.to_dict() == { 367 'port': '8080', 'host': '0.0.0.0' 368 } 369 370 def test_conf_changed(self): 371 pecan.conf.server = pecan.configuration.Config({'port': '80'}) 372 assert pecan.conf.server.to_dict() == {'port': '80'} 373