~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: John Arbash Meinel
  • Date: 2011-05-06 15:15:44 UTC
  • mfrom: (5835 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5836.
  • Revision ID: john@arbash-meinel.com-20110506151544-atzxeezfwssnlacr
Merge bzr.dev 5835 in prep for release-notes updates

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
    mergetools,
37
37
    ui,
38
38
    urlutils,
 
39
    registry,
39
40
    tests,
40
41
    trace,
41
42
    transport,
62
63
 
63
64
load_tests = scenarios.load_tests_apply_scenarios
64
65
 
 
66
# We need adapters that can build a config store in a test context. Test
 
67
# classes, based on TestCaseWithTransport, can use the registry to parametrize
 
68
# themselves. The builder will receive a test instance and should return a
 
69
# ready-to-use store.  Plugins that defines new stores can also register
 
70
# themselves here to be tested against the tests defined below.
 
71
 
 
72
# FIXME: plugins should *not* need to import test_config to register their
 
73
# helpers (or selftest -s xxx will be broken), the following registry should be
 
74
# moved to bzrlib.config instead so that selftest -s bt.test_config also runs
 
75
# the plugin specific tests (selftest -s bp.xxx won't, that would be against
 
76
# the spirit of '-s') -- vila 20110503
 
77
test_store_builder_registry = registry.Registry()
 
78
test_store_builder_registry.register(
 
79
    'configobj', lambda test: config.IniFileStore(test.get_transport(),
 
80
                                                  'configobj.conf'))
 
81
test_store_builder_registry.register(
 
82
    'bazaar', lambda test: config.GlobalStore())
 
83
test_store_builder_registry.register(
 
84
    'location', lambda test: config.LocationStore())
 
85
test_store_builder_registry.register(
 
86
    'branch', lambda test: config.BranchStore(test.branch))
 
87
 
 
88
 
65
89
 
66
90
sample_long_alias="log -r-15..-1 --line"
67
91
sample_config_text = u"""
832
856
        def c1_write_config_file():
833
857
            before_writing.set()
834
858
            c1_orig()
835
 
            # The lock is held we wait for the main thread to decide when to
 
859
            # The lock is held. We wait for the main thread to decide when to
836
860
            # continue
837
861
            after_writing.wait()
838
862
        c1._write_config_file = c1_write_config_file
865
889
       c1_orig = c1._write_config_file
866
890
       def c1_write_config_file():
867
891
           ready_to_write.set()
868
 
           # The lock is held we wait for the main thread to decide when to
 
892
           # The lock is held. We wait for the main thread to decide when to
869
893
           # continue
870
894
           do_writing.wait()
871
895
           c1_orig()
1814
1838
        self.assertIs(None, bzrdir_config.get_default_stack_on())
1815
1839
 
1816
1840
 
 
1841
class TestSection(tests.TestCase):
 
1842
 
 
1843
    # FIXME: Parametrize so that all sections produced by Stores run these
 
1844
    # tests -- vila 2011-04-01
 
1845
 
 
1846
    def test_get_a_value(self):
 
1847
        a_dict = dict(foo='bar')
 
1848
        section = config.Section('myID', a_dict)
 
1849
        self.assertEquals('bar', section.get('foo'))
 
1850
 
 
1851
    def test_get_unknown_option(self):
 
1852
        a_dict = dict()
 
1853
        section = config.Section(None, a_dict)
 
1854
        self.assertEquals('out of thin air',
 
1855
                          section.get('foo', 'out of thin air'))
 
1856
 
 
1857
    def test_options_is_shared(self):
 
1858
        a_dict = dict()
 
1859
        section = config.Section(None, a_dict)
 
1860
        self.assertIs(a_dict, section.options)
 
1861
 
 
1862
 
 
1863
class TestMutableSection(tests.TestCase):
 
1864
 
 
1865
    # FIXME: Parametrize so that all sections (including os.environ and the
 
1866
    # ones produced by Stores) run these tests -- vila 2011-04-01
 
1867
 
 
1868
    def test_set(self):
 
1869
        a_dict = dict(foo='bar')
 
1870
        section = config.MutableSection('myID', a_dict)
 
1871
        section.set('foo', 'new_value')
 
1872
        self.assertEquals('new_value', section.get('foo'))
 
1873
        # The change appears in the shared section
 
1874
        self.assertEquals('new_value', a_dict.get('foo'))
 
1875
        # We keep track of the change
 
1876
        self.assertTrue('foo' in section.orig)
 
1877
        self.assertEquals('bar', section.orig.get('foo'))
 
1878
 
 
1879
    def test_set_preserve_original_once(self):
 
1880
        a_dict = dict(foo='bar')
 
1881
        section = config.MutableSection('myID', a_dict)
 
1882
        section.set('foo', 'first_value')
 
1883
        section.set('foo', 'second_value')
 
1884
        # We keep track of the original value
 
1885
        self.assertTrue('foo' in section.orig)
 
1886
        self.assertEquals('bar', section.orig.get('foo'))
 
1887
 
 
1888
    def test_remove(self):
 
1889
        a_dict = dict(foo='bar')
 
1890
        section = config.MutableSection('myID', a_dict)
 
1891
        section.remove('foo')
 
1892
        # We get None for unknown options via the default value
 
1893
        self.assertEquals(None, section.get('foo'))
 
1894
        # Or we just get the default value
 
1895
        self.assertEquals('unknown', section.get('foo', 'unknown'))
 
1896
        self.assertFalse('foo' in section.options)
 
1897
        # We keep track of the deletion
 
1898
        self.assertTrue('foo' in section.orig)
 
1899
        self.assertEquals('bar', section.orig.get('foo'))
 
1900
 
 
1901
    def test_remove_new_option(self):
 
1902
        a_dict = dict()
 
1903
        section = config.MutableSection('myID', a_dict)
 
1904
        section.set('foo', 'bar')
 
1905
        section.remove('foo')
 
1906
        self.assertFalse('foo' in section.options)
 
1907
        # The option didn't exist initially so it we need to keep track of it
 
1908
        # with a special value
 
1909
        self.assertTrue('foo' in section.orig)
 
1910
        self.assertEquals(config._NewlyCreatedOption, section.orig['foo'])
 
1911
 
 
1912
 
 
1913
class TestStore(tests.TestCaseWithTransport):
 
1914
 
 
1915
    def assertSectionContent(self, expected, section):
 
1916
        """Assert that some options have the proper values in a section."""
 
1917
        expected_name, expected_options = expected
 
1918
        self.assertEquals(expected_name, section.id)
 
1919
        self.assertEquals(
 
1920
            expected_options,
 
1921
            dict([(k, section.get(k)) for k in expected_options.keys()]))
 
1922
 
 
1923
 
 
1924
class TestReadonlyStore(TestStore):
 
1925
 
 
1926
    scenarios = [(key, {'get_store': builder})
 
1927
                 for key, builder in test_store_builder_registry.iteritems()]
 
1928
 
 
1929
    def setUp(self):
 
1930
        super(TestReadonlyStore, self).setUp()
 
1931
        self.branch = self.make_branch('branch')
 
1932
 
 
1933
    def test_building_delays_load(self):
 
1934
        store = self.get_store(self)
 
1935
        self.assertEquals(False, store.is_loaded())
 
1936
        store._load_from_string('')
 
1937
        self.assertEquals(True, store.is_loaded())
 
1938
 
 
1939
    def test_get_no_sections_for_empty(self):
 
1940
        store = self.get_store(self)
 
1941
        store._load_from_string('')
 
1942
        self.assertEquals([], list(store.get_sections()))
 
1943
 
 
1944
    def test_get_default_section(self):
 
1945
        store = self.get_store(self)
 
1946
        store._load_from_string('foo=bar')
 
1947
        sections = list(store.get_sections())
 
1948
        self.assertLength(1, sections)
 
1949
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
 
1950
 
 
1951
    def test_get_named_section(self):
 
1952
        store = self.get_store(self)
 
1953
        store._load_from_string('[baz]\nfoo=bar')
 
1954
        sections = list(store.get_sections())
 
1955
        self.assertLength(1, sections)
 
1956
        self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
 
1957
 
 
1958
    def test_load_from_string_fails_for_non_empty_store(self):
 
1959
        store = self.get_store(self)
 
1960
        store._load_from_string('foo=bar')
 
1961
        self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
 
1962
 
 
1963
 
 
1964
class TestMutableStore(TestStore):
 
1965
 
 
1966
    scenarios = [(key, {'store_id': key, 'get_store': builder})
 
1967
                 for key, builder in test_store_builder_registry.iteritems()]
 
1968
 
 
1969
    def setUp(self):
 
1970
        super(TestMutableStore, self).setUp()
 
1971
        self.transport = self.get_transport()
 
1972
        self.branch = self.make_branch('branch')
 
1973
 
 
1974
    def has_store(self, store):
 
1975
        store_basename = urlutils.relative_url(self.transport.external_url(),
 
1976
                                               store.external_url())
 
1977
        return self.transport.has(store_basename)
 
1978
 
 
1979
    def test_save_empty_creates_no_file(self):
 
1980
        if self.store_id == 'branch':
 
1981
            raise tests.TestNotApplicable(
 
1982
                'branch.conf is *always* created when a branch is initialized')
 
1983
        store = self.get_store(self)
 
1984
        store.save()
 
1985
        self.assertEquals(False, self.has_store(store))
 
1986
 
 
1987
    def test_save_emptied_succeeds(self):
 
1988
        store = self.get_store(self)
 
1989
        store._load_from_string('foo=bar\n')
 
1990
        section = store.get_mutable_section(None)
 
1991
        section.remove('foo')
 
1992
        store.save()
 
1993
        self.assertEquals(True, self.has_store(store))
 
1994
        modified_store = self.get_store(self)
 
1995
        sections = list(modified_store.get_sections())
 
1996
        self.assertLength(0, sections)
 
1997
 
 
1998
    def test_save_with_content_succeeds(self):
 
1999
        if self.store_id == 'branch':
 
2000
            raise tests.TestNotApplicable(
 
2001
                'branch.conf is *always* created when a branch is initialized')
 
2002
        store = self.get_store(self)
 
2003
        store._load_from_string('foo=bar\n')
 
2004
        self.assertEquals(False, self.has_store(store))
 
2005
        store.save()
 
2006
        self.assertEquals(True, self.has_store(store))
 
2007
        modified_store = self.get_store(self)
 
2008
        sections = list(modified_store.get_sections())
 
2009
        self.assertLength(1, sections)
 
2010
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
 
2011
 
 
2012
    def test_set_option_in_empty_store(self):
 
2013
        store = self.get_store(self)
 
2014
        section = store.get_mutable_section(None)
 
2015
        section.set('foo', 'bar')
 
2016
        store.save()
 
2017
        modified_store = self.get_store(self)
 
2018
        sections = list(modified_store.get_sections())
 
2019
        self.assertLength(1, sections)
 
2020
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
 
2021
 
 
2022
    def test_set_option_in_default_section(self):
 
2023
        store = self.get_store(self)
 
2024
        store._load_from_string('')
 
2025
        section = store.get_mutable_section(None)
 
2026
        section.set('foo', 'bar')
 
2027
        store.save()
 
2028
        modified_store = self.get_store(self)
 
2029
        sections = list(modified_store.get_sections())
 
2030
        self.assertLength(1, sections)
 
2031
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
 
2032
 
 
2033
    def test_set_option_in_named_section(self):
 
2034
        store = self.get_store(self)
 
2035
        store._load_from_string('')
 
2036
        section = store.get_mutable_section('baz')
 
2037
        section.set('foo', 'bar')
 
2038
        store.save()
 
2039
        modified_store = self.get_store(self)
 
2040
        sections = list(modified_store.get_sections())
 
2041
        self.assertLength(1, sections)
 
2042
        self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
 
2043
 
 
2044
 
 
2045
class TestIniFileStore(TestStore):
 
2046
 
 
2047
    def test_loading_unknown_file_fails(self):
 
2048
        store = config.IniFileStore(self.get_transport(), 'I-do-not-exist')
 
2049
        self.assertRaises(errors.NoSuchFile, store.load)
 
2050
 
 
2051
    def test_invalid_content(self):
 
2052
        store = config.IniFileStore(self.get_transport(), 'foo.conf', )
 
2053
        self.assertEquals(False, store.is_loaded())
 
2054
        exc = self.assertRaises(
 
2055
            errors.ParseConfigError, store._load_from_string,
 
2056
            'this is invalid !')
 
2057
        self.assertEndsWith(exc.filename, 'foo.conf')
 
2058
        # And the load failed
 
2059
        self.assertEquals(False, store.is_loaded())
 
2060
 
 
2061
    def test_get_embedded_sections(self):
 
2062
        # A more complicated example (which also shows that section names and
 
2063
        # option names share the same name space...)
 
2064
        # FIXME: This should be fixed by forbidding dicts as values ?
 
2065
        # -- vila 2011-04-05
 
2066
        store = config.IniFileStore(self.get_transport(), 'foo.conf', )
 
2067
        store._load_from_string('''
 
2068
foo=bar
 
2069
l=1,2
 
2070
[DEFAULT]
 
2071
foo_in_DEFAULT=foo_DEFAULT
 
2072
[bar]
 
2073
foo_in_bar=barbar
 
2074
[baz]
 
2075
foo_in_baz=barbaz
 
2076
[[qux]]
 
2077
foo_in_qux=quux
 
2078
''')
 
2079
        sections = list(store.get_sections())
 
2080
        self.assertLength(4, sections)
 
2081
        # The default section has no name.
 
2082
        # List values are provided as lists
 
2083
        self.assertSectionContent((None, {'foo': 'bar', 'l': ['1', '2']}),
 
2084
                                  sections[0])
 
2085
        self.assertSectionContent(
 
2086
            ('DEFAULT', {'foo_in_DEFAULT': 'foo_DEFAULT'}), sections[1])
 
2087
        self.assertSectionContent(
 
2088
            ('bar', {'foo_in_bar': 'barbar'}), sections[2])
 
2089
        # sub sections are provided as embedded dicts.
 
2090
        self.assertSectionContent(
 
2091
            ('baz', {'foo_in_baz': 'barbaz', 'qux': {'foo_in_qux': 'quux'}}),
 
2092
            sections[3])
 
2093
 
 
2094
 
 
2095
class TestLockableIniFileStore(TestStore):
 
2096
 
 
2097
    def test_create_store_in_created_dir(self):
 
2098
        t = self.get_transport('dir/subdir')
 
2099
        store = config.LockableIniFileStore(t, 'foo.conf')
 
2100
        store.get_mutable_section(None).set('foo', 'bar')
 
2101
        store.save()
 
2102
 
 
2103
    # FIXME: We should adapt the tests in TestLockableConfig about concurrent
 
2104
    # writes. Since this requires a clearer rewrite, I'll just rely on using
 
2105
    # the same code in LockableIniFileStore (copied from LockableConfig, but
 
2106
    # trivial enough, the main difference is that we add @needs_write_lock on
 
2107
    # save() instead of set_user_option() and remove_user_option()). The intent
 
2108
    # is to ensure that we always get a valid content for the store even when
 
2109
    # concurrent accesses occur, read/write, write/write. It may be worth
 
2110
    # looking into removing the lock dir when it;s not needed anymore and look
 
2111
    # at possible fallouts for concurrent lockers -- vila 20110-04-06
 
2112
 
 
2113
 
 
2114
class TestSectionMatcher(TestStore):
 
2115
 
 
2116
    scenarios = [('location', {'matcher': config.LocationMatcher})]
 
2117
 
 
2118
    def get_store(self, file_name):
 
2119
        return config.IniFileStore(self.get_readonly_transport(), file_name)
 
2120
 
 
2121
    def test_no_matches_for_empty_stores(self):
 
2122
        store = self.get_store('foo.conf')
 
2123
        store._load_from_string('')
 
2124
        matcher = self.matcher(store, '/bar')
 
2125
        self.assertEquals([], list(matcher.get_sections()))
 
2126
 
 
2127
    def test_build_doesnt_load_store(self):
 
2128
        store = self.get_store('foo.conf')
 
2129
        matcher = self.matcher(store, '/bar')
 
2130
        self.assertFalse(store.is_loaded())
 
2131
 
 
2132
 
 
2133
class TestLocationSection(tests.TestCase):
 
2134
 
 
2135
    def get_section(self, options, extra_path):
 
2136
        section = config.Section('foo', options)
 
2137
        # We don't care about the length so we use '0'
 
2138
        return config.LocationSection(section, 0, extra_path)
 
2139
 
 
2140
    def test_simple_option(self):
 
2141
        section = self.get_section({'foo': 'bar'}, '')
 
2142
        self.assertEquals('bar', section.get('foo'))
 
2143
 
 
2144
    def test_option_with_extra_path(self):
 
2145
        section = self.get_section({'foo': 'bar', 'foo:policy': 'appendpath'},
 
2146
                                   'baz')
 
2147
        self.assertEquals('bar/baz', section.get('foo'))
 
2148
 
 
2149
    def test_invalid_policy(self):
 
2150
        section = self.get_section({'foo': 'bar', 'foo:policy': 'die'},
 
2151
                                   'baz')
 
2152
        # invalid policies are ignored
 
2153
        self.assertEquals('bar', section.get('foo'))
 
2154
 
 
2155
 
 
2156
class TestLocationMatcher(TestStore):
 
2157
 
 
2158
    def get_store(self, file_name):
 
2159
        return config.IniFileStore(self.get_readonly_transport(), file_name)
 
2160
 
 
2161
    def test_more_specific_sections_first(self):
 
2162
        store = self.get_store('foo.conf')
 
2163
        store._load_from_string('''
 
2164
[/foo]
 
2165
section=/foo
 
2166
[/foo/bar]
 
2167
section=/foo/bar
 
2168
''')
 
2169
        self.assertEquals(['/foo', '/foo/bar'],
 
2170
                          [section.id for section in store.get_sections()])
 
2171
        matcher = config.LocationMatcher(store, '/foo/bar/baz')
 
2172
        sections = list(matcher.get_sections())
 
2173
        self.assertEquals([3, 2],
 
2174
                          [section.length for section in sections])
 
2175
        self.assertEquals(['/foo/bar', '/foo'],
 
2176
                          [section.id for section in sections])
 
2177
        self.assertEquals(['baz', 'bar/baz'],
 
2178
                          [section.extra_path for section in sections])
 
2179
 
 
2180
 
 
2181
 
 
2182
class TestStackGet(tests.TestCase):
 
2183
 
 
2184
    # FIXME: This should be parametrized for all known Stack or dedicated
 
2185
    # paramerized tests created to avoid bloating -- vila 2011-03-31
 
2186
 
 
2187
    def test_single_config_get(self):
 
2188
        conf = dict(foo='bar')
 
2189
        conf_stack = config.Stack([conf])
 
2190
        self.assertEquals('bar', conf_stack.get('foo'))
 
2191
 
 
2192
    def test_get_first_definition(self):
 
2193
        conf1 = dict(foo='bar')
 
2194
        conf2 = dict(foo='baz')
 
2195
        conf_stack = config.Stack([conf1, conf2])
 
2196
        self.assertEquals('bar', conf_stack.get('foo'))
 
2197
 
 
2198
    def test_get_embedded_definition(self):
 
2199
        conf1 = dict(yy='12')
 
2200
        conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
 
2201
        conf_stack = config.Stack([conf1, conf2])
 
2202
        self.assertEquals('baz', conf_stack.get('foo'))
 
2203
 
 
2204
    def test_get_for_empty_stack(self):
 
2205
        conf_stack = config.Stack([])
 
2206
        self.assertEquals(None, conf_stack.get('foo'))
 
2207
 
 
2208
    def test_get_for_empty_section_callable(self):
 
2209
        conf_stack = config.Stack([lambda : []])
 
2210
        self.assertEquals(None, conf_stack.get('foo'))
 
2211
 
 
2212
    def test_get_for_broken_callable(self):
 
2213
        # Trying to use and invalid callable raises an exception on first use
 
2214
        conf_stack = config.Stack([lambda : object()])
 
2215
        self.assertRaises(TypeError, conf_stack.get, 'foo')
 
2216
 
 
2217
 
 
2218
class TestStackSet(tests.TestCaseWithTransport):
 
2219
 
 
2220
    # FIXME: This should be parametrized for all known Stack or dedicated
 
2221
    # paramerized tests created to avoid bloating -- vila 2011-04-05
 
2222
 
 
2223
    def test_simple_set(self):
 
2224
        store = config.IniFileStore(self.get_transport(), 'test.conf')
 
2225
        store._load_from_string('foo=bar')
 
2226
        conf = config.Stack([store.get_sections], store)
 
2227
        self.assertEquals('bar', conf.get('foo'))
 
2228
        conf.set('foo', 'baz')
 
2229
        # Did we get it back ?
 
2230
        self.assertEquals('baz', conf.get('foo'))
 
2231
 
 
2232
    def test_set_creates_a_new_section(self):
 
2233
        store = config.IniFileStore(self.get_transport(), 'test.conf')
 
2234
        conf = config.Stack([store.get_sections], store)
 
2235
        conf.set('foo', 'baz')
 
2236
        self.assertEquals, 'baz', conf.get('foo')
 
2237
 
 
2238
 
 
2239
class TestStackRemove(tests.TestCaseWithTransport):
 
2240
 
 
2241
    # FIXME: This should be parametrized for all known Stack or dedicated
 
2242
    # paramerized tests created to avoid bloating -- vila 2011-04-06
 
2243
 
 
2244
    def test_remove_existing(self):
 
2245
        store = config.IniFileStore(self.get_transport(), 'test.conf')
 
2246
        store._load_from_string('foo=bar')
 
2247
        conf = config.Stack([store.get_sections], store)
 
2248
        self.assertEquals('bar', conf.get('foo'))
 
2249
        conf.remove('foo')
 
2250
        # Did we get it back ?
 
2251
        self.assertEquals(None, conf.get('foo'))
 
2252
 
 
2253
    def test_remove_unknown(self):
 
2254
        store = config.IniFileStore(self.get_transport(), 'test.conf')
 
2255
        conf = config.Stack([store.get_sections], store)
 
2256
        self.assertRaises(KeyError, conf.remove, 'I_do_not_exist')
 
2257
 
 
2258
 
1817
2259
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
1818
2260
 
1819
2261
    def setUp(self):
1820
2262
        super(TestConfigGetOptions, self).setUp()
1821
2263
        create_configs(self)
1822
2264
 
1823
 
    # One variable in none of the above
1824
2265
    def test_no_variable(self):
1825
2266
        # Using branch should query branch, locations and bazaar
1826
2267
        self.assertOptions([], self.branch_config)
2483
2924
            raise TestSkipped("User name inference not implemented on win32")
2484
2925
        realname, address = config._auto_user_id()
2485
2926
        if os.path.exists('/etc/mailname'):
2486
 
            self.assertTrue(realname)
2487
 
            self.assertTrue(address)
 
2927
            self.assertIsNot(None, realname)
 
2928
            self.assertIsNot(None, address)
2488
2929
        else:
2489
2930
            self.assertEquals((None, None), (realname, address))
2490
2931