495
495
def test_signatures_default(self):
496
496
my_config = config.Config()
497
self.assertFalse(my_config.signature_needed())
498
self.applyDeprecated(deprecated_in((2, 5, 0)),
499
my_config.signature_needed))
498
500
self.assertEqual(config.CHECK_IF_POSSIBLE,
499
my_config.signature_checking())
501
self.applyDeprecated(deprecated_in((2, 5, 0)),
502
my_config.signature_checking))
500
503
self.assertEqual(config.SIGN_WHEN_REQUIRED,
501
my_config.signing_policy())
504
self.applyDeprecated(deprecated_in((2, 5, 0)),
505
my_config.signing_policy))
503
507
def test_signatures_template_method(self):
504
508
my_config = InstrumentedConfig()
505
self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
509
self.assertEqual(config.CHECK_NEVER,
510
self.applyDeprecated(deprecated_in((2, 5, 0)),
511
my_config.signature_checking))
506
512
self.assertEqual(['_get_signature_checking'], my_config._calls)
508
514
def test_signatures_template_method_none(self):
509
515
my_config = InstrumentedConfig()
510
516
my_config._signatures = None
511
517
self.assertEqual(config.CHECK_IF_POSSIBLE,
512
my_config.signature_checking())
518
self.applyDeprecated(deprecated_in((2, 5, 0)),
519
my_config.signature_checking))
513
520
self.assertEqual(['_get_signature_checking'], my_config._calls)
515
522
def test_gpg_signing_command_default(self):
516
523
my_config = config.Config()
517
self.assertEqual('gpg', my_config.gpg_signing_command())
524
self.assertEqual('gpg',
525
self.applyDeprecated(deprecated_in((2, 5, 0)),
526
my_config.gpg_signing_command))
519
528
def test_get_user_option_default(self):
520
529
my_config = config.Config()
1229
1247
def test_signatures_always(self):
1230
1248
my_config = config.GlobalConfig.from_string(sample_always_signatures)
1231
1249
self.assertEqual(config.CHECK_NEVER,
1232
my_config.signature_checking())
1250
self.applyDeprecated(deprecated_in((2, 5, 0)),
1251
my_config.signature_checking))
1233
1252
self.assertEqual(config.SIGN_ALWAYS,
1234
my_config.signing_policy())
1235
self.assertEqual(True, my_config.signature_needed())
1253
self.applyDeprecated(deprecated_in((2, 5, 0)),
1254
my_config.signing_policy))
1255
self.assertEqual(True,
1256
self.applyDeprecated(deprecated_in((2, 5, 0)),
1257
my_config.signature_needed))
1237
1259
def test_signatures_if_possible(self):
1238
1260
my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
1239
1261
self.assertEqual(config.CHECK_NEVER,
1240
my_config.signature_checking())
1262
self.applyDeprecated(deprecated_in((2, 5, 0)),
1263
my_config.signature_checking))
1241
1264
self.assertEqual(config.SIGN_WHEN_REQUIRED,
1242
my_config.signing_policy())
1243
self.assertEqual(False, my_config.signature_needed())
1265
self.applyDeprecated(deprecated_in((2, 5, 0)),
1266
my_config.signing_policy))
1267
self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
1268
my_config.signature_needed))
1245
1270
def test_signatures_ignore(self):
1246
1271
my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
1247
1272
self.assertEqual(config.CHECK_ALWAYS,
1248
my_config.signature_checking())
1273
self.applyDeprecated(deprecated_in((2, 5, 0)),
1274
my_config.signature_checking))
1249
1275
self.assertEqual(config.SIGN_NEVER,
1250
my_config.signing_policy())
1251
self.assertEqual(False, my_config.signature_needed())
1276
self.applyDeprecated(deprecated_in((2, 5, 0)),
1277
my_config.signing_policy))
1278
self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
1279
my_config.signature_needed))
1253
1281
def _get_sample_config(self):
1254
1282
my_config = config.GlobalConfig.from_string(sample_config_text)
1532
1573
self.get_branch_config('http://www.example.com',
1533
1574
global_config=sample_ignore_signatures)
1534
1575
self.assertEqual(config.CHECK_ALWAYS,
1535
self.my_config.signature_checking())
1576
self.applyDeprecated(deprecated_in((2, 5, 0)),
1577
self.my_config.signature_checking))
1536
1578
self.assertEqual(config.SIGN_NEVER,
1537
self.my_config.signing_policy())
1579
self.applyDeprecated(deprecated_in((2, 5, 0)),
1580
self.my_config.signing_policy))
1539
1582
def test_signatures_never(self):
1540
1583
self.get_branch_config('/a/c')
1541
1584
self.assertEqual(config.CHECK_NEVER,
1542
self.my_config.signature_checking())
1585
self.applyDeprecated(deprecated_in((2, 5, 0)),
1586
self.my_config.signature_checking))
1544
1588
def test_signatures_when_available(self):
1545
1589
self.get_branch_config('/a/', global_config=sample_ignore_signatures)
1546
1590
self.assertEqual(config.CHECK_IF_POSSIBLE,
1547
self.my_config.signature_checking())
1591
self.applyDeprecated(deprecated_in((2, 5, 0)),
1592
self.my_config.signature_checking))
1549
1594
def test_signatures_always(self):
1550
1595
self.get_branch_config('/b')
1551
1596
self.assertEqual(config.CHECK_ALWAYS,
1552
self.my_config.signature_checking())
1597
self.applyDeprecated(deprecated_in((2, 5, 0)),
1598
self.my_config.signature_checking))
1554
1600
def test_gpg_signing_command(self):
1555
1601
self.get_branch_config('/b')
1556
self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
1602
self.assertEqual("gnome-gpg",
1603
self.applyDeprecated(deprecated_in((2, 5, 0)),
1604
self.my_config.gpg_signing_command))
1558
1606
def test_gpg_signing_command_missing(self):
1559
1607
self.get_branch_config('/a')
1560
self.assertEqual("false", self.my_config.gpg_signing_command())
1608
self.assertEqual("false",
1609
self.applyDeprecated(deprecated_in((2, 5, 0)),
1610
self.my_config.gpg_signing_command))
1562
1612
def test_gpg_signing_key(self):
1563
1613
self.get_branch_config('/b')
1564
self.assertEqual("DD4D5088", self.my_config.gpg_signing_key())
1614
self.assertEqual("DD4D5088", self.applyDeprecated(deprecated_in((2, 5, 0)),
1615
self.my_config.gpg_signing_key))
1566
1617
def test_gpg_signing_key_default(self):
1567
1618
self.get_branch_config('/a')
1568
self.assertEqual("erik@bagfors.nu", self.my_config.gpg_signing_key())
1619
self.assertEqual("erik@bagfors.nu",
1620
self.applyDeprecated(deprecated_in((2, 5, 0)),
1621
self.my_config.gpg_signing_key))
1570
1623
def test_get_user_option_global(self):
1571
1624
self.get_branch_config('/a')
1774
1828
def test_signatures_forced(self):
1775
1829
my_config = self.get_branch_config(
1776
1830
global_config=sample_always_signatures)
1777
self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1778
self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1779
self.assertTrue(my_config.signature_needed())
1831
self.assertEqual(config.CHECK_NEVER,
1832
self.applyDeprecated(deprecated_in((2, 5, 0)),
1833
my_config.signature_checking))
1834
self.assertEqual(config.SIGN_ALWAYS,
1835
self.applyDeprecated(deprecated_in((2, 5, 0)),
1836
my_config.signing_policy))
1837
self.assertTrue(self.applyDeprecated(deprecated_in((2, 5, 0)),
1838
my_config.signature_needed))
1781
1840
def test_signatures_forced_branch(self):
1782
1841
my_config = self.get_branch_config(
1783
1842
global_config=sample_ignore_signatures,
1784
1843
branch_data_config=sample_always_signatures)
1785
self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1786
self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1787
self.assertTrue(my_config.signature_needed())
1844
self.assertEqual(config.CHECK_NEVER,
1845
self.applyDeprecated(deprecated_in((2, 5, 0)),
1846
my_config.signature_checking))
1847
self.assertEqual(config.SIGN_ALWAYS,
1848
self.applyDeprecated(deprecated_in((2, 5, 0)),
1849
my_config.signing_policy))
1850
self.assertTrue(self.applyDeprecated(deprecated_in((2, 5, 0)),
1851
my_config.signature_needed))
1789
1853
def test_gpg_signing_command(self):
1790
1854
my_config = self.get_branch_config(
1791
1855
global_config=sample_config_text,
1792
1856
# branch data cannot set gpg_signing_command
1793
1857
branch_data_config="gpg_signing_command=pgp")
1794
self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1858
self.assertEqual('gnome-gpg',
1859
self.applyDeprecated(deprecated_in((2, 5, 0)),
1860
my_config.gpg_signing_command))
1796
1862
def test_get_user_option_global(self):
1797
1863
my_config = self.get_branch_config(global_config=sample_config_text)
2296
2366
class TestOptionConverterMixin(object):
2298
2368
def assertConverted(self, expected, opt, value):
2299
self.assertEquals(expected, opt.convert_from_unicode(value))
2301
def assertWarns(self, opt, value):
2304
warnings.append(args[0] % args[1:])
2305
self.overrideAttr(trace, 'warning', warning)
2306
self.assertEquals(None, opt.convert_from_unicode(value))
2307
self.assertLength(1, warnings)
2309
'Value "%s" is not valid for "%s"' % (value, opt.name),
2312
def assertErrors(self, opt, value):
2313
self.assertRaises(errors.ConfigOptionValueError,
2314
opt.convert_from_unicode, value)
2316
def assertConvertInvalid(self, opt, invalid_value):
2318
self.assertEquals(None, opt.convert_from_unicode(invalid_value))
2319
opt.invalid = 'warning'
2320
self.assertWarns(opt, invalid_value)
2321
opt.invalid = 'error'
2322
self.assertErrors(opt, invalid_value)
2325
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2327
def get_option(self):
2328
return config.Option('foo', help='A boolean.',
2329
from_unicode=config.bool_from_store)
2331
def test_convert_invalid(self):
2332
opt = self.get_option()
2333
# A string that is not recognized as a boolean
2334
self.assertConvertInvalid(opt, u'invalid-boolean')
2335
# A list of strings is never recognized as a boolean
2336
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2338
def test_convert_valid(self):
2339
opt = self.get_option()
2340
self.assertConverted(True, opt, u'True')
2341
self.assertConverted(True, opt, u'1')
2342
self.assertConverted(False, opt, u'False')
2345
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2347
def get_option(self):
2348
return config.Option('foo', help='An integer.',
2349
from_unicode=config.int_from_store)
2351
def test_convert_invalid(self):
2352
opt = self.get_option()
2353
# A string that is not recognized as an integer
2354
self.assertConvertInvalid(opt, u'forty-two')
2355
# A list of strings is never recognized as an integer
2356
self.assertConvertInvalid(opt, [u'a', u'list'])
2358
def test_convert_valid(self):
2359
opt = self.get_option()
2360
self.assertConverted(16, opt, u'16')
2363
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
2365
def get_option(self):
2366
return config.Option('foo', help='A list.',
2367
from_unicode=config.list_from_store)
2369
def test_convert_invalid(self):
2370
# No string is invalid as all forms can be converted to a list
2373
def test_convert_valid(self):
2374
opt = self.get_option()
2375
# An empty string is an empty list
2376
self.assertConverted([], opt, '') # Using a bare str() just in case
2377
self.assertConverted([], opt, u'')
2379
self.assertConverted([u'True'], opt, u'True')
2381
self.assertConverted([u'42'], opt, u'42')
2383
self.assertConverted([u'bar'], opt, u'bar')
2384
# A list remains a list (configObj will turn a string containing commas
2385
# into a list, but that's not what we're testing here)
2386
self.assertConverted([u'foo', u'1', u'True'],
2387
opt, [u'foo', u'1', u'True'])
2390
class TestOptionConverterMixin(object):
2392
def assertConverted(self, expected, opt, value):
2393
self.assertEquals(expected, opt.convert_from_unicode(value))
2395
def assertWarns(self, opt, value):
2398
warnings.append(args[0] % args[1:])
2399
self.overrideAttr(trace, 'warning', warning)
2400
self.assertEquals(None, opt.convert_from_unicode(value))
2401
self.assertLength(1, warnings)
2403
'Value "%s" is not valid for "%s"' % (value, opt.name),
2406
def assertErrors(self, opt, value):
2407
self.assertRaises(errors.ConfigOptionValueError,
2408
opt.convert_from_unicode, value)
2410
def assertConvertInvalid(self, opt, invalid_value):
2412
self.assertEquals(None, opt.convert_from_unicode(invalid_value))
2413
opt.invalid = 'warning'
2414
self.assertWarns(opt, invalid_value)
2415
opt.invalid = 'error'
2416
self.assertErrors(opt, invalid_value)
2419
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2421
def get_option(self):
2422
return config.Option('foo', help='A boolean.',
2423
from_unicode=config.bool_from_store)
2425
def test_convert_invalid(self):
2426
opt = self.get_option()
2427
# A string that is not recognized as a boolean
2428
self.assertConvertInvalid(opt, u'invalid-boolean')
2429
# A list of strings is never recognized as a boolean
2430
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2432
def test_convert_valid(self):
2433
opt = self.get_option()
2434
self.assertConverted(True, opt, u'True')
2435
self.assertConverted(True, opt, u'1')
2436
self.assertConverted(False, opt, u'False')
2439
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2441
def get_option(self):
2442
return config.Option('foo', help='An integer.',
2443
from_unicode=config.int_from_store)
2445
def test_convert_invalid(self):
2446
opt = self.get_option()
2447
# A string that is not recognized as an integer
2448
self.assertConvertInvalid(opt, u'forty-two')
2449
# A list of strings is never recognized as an integer
2450
self.assertConvertInvalid(opt, [u'a', u'list'])
2452
def test_convert_valid(self):
2453
opt = self.get_option()
2454
self.assertConverted(16, opt, u'16')
2457
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
2459
def get_option(self):
2460
return config.Option('foo', help='A list.',
2461
from_unicode=config.list_from_store)
2369
self.assertEquals(expected, opt.convert_from_unicode(None, value))
2371
def assertWarns(self, opt, value):
2374
warnings.append(args[0] % args[1:])
2375
self.overrideAttr(trace, 'warning', warning)
2376
self.assertEquals(None, opt.convert_from_unicode(None, value))
2377
self.assertLength(1, warnings)
2379
'Value "%s" is not valid for "%s"' % (value, opt.name),
2382
def assertErrors(self, opt, value):
2383
self.assertRaises(errors.ConfigOptionValueError,
2384
opt.convert_from_unicode, None, value)
2386
def assertConvertInvalid(self, opt, invalid_value):
2388
self.assertEquals(None, opt.convert_from_unicode(None, invalid_value))
2389
opt.invalid = 'warning'
2390
self.assertWarns(opt, invalid_value)
2391
opt.invalid = 'error'
2392
self.assertErrors(opt, invalid_value)
2395
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2397
def get_option(self):
2398
return config.Option('foo', help='A boolean.',
2399
from_unicode=config.bool_from_store)
2401
def test_convert_invalid(self):
2402
opt = self.get_option()
2403
# A string that is not recognized as a boolean
2404
self.assertConvertInvalid(opt, u'invalid-boolean')
2405
# A list of strings is never recognized as a boolean
2406
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2408
def test_convert_valid(self):
2409
opt = self.get_option()
2410
self.assertConverted(True, opt, u'True')
2411
self.assertConverted(True, opt, u'1')
2412
self.assertConverted(False, opt, u'False')
2415
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2417
def get_option(self):
2418
return config.Option('foo', help='An integer.',
2419
from_unicode=config.int_from_store)
2421
def test_convert_invalid(self):
2422
opt = self.get_option()
2423
# A string that is not recognized as an integer
2424
self.assertConvertInvalid(opt, u'forty-two')
2425
# A list of strings is never recognized as an integer
2426
self.assertConvertInvalid(opt, [u'a', u'list'])
2428
def test_convert_valid(self):
2429
opt = self.get_option()
2430
self.assertConverted(16, opt, u'16')
2433
class TestOptionWithSIUnitConverter(tests.TestCase, TestOptionConverterMixin):
2435
def get_option(self):
2436
return config.Option('foo', help='An integer in SI units.',
2437
from_unicode=config.int_SI_from_store)
2439
def test_convert_invalid(self):
2440
opt = self.get_option()
2441
self.assertConvertInvalid(opt, u'not-a-unit')
2442
self.assertConvertInvalid(opt, u'Gb') # Forgot the int
2443
self.assertConvertInvalid(opt, u'1b') # Forgot the unit
2444
self.assertConvertInvalid(opt, u'1GG')
2445
self.assertConvertInvalid(opt, u'1Mbb')
2446
self.assertConvertInvalid(opt, u'1MM')
2448
def test_convert_valid(self):
2449
opt = self.get_option()
2450
self.assertConverted(int(5e3), opt, u'5kb')
2451
self.assertConverted(int(5e6), opt, u'5M')
2452
self.assertConverted(int(5e6), opt, u'5MB')
2453
self.assertConverted(int(5e9), opt, u'5g')
2454
self.assertConverted(int(5e9), opt, u'5gB')
2455
self.assertConverted(100, opt, u'100')
2458
class TestListOption(tests.TestCase, TestOptionConverterMixin):
2460
def get_option(self):
2461
return config.ListOption('foo', help='A list.')
2463
2463
def test_convert_invalid(self):
2464
2464
opt = self.get_option()
2699
2717
self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2720
class TestStoreQuoting(TestStore):
2722
scenarios = [(key, {'get_store': builder}) for key, builder
2723
in config.test_store_builder_registry.iteritems()]
2726
super(TestStoreQuoting, self).setUp()
2727
self.store = self.get_store(self)
2728
# We need a loaded store but any content will do
2729
self.store._load_from_string('')
2731
def assertIdempotent(self, s):
2732
"""Assert that quoting an unquoted string is a no-op and vice-versa.
2734
What matters here is that option values, as they appear in a store, can
2735
be safely round-tripped out of the store and back.
2737
:param s: A string, quoted if required.
2739
self.assertEquals(s, self.store.quote(self.store.unquote(s)))
2740
self.assertEquals(s, self.store.unquote(self.store.quote(s)))
2742
def test_empty_string(self):
2743
if isinstance(self.store, config.IniFileStore):
2744
# configobj._quote doesn't handle empty values
2745
self.assertRaises(AssertionError,
2746
self.assertIdempotent, '')
2748
self.assertIdempotent('')
2749
# But quoted empty strings are ok
2750
self.assertIdempotent('""')
2752
def test_embedded_spaces(self):
2753
self.assertIdempotent('" a b c "')
2755
def test_embedded_commas(self):
2756
self.assertIdempotent('" a , b c "')
2758
def test_simple_comma(self):
2759
if isinstance(self.store, config.IniFileStore):
2760
# configobj requires that lists are special-cased
2761
self.assertRaises(AssertionError,
2762
self.assertIdempotent, ',')
2764
self.assertIdempotent(',')
2765
# When a single comma is required, quoting is also required
2766
self.assertIdempotent('","')
2768
def test_list(self):
2769
if isinstance(self.store, config.IniFileStore):
2770
# configobj requires that lists are special-cased
2771
self.assertRaises(AssertionError,
2772
self.assertIdempotent, 'a,b')
2774
self.assertIdempotent('a,b')
2777
class TestDictFromStore(tests.TestCase):
2779
def test_unquote_not_string(self):
2780
conf = config.MemoryStack('x=2\n[a_section]\na=1\n')
2781
value = conf.get('a_section')
2782
# Urgh, despite 'conf' asking for the no-name section, we get the
2783
# content of another section as a dict o_O
2784
self.assertEquals({'a': '1'}, value)
2785
unquoted = conf.store.unquote(value)
2786
# Which cannot be unquoted but shouldn't crash either (the use cases
2787
# are getting the value or displaying it. In the later case, '%s' will
2789
self.assertEquals({'a': '1'}, unquoted)
2790
self.assertEquals("{u'a': u'1'}", '%s' % (unquoted,))
2702
2793
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2703
2794
"""Simulate loading a config store with content of various encodings.
2909
3000
self.assertLength(1, calls)
2910
3001
self.assertEquals((store,), calls[0])
3003
def test_set_mark_dirty(self):
3004
stack = config.MemoryStack('')
3005
self.assertLength(0, stack.store.dirty_sections)
3006
stack.set('foo', 'baz')
3007
self.assertLength(1, stack.store.dirty_sections)
3008
self.assertTrue(stack.store._need_saving())
3010
def test_remove_mark_dirty(self):
3011
stack = config.MemoryStack('foo=bar')
3012
self.assertLength(0, stack.store.dirty_sections)
3014
self.assertLength(1, stack.store.dirty_sections)
3015
self.assertTrue(stack.store._need_saving())
3018
class TestStoreSaveChanges(tests.TestCaseWithTransport):
3019
"""Tests that config changes are kept in memory and saved on-demand."""
3022
super(TestStoreSaveChanges, self).setUp()
3023
self.transport = self.get_transport()
3024
# Most of the tests involve two stores pointing to the same persistent
3025
# storage to observe the effects of concurrent changes
3026
self.st1 = config.TransportIniFileStore(self.transport, 'foo.conf')
3027
self.st2 = config.TransportIniFileStore(self.transport, 'foo.conf')
3030
self.warnings.append(args[0] % args[1:])
3031
self.overrideAttr(trace, 'warning', warning)
3033
def has_store(self, store):
3034
store_basename = urlutils.relative_url(self.transport.external_url(),
3035
store.external_url())
3036
return self.transport.has(store_basename)
3038
def get_stack(self, store):
3039
# Any stack will do as long as it uses the right store, just a single
3040
# no-name section is enough
3041
return config.Stack([store.get_sections], store)
3043
def test_no_changes_no_save(self):
3044
s = self.get_stack(self.st1)
3045
s.store.save_changes()
3046
self.assertEquals(False, self.has_store(self.st1))
3048
def test_unrelated_concurrent_update(self):
3049
s1 = self.get_stack(self.st1)
3050
s2 = self.get_stack(self.st2)
3051
s1.set('foo', 'bar')
3052
s2.set('baz', 'quux')
3054
# Changes don't propagate magically
3055
self.assertEquals(None, s1.get('baz'))
3056
s2.store.save_changes()
3057
self.assertEquals('quux', s2.get('baz'))
3058
# Changes are acquired when saving
3059
self.assertEquals('bar', s2.get('foo'))
3060
# Since there is no overlap, no warnings are emitted
3061
self.assertLength(0, self.warnings)
3063
def test_concurrent_update_modified(self):
3064
s1 = self.get_stack(self.st1)
3065
s2 = self.get_stack(self.st2)
3066
s1.set('foo', 'bar')
3067
s2.set('foo', 'baz')
3070
s2.store.save_changes()
3071
self.assertEquals('baz', s2.get('foo'))
3072
# But the user get a warning
3073
self.assertLength(1, self.warnings)
3074
warning = self.warnings[0]
3075
self.assertStartsWith(warning, 'Option foo in section None')
3076
self.assertEndsWith(warning, 'was changed from <CREATED> to bar.'
3077
' The baz value will be saved.')
3079
def test_concurrent_deletion(self):
3080
self.st1._load_from_string('foo=bar')
3082
s1 = self.get_stack(self.st1)
3083
s2 = self.get_stack(self.st2)
3086
s1.store.save_changes()
3088
self.assertLength(0, self.warnings)
3089
s2.store.save_changes()
3091
self.assertLength(1, self.warnings)
3092
warning = self.warnings[0]
3093
self.assertStartsWith(warning, 'Option foo in section None')
3094
self.assertEndsWith(warning, 'was changed from bar to <CREATED>.'
3095
' The <DELETED> value will be saved.')
3098
class TestQuotingIniFileStore(tests.TestCaseWithTransport):
3100
def get_store(self):
3101
return config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3103
def test_get_quoted_string(self):
3104
store = self.get_store()
3105
store._load_from_string('foo= " abc "')
3106
stack = config.Stack([store.get_sections])
3107
self.assertEquals(' abc ', stack.get('foo'))
3109
def test_set_quoted_string(self):
3110
store = self.get_store()
3111
stack = config.Stack([store.get_sections], store)
3112
stack.set('foo', ' a b c ')
3114
self.assertFileEqual('foo = " a b c "' + os.linesep, 'foo.conf')
2913
3117
class TestTransportIniFileStore(TestStore):
3259
3463
self.assertLength(0, sections)
3262
class TestStackGet(tests.TestCase):
3264
# FIXME: This should be parametrized for all known Stack or dedicated
3265
# paramerized tests created to avoid bloating -- vila 2011-03-31
3267
def overrideOptionRegistry(self):
3466
class TestBaseStackGet(tests.TestCase):
3469
super(TestBaseStackGet, self).setUp()
3268
3470
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3270
def test_single_config_get(self):
3271
conf = dict(foo='bar')
3272
conf_stack = config.Stack([conf])
3273
self.assertEquals('bar', conf_stack.get('foo'))
3472
def test_get_first_definition(self):
3473
store1 = config.IniFileStore()
3474
store1._load_from_string('foo=bar')
3475
store2 = config.IniFileStore()
3476
store2._load_from_string('foo=baz')
3477
conf = config.Stack([store1.get_sections, store2.get_sections])
3478
self.assertEquals('bar', conf.get('foo'))
3275
3480
def test_get_with_registered_default_value(self):
3276
conf_stack = config.Stack([dict()])
3277
opt = config.Option('foo', default='bar')
3278
self.overrideOptionRegistry()
3279
config.option_registry.register('foo', opt)
3481
config.option_registry.register(config.Option('foo', default='bar'))
3482
conf_stack = config.Stack([])
3280
3483
self.assertEquals('bar', conf_stack.get('foo'))
3282
3485
def test_get_without_registered_default_value(self):
3283
conf_stack = config.Stack([dict()])
3284
opt = config.Option('foo')
3285
self.overrideOptionRegistry()
3286
config.option_registry.register('foo', opt)
3486
config.option_registry.register(config.Option('foo'))
3487
conf_stack = config.Stack([])
3287
3488
self.assertEquals(None, conf_stack.get('foo'))
3289
3490
def test_get_without_default_value_for_not_registered(self):
3290
conf_stack = config.Stack([dict()])
3291
opt = config.Option('foo')
3292
self.overrideOptionRegistry()
3491
conf_stack = config.Stack([])
3293
3492
self.assertEquals(None, conf_stack.get('foo'))
3295
def test_get_first_definition(self):
3296
conf1 = dict(foo='bar')
3297
conf2 = dict(foo='baz')
3298
conf_stack = config.Stack([conf1, conf2])
3299
self.assertEquals('bar', conf_stack.get('foo'))
3301
def test_get_embedded_definition(self):
3302
conf1 = dict(yy='12')
3303
conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
3304
conf_stack = config.Stack([conf1, conf2])
3305
self.assertEquals('baz', conf_stack.get('foo'))
3307
3494
def test_get_for_empty_section_callable(self):
3308
3495
conf_stack = config.Stack([lambda : []])
3309
3496
self.assertEquals(None, conf_stack.get('foo'))
3311
3498
def test_get_for_broken_callable(self):
3312
3499
# Trying to use and invalid callable raises an exception on first use
3313
conf_stack = config.Stack([lambda : object()])
3500
conf_stack = config.Stack([object])
3314
3501
self.assertRaises(TypeError, conf_stack.get, 'foo')
3504
class TestStackWithSimpleStore(tests.TestCase):
3507
super(TestStackWithSimpleStore, self).setUp()
3508
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3509
self.registry = config.option_registry
3511
def get_conf(self, content=None):
3512
return config.MemoryStack(content)
3514
def test_override_value_from_env(self):
3515
self.registry.register(
3516
config.Option('foo', default='bar', override_from_env=['FOO']))
3517
self.overrideEnv('FOO', 'quux')
3518
# Env variable provides a default taking over the option one
3519
conf = self.get_conf('foo=store')
3520
self.assertEquals('quux', conf.get('foo'))
3522
def test_first_override_value_from_env_wins(self):
3523
self.registry.register(
3524
config.Option('foo', default='bar',
3525
override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
3526
self.overrideEnv('FOO', 'foo')
3527
self.overrideEnv('BAZ', 'baz')
3528
# The first env var set wins
3529
conf = self.get_conf('foo=store')
3530
self.assertEquals('foo', conf.get('foo'))
3533
class TestMemoryStack(tests.TestCase):
3536
conf = config.MemoryStack('foo=bar')
3537
self.assertEquals('bar', conf.get('foo'))
3540
conf = config.MemoryStack('foo=bar')
3541
conf.set('foo', 'baz')
3542
self.assertEquals('baz', conf.get('foo'))
3544
def test_no_content(self):
3545
conf = config.MemoryStack()
3546
# No content means no loading
3547
self.assertFalse(conf.store.is_loaded())
3548
self.assertRaises(NotImplementedError, conf.get, 'foo')
3549
# But a content can still be provided
3550
conf.store._load_from_string('foo=bar')
3551
self.assertEquals('bar', conf.get('foo'))
3317
3554
class TestStackWithTransport(tests.TestCaseWithTransport):
3319
3556
scenarios = [(key, {'get_stack': builder}) for key, builder
3403
3643
def test_get_default_integer_None(self):
3404
3644
self.register_integer_option('foo')
3405
self.assertEquals(None, self.conf.get('foo'))
3645
conf = self.get_conf('')
3646
self.assertEquals(None, conf.get('foo'))
3407
3648
def test_get_default_integer(self):
3408
3649
self.register_integer_option('foo', 42)
3409
self.assertEquals(42, self.conf.get('foo'))
3650
conf = self.get_conf('')
3651
self.assertEquals(42, conf.get('foo'))
3411
3653
def test_get_default_integer_as_string(self):
3412
3654
self.register_integer_option('foo', u'42')
3413
self.assertEquals(42, self.conf.get('foo'))
3655
conf = self.get_conf('')
3656
self.assertEquals(42, conf.get('foo'))
3415
3658
def test_get_default_integer_from_env(self):
3416
3659
self.register_integer_option('foo', default_from_env=['FOO'])
3417
3660
self.overrideEnv('FOO', '18')
3418
self.assertEquals(18, self.conf.get('foo'))
3661
conf = self.get_conf('')
3662
self.assertEquals(18, conf.get('foo'))
3420
3664
def test_get_default_integer_when_conversion_fails(self):
3421
3665
self.register_integer_option('foo', default='12')
3422
self.conf.store._load_from_string('foo=invalid integer')
3423
self.assertEquals(12, self.conf.get('foo'))
3666
conf = self.get_conf('foo=invalid integer')
3667
self.assertEquals(12, conf.get('foo'))
3425
3669
def register_list_option(self, name, default=None, default_from_env=None):
3426
l = config.Option(name, help='A list.',
3427
default=default, default_from_env=default_from_env,
3428
from_unicode=config.list_from_store)
3670
l = config.ListOption(name, help='A list.', default=default,
3671
default_from_env=default_from_env)
3429
3672
self.registry.register(l)
3431
3674
def test_get_default_list_None(self):
3432
3675
self.register_list_option('foo')
3433
self.assertEquals(None, self.conf.get('foo'))
3676
conf = self.get_conf('')
3677
self.assertEquals(None, conf.get('foo'))
3435
3679
def test_get_default_list_empty(self):
3436
3680
self.register_list_option('foo', '')
3437
self.assertEquals([], self.conf.get('foo'))
3681
conf = self.get_conf('')
3682
self.assertEquals([], conf.get('foo'))
3439
3684
def test_get_default_list_from_env(self):
3440
3685
self.register_list_option('foo', default_from_env=['FOO'])
3441
3686
self.overrideEnv('FOO', '')
3442
self.assertEquals([], self.conf.get('foo'))
3687
conf = self.get_conf('')
3688
self.assertEquals([], conf.get('foo'))
3444
3690
def test_get_with_list_converter_no_item(self):
3445
3691
self.register_list_option('foo', None)
3446
self.conf.store._load_from_string('foo=,')
3447
self.assertEquals([], self.conf.get('foo'))
3692
conf = self.get_conf('foo=,')
3693
self.assertEquals([], conf.get('foo'))
3449
3695
def test_get_with_list_converter_many_items(self):
3450
3696
self.register_list_option('foo', None)
3451
self.conf.store._load_from_string('foo=m,o,r,e')
3452
self.assertEquals(['m', 'o', 'r', 'e'], self.conf.get('foo'))
3697
conf = self.get_conf('foo=m,o,r,e')
3698
self.assertEquals(['m', 'o', 'r', 'e'], conf.get('foo'))
3454
3700
def test_get_with_list_converter_embedded_spaces_many_items(self):
3455
3701
self.register_list_option('foo', None)
3456
self.conf.store._load_from_string('foo=" bar", "baz "')
3457
self.assertEquals([' bar', 'baz '], self.conf.get('foo'))
3702
conf = self.get_conf('foo=" bar", "baz "')
3703
self.assertEquals([' bar', 'baz '], conf.get('foo'))
3459
3705
def test_get_with_list_converter_stripped_spaces_many_items(self):
3460
3706
self.register_list_option('foo', None)
3461
self.conf.store._load_from_string('foo= bar , baz ')
3462
self.assertEquals(['bar', 'baz'], self.conf.get('foo'))
3707
conf = self.get_conf('foo= bar , baz ')
3708
self.assertEquals(['bar', 'baz'], conf.get('foo'))
3465
3711
class TestIterOptionRefs(tests.TestCase):