~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Patch Queue Manager
  • Date: 2012-01-05 10:39:49 UTC
  • mfrom: (6404.5.9 store-save-changes)
  • Revision ID: pqm@pqm.ubuntu.com-20120105103949-xxe5dkbfiu16q4ch
(vila) Provide Store.save_changes() to allow configuration store to be saved
 incrementally. (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
3000
3000
        self.assertLength(1, calls)
3001
3001
        self.assertEquals((store,), calls[0])
3002
3002
 
 
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())
 
3009
 
 
3010
    def test_remove_mark_dirty(self):
 
3011
        stack = config.MemoryStack('foo=bar')
 
3012
        self.assertLength(0, stack.store.dirty_sections)
 
3013
        stack.remove('foo')
 
3014
        self.assertLength(1, stack.store.dirty_sections)
 
3015
        self.assertTrue(stack.store._need_saving())
 
3016
 
 
3017
 
 
3018
class TestStoreSaveChanges(tests.TestCaseWithTransport):
 
3019
    """Tests that config changes are kept in memory and saved on-demand."""
 
3020
 
 
3021
    def setUp(self):
 
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')
 
3028
        self.warnings = []
 
3029
        def warning(*args):
 
3030
            self.warnings.append(args[0] % args[1:])
 
3031
        self.overrideAttr(trace, 'warning', warning)
 
3032
 
 
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)
 
3037
 
 
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)
 
3042
 
 
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))
 
3047
 
 
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')
 
3053
        s1.store.save()
 
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)
 
3062
 
 
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')
 
3068
        s1.store.save()
 
3069
        # Last speaker wins
 
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.')
 
3078
 
 
3079
    def test_concurrent_deletion(self):
 
3080
        self.st1._load_from_string('foo=bar')
 
3081
        self.st1.save()
 
3082
        s1 = self.get_stack(self.st1)
 
3083
        s2 = self.get_stack(self.st2)
 
3084
        s1.remove('foo')
 
3085
        s2.remove('foo')
 
3086
        s1.store.save_changes()
 
3087
        # No warning yet
 
3088
        self.assertLength(0, self.warnings)
 
3089
        s2.store.save_changes()
 
3090
        # Now we get one
 
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.')
 
3096
 
3003
3097
 
3004
3098
class TestQuotingIniFileStore(tests.TestCaseWithTransport):
3005
3099