~bzr-pqm/bzr/bzr.dev

5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2005-2009, 2011 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
974.1.44 by aaron.bentley at utoronto
Added test of double-add in ImmutableStore
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
974.1.44 by aaron.bentley at utoronto
Added test of double-add in ImmutableStore
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
974.1.44 by aaron.bentley at utoronto
Added test of double-add in ImmutableStore
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
974.1.44 by aaron.bentley at utoronto
Added test of double-add in ImmutableStore
16
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
17
"""Test Store implementations."""
18
1092.2.24 by Robert Collins
merge from martins newformat branch - brings in transport abstraction
19
from cStringIO import StringIO
1185.1.46 by Robert Collins
Aarons branch --basis patch
20
import os
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
21
import gzip
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
22
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
23
import bzrlib.errors as errors
5579.3.1 by Jelmer Vernooij
Remove unused imports.
24
from bzrlib.errors import BzrError
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
25
from bzrlib.store import TransportStore
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
26
from bzrlib.store.text import TextStore
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
27
from bzrlib.store.versioned import VersionedFileStore
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
28
from bzrlib.tests import TestCase, TestCaseInTempDir, TestCaseWithTransport
29
import bzrlib.transactions as transactions
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
30
import bzrlib.transport as transport
1442.1.46 by Robert Collins
test simple has_id
31
from bzrlib.transport.memory import MemoryTransport
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
32
from bzrlib.weave import WeaveFile
974.1.44 by aaron.bentley at utoronto
Added test of double-add in ImmutableStore
33
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
34
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
35
class TestStores(object):
1185.16.146 by Martin Pool
Fix up assert with sideeffects in CompressedTextStore._copy_one
36
    """Mixin template class that provides some common tests for stores"""
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
37
38
    def check_content(self, store, fileid, value):
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
39
        f = store.get(fileid)
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
40
        self.assertEqual(f.read(), value)
41
42
    def fill_store(self, store):
43
        store.add(StringIO('hello'), 'a')
44
        store.add(StringIO('other'), 'b')
45
        store.add(StringIO('something'), 'c')
46
        store.add(StringIO('goodbye'), '123123')
47
48
    def test_copy_all(self):
49
        """Test copying"""
50
        os.mkdir('a')
51
        store_a = self.get_store('a')
1955.3.13 by John Arbash Meinel
Run the full test suite, and fix up any deprecation warnings.
52
        store_a.add(StringIO('foo'), '1')
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
53
        os.mkdir('b')
54
        store_b = self.get_store('b')
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
55
        store_b.copy_all_ids(store_a)
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
56
        self.assertEqual(store_a.get('1').read(), 'foo')
57
        self.assertEqual(store_b.get('1').read(), 'foo')
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
58
        # TODO: Switch the exception form UnlistableStore to
59
        #       or make Stores throw UnlistableStore if their
60
        #       Transport doesn't support listing
61
        # store_c = RemoteStore('http://example.com/')
62
        # self.assertRaises(UnlistableStore, copy_all, store_c, store_b)
63
64
    def test_get(self):
65
        store = self.get_store()
66
        self.fill_store(store)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
67
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
68
        self.check_content(store, 'a', 'hello')
69
        self.check_content(store, 'b', 'other')
70
        self.check_content(store, 'c', 'something')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
71
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
72
        # Make sure that requesting a non-existing file fails
73
        self.assertRaises(KeyError, self.check_content, store, 'd', None)
74
974.1.44 by aaron.bentley at utoronto
Added test of double-add in ImmutableStore
75
    def test_multiple_add(self):
76
        """Multiple add with same ID should raise a BzrError"""
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
77
        store = self.get_store()
78
        self.fill_store(store)
79
        self.assertRaises(BzrError, store.add, StringIO('goodbye'), '123123')
80
81
82
class TestCompressedTextStore(TestCaseInTempDir, TestStores):
83
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
84
    def get_store(self, path=u'.'):
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
85
        t = transport.get_transport_from_path(path)
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
86
        return TextStore(t, compressed=True)
1185.11.1 by John Arbash Meinel
(broken) Transport work is merged in. Tests do not pass yet.
87
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
88
    def test_total_size(self):
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
89
        store = self.get_store(u'.')
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
90
        store.register_suffix('dsc')
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
91
        store.add(StringIO('goodbye'), '123123')
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
92
        store.add(StringIO('goodbye2'), '123123', 'dsc')
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
93
        # these get gzipped - content should be stable
94
        self.assertEqual(store.total_size(), (2, 55))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
95
1442.1.32 by Robert Collins
Teach CompressedTextStore._relpath to support file suffixes too.
96
    def test__relpath_suffixed(self):
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
97
        my_store = TextStore(MockTransport(),
98
                             prefixed=True, compressed=True)
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
99
        my_store.register_suffix('dsc')
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
100
        self.assertEqual('45/foo.dsc', my_store._relpath('foo', ['dsc']))
1442.1.32 by Robert Collins
Teach CompressedTextStore._relpath to support file suffixes too.
101
1404 by Robert Collins
only pull remote text weaves once per fetch operation
102
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
103
class TestMemoryStore(TestCase):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
104
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
105
    def get_store(self):
1651.1.7 by Martin Pool
Move small ImmutableMemoryStore class into test module,
106
        return TextStore(MemoryTransport())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
107
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
108
    def test_add_and_retrieve(self):
109
        store = self.get_store()
110
        store.add(StringIO('hello'), 'aa')
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
111
        self.assertNotEqual(store.get('aa'), None)
112
        self.assertEqual(store.get('aa').read(), 'hello')
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
113
        store.add(StringIO('hello world'), 'bb')
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
114
        self.assertNotEqual(store.get('bb'), None)
115
        self.assertEqual(store.get('bb').read(), 'hello world')
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
116
117
    def test_missing_is_absent(self):
118
        store = self.get_store()
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
119
        self.assertFalse('aa' in store)
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
120
121
    def test_adding_fails_when_present(self):
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
122
        my_store = self.get_store()
123
        my_store.add(StringIO('hello'), 'aa')
1442.1.44 by Robert Collins
Many transport related tweaks:
124
        self.assertRaises(BzrError,
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
125
                          my_store.add, StringIO('hello'), 'aa')
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
126
127
    def test_total_size(self):
128
        store = self.get_store()
129
        store.add(StringIO('goodbye'), '123123')
130
        store.add(StringIO('goodbye2'), '123123.dsc')
131
        self.assertEqual(store.total_size(), (2, 15))
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
132
        # TODO: Switch the exception form UnlistableStore to
133
        #       or make Stores throw UnlistableStore if their
134
        #       Transport doesn't support listing
135
        # store_c = RemoteStore('http://example.com/')
136
        # self.assertRaises(UnlistableStore, copy_all, store_c, store_b)
137
1404 by Robert Collins
only pull remote text weaves once per fetch operation
138
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
139
class TestTextStore(TestCaseInTempDir, TestStores):
140
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
141
    def get_store(self, path=u'.'):
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
142
        t = transport.get_transport_from_path(path)
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
143
        return TextStore(t, compressed=False)
1442.1.34 by Robert Collins
Remove the Store.get multiple-get interface which was not used, and remove much spurious duplication in teststore.py.
144
145
    def test_total_size(self):
146
        store = self.get_store()
147
        store.add(StringIO('goodbye'), '123123')
148
        store.add(StringIO('goodbye2'), '123123.dsc')
149
        self.assertEqual(store.total_size(), (2, 15))
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
150
        # TODO: Switch the exception form UnlistableStore to
151
        #       or make Stores throw UnlistableStore if their
152
        #       Transport doesn't support listing
153
        # store_c = RemoteStore('http://example.com/')
154
        # self.assertRaises(UnlistableStore, copy_all, store_c, store_b)
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
155
156
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
157
class TestMixedTextStore(TestCaseInTempDir, TestStores):
158
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
159
    def get_store(self, path=u'.', compressed=True):
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
160
        t = transport.get_transport_from_path(path)
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
161
        return TextStore(t, compressed=compressed)
162
163
    def test_get_mixed(self):
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
164
        cs = self.get_store(u'.', compressed=True)
165
        s = self.get_store(u'.', compressed=False)
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
166
        cs.add(StringIO('hello there'), 'a')
167
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
168
        self.assertPathExists('a.gz')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
169
        self.assertFalse(os.path.lexists('a'))
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
170
171
        self.assertEquals(gzip.GzipFile('a.gz').read(), 'hello there')
172
173
        self.assertEquals(cs.has_id('a'), True)
174
        self.assertEquals(s.has_id('a'), True)
175
        self.assertEquals(cs.get('a').read(), 'hello there')
176
        self.assertEquals(s.get('a').read(), 'hello there')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
177
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
178
        self.assertRaises(BzrError, s.add, StringIO('goodbye'), 'a')
179
180
        s.add(StringIO('goodbye'), 'b')
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
181
        self.assertPathExists('b')
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
182
        self.assertFalse(os.path.lexists('b.gz'))
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
183
        self.assertEquals(open('b').read(), 'goodbye')
184
185
        self.assertEquals(cs.has_id('b'), True)
186
        self.assertEquals(s.has_id('b'), True)
187
        self.assertEquals(cs.get('b').read(), 'goodbye')
188
        self.assertEquals(s.get('b').read(), 'goodbye')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
189
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
190
        self.assertRaises(BzrError, cs.add, StringIO('again'), 'b')
191
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
192
class MockTransport(transport.Transport):
193
    """A fake transport for testing with."""
194
1442.1.30 by Robert Collins
Add stuf has and mkdir to MockTransport to enable testing store adds
195
    def has(self, filename):
196
        return False
197
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
198
    def __init__(self, url=None):
199
        if url is None:
200
            url = "http://example.com"
201
        super(MockTransport, self).__init__(url)
202
1442.1.30 by Robert Collins
Add stuf has and mkdir to MockTransport to enable testing store adds
203
    def mkdir(self, filename):
204
        return
205
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
206
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
207
class InstrumentedTransportStore(TransportStore):
1442.1.29 by Robert Collins
create an instrumented transport store for testing common logic.
208
    """An instrumented TransportStore.
209
210
    Here we replace template method worker methods with calls that record the
211
    expected results.
212
    """
213
214
    def _add(self, filename, file):
215
        self._calls.append(("_add", filename, file))
216
217
    def __init__(self, transport, prefixed=False):
218
        super(InstrumentedTransportStore, self).__init__(transport, prefixed)
219
        self._calls = []
220
221
222
class TestInstrumentedTransportStore(TestCase):
223
224
    def test__add_records(self):
225
        my_store = InstrumentedTransportStore(MockTransport())
1442.1.30 by Robert Collins
Add stuf has and mkdir to MockTransport to enable testing store adds
226
        my_store._add("filename", "file")
1442.1.29 by Robert Collins
create an instrumented transport store for testing common logic.
227
        self.assertEqual([("_add", "filename", "file")], my_store._calls)
228
229
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
230
class TestMockTransport(TestCase):
231
232
    def test_isinstance(self):
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
233
        self.assertIsInstance(MockTransport(), transport.Transport)
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
234
1442.1.30 by Robert Collins
Add stuf has and mkdir to MockTransport to enable testing store adds
235
    def test_has(self):
236
        self.assertEqual(False, MockTransport().has('foo'))
237
238
    def test_mkdir(self):
239
        MockTransport().mkdir('45')
240
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
241
242
class TestTransportStore(TestCase):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
243
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
244
    def test__relpath_invalid(self):
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
245
        my_store = TransportStore(MockTransport())
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
246
        self.assertRaises(ValueError, my_store._relpath, '/foo')
247
        self.assertRaises(ValueError, my_store._relpath, 'foo/')
248
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
249
    def test_register_invalid_suffixes(self):
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
250
        my_store = TransportStore(MockTransport())
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
251
        self.assertRaises(ValueError, my_store.register_suffix, '/')
252
        self.assertRaises(ValueError, my_store.register_suffix, '.gz/bar')
253
254
    def test__relpath_unregister_suffixes(self):
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
255
        my_store = TransportStore(MockTransport())
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
256
        self.assertRaises(ValueError, my_store._relpath, 'foo', ['gz'])
257
        self.assertRaises(ValueError, my_store._relpath, 'foo', ['dsc', 'gz'])
1442.1.27 by Robert Collins
Check that file suffixes in TransportStore are also valid
258
1442.1.25 by Robert Collins
Test TransportStore._relpath for simple cases: pull up _prefixed attribute as a result.
259
    def test__relpath_simple(self):
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
260
        my_store = TransportStore(MockTransport())
1442.1.25 by Robert Collins
Test TransportStore._relpath for simple cases: pull up _prefixed attribute as a result.
261
        self.assertEqual("foo", my_store._relpath('foo'))
1442.1.26 by Robert Collins
Pull up _relpath with gz suffix for CompressedTextStore into TransportStore
262
263
    def test__relpath_prefixed(self):
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
264
        my_store = TransportStore(MockTransport(), True)
1442.1.26 by Robert Collins
Pull up _relpath with gz suffix for CompressedTextStore into TransportStore
265
        self.assertEqual('45/foo', my_store._relpath('foo'))
266
267
    def test__relpath_simple_suffixed(self):
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
268
        my_store = TransportStore(MockTransport())
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
269
        my_store.register_suffix('bar')
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
270
        my_store.register_suffix('baz')
271
        self.assertEqual('foo.baz', my_store._relpath('foo', ['baz']))
272
        self.assertEqual('foo.bar.baz', my_store._relpath('foo', ['bar', 'baz']))
1442.1.27 by Robert Collins
Check that file suffixes in TransportStore are also valid
273
274
    def test__relpath_prefixed_suffixed(self):
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
275
        my_store = TransportStore(MockTransport(), True)
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
276
        my_store.register_suffix('bar')
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
277
        my_store.register_suffix('baz')
278
        self.assertEqual('45/foo.baz', my_store._relpath('foo', ['baz']))
279
        self.assertEqual('45/foo.bar.baz',
280
                         my_store._relpath('foo', ['bar', 'baz']))
1442.1.27 by Robert Collins
Check that file suffixes in TransportStore are also valid
281
1442.1.31 by Robert Collins
test that TransportStore.add calls _add appropriately.
282
    def test_add_simple(self):
283
        stream = StringIO("content")
284
        my_store = InstrumentedTransportStore(MockTransport())
285
        my_store.add(stream, "foo")
286
        self.assertEqual([("_add", "foo", stream)], my_store._calls)
287
288
    def test_add_prefixed(self):
289
        stream = StringIO("content")
290
        my_store = InstrumentedTransportStore(MockTransport(), True)
291
        my_store.add(stream, "foo")
292
        self.assertEqual([("_add", "45/foo", stream)], my_store._calls)
1442.1.33 by Robert Collins
teach TransportStore.add to accept an optional file suffix, which does not alter the fileid.
293
294
    def test_add_simple_suffixed(self):
295
        stream = StringIO("content")
296
        my_store = InstrumentedTransportStore(MockTransport())
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
297
        my_store.register_suffix('dsc')
1442.1.33 by Robert Collins
teach TransportStore.add to accept an optional file suffix, which does not alter the fileid.
298
        my_store.add(stream, "foo", 'dsc')
299
        self.assertEqual([("_add", "foo.dsc", stream)], my_store._calls)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
300
1442.1.33 by Robert Collins
teach TransportStore.add to accept an optional file suffix, which does not alter the fileid.
301
    def test_add_simple_suffixed(self):
302
        stream = StringIO("content")
303
        my_store = InstrumentedTransportStore(MockTransport(), True)
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
304
        my_store.register_suffix('dsc')
1442.1.33 by Robert Collins
teach TransportStore.add to accept an optional file suffix, which does not alter the fileid.
305
        my_store.add(stream, "foo", 'dsc')
306
        self.assertEqual([("_add", "45/foo.dsc", stream)], my_store._calls)
1442.1.46 by Robert Collins
test simple has_id
307
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
308
    def get_populated_store(self, prefixed=False,
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
309
            store_class=TextStore, compressed=False):
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
310
        my_store = store_class(MemoryTransport(), prefixed,
311
                               compressed=compressed)
1442.1.46 by Robert Collins
test simple has_id
312
        my_store.register_suffix('sig')
1442.1.48 by Robert Collins
test that the presence of a signature does not make a missing base file magically appear present
313
        stream = StringIO("signature")
1442.1.46 by Robert Collins
test simple has_id
314
        my_store.add(stream, "foo", 'sig')
315
        stream = StringIO("content")
316
        my_store.add(stream, "foo")
1442.1.48 by Robert Collins
test that the presence of a signature does not make a missing base file magically appear present
317
        stream = StringIO("signature for missing base")
318
        my_store.add(stream, "missing", 'sig')
1442.1.46 by Robert Collins
test simple has_id
319
        return my_store
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
320
1442.1.46 by Robert Collins
test simple has_id
321
    def test_has_simple(self):
322
        my_store = self.get_populated_store()
323
        self.assertEqual(True, my_store.has_id('foo'))
1442.1.47 by Robert Collins
test for has with suffixed files
324
        my_store = self.get_populated_store(True)
325
        self.assertEqual(True, my_store.has_id('foo'))
326
327
    def test_has_suffixed(self):
328
        my_store = self.get_populated_store()
329
        self.assertEqual(True, my_store.has_id('foo', 'sig'))
330
        my_store = self.get_populated_store(True)
331
        self.assertEqual(True, my_store.has_id('foo', 'sig'))
1442.1.48 by Robert Collins
test that the presence of a signature does not make a missing base file magically appear present
332
333
    def test_has_suffixed_no_base(self):
334
        my_store = self.get_populated_store()
335
        self.assertEqual(False, my_store.has_id('missing'))
336
        my_store = self.get_populated_store(True)
337
        self.assertEqual(False, my_store.has_id('missing'))
1442.1.50 by Robert Collins
test get with suffixes
338
339
    def test_get_simple(self):
340
        my_store = self.get_populated_store()
341
        self.assertEqual('content', my_store.get('foo').read())
342
        my_store = self.get_populated_store(True)
343
        self.assertEqual('content', my_store.get('foo').read())
344
345
    def test_get_suffixed(self):
346
        my_store = self.get_populated_store()
347
        self.assertEqual('signature', my_store.get('foo', 'sig').read())
348
        my_store = self.get_populated_store(True)
349
        self.assertEqual('signature', my_store.get('foo', 'sig').read())
350
351
    def test_get_suffixed_no_base(self):
352
        my_store = self.get_populated_store()
353
        self.assertEqual('signature for missing base',
354
                         my_store.get('missing', 'sig').read())
355
        my_store = self.get_populated_store(True)
356
        self.assertEqual('signature for missing base',
357
                         my_store.get('missing', 'sig').read())
1442.1.51 by Robert Collins
teach iter about suffixes
358
359
    def test___iter__no_suffix(self):
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
360
        my_store = TextStore(MemoryTransport(),
361
                             prefixed=False, compressed=False)
1442.1.51 by Robert Collins
teach iter about suffixes
362
        stream = StringIO("content")
363
        my_store.add(stream, "foo")
364
        self.assertEqual(set(['foo']),
365
                         set(my_store.__iter__()))
366
367
    def test___iter__(self):
368
        self.assertEqual(set(['foo']),
369
                         set(self.get_populated_store().__iter__()))
370
        self.assertEqual(set(['foo']),
371
                         set(self.get_populated_store(True).__iter__()))
372
373
    def test___iter__compressed(self):
374
        self.assertEqual(set(['foo']),
375
                         set(self.get_populated_store(
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
376
                             compressed=True).__iter__()))
1442.1.51 by Robert Collins
teach iter about suffixes
377
        self.assertEqual(set(['foo']),
378
                         set(self.get_populated_store(
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
379
                             True, compressed=True).__iter__()))
1442.1.51 by Robert Collins
teach iter about suffixes
380
381
    def test___len__(self):
382
        self.assertEqual(1, len(self.get_populated_store()))
1442.1.54 by Robert Collins
Teach store.copy_all about fileid suffixes
383
384
    def test_copy_suffixes(self):
385
        from_store = self.get_populated_store()
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
386
        to_store = TextStore(MemoryTransport(),
387
                             prefixed=True, compressed=True)
1442.1.54 by Robert Collins
Teach store.copy_all about fileid suffixes
388
        to_store.register_suffix('sig')
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
389
        to_store.copy_all_ids(from_store)
1442.1.54 by Robert Collins
Teach store.copy_all about fileid suffixes
390
        self.assertEqual(1, len(to_store))
391
        self.assertEqual(set(['foo']), set(to_store.__iter__()))
392
        self.assertEqual('content', to_store.get('foo').read())
393
        self.assertEqual('signature', to_store.get('foo', 'sig').read())
394
        self.assertRaises(KeyError, to_store.get, 'missing', 'sig')
1469 by Robert Collins
Change Transport.* to work with URL's.
395
396
    def test_relpath_escaped(self):
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
397
        my_store = TransportStore(MemoryTransport())
1469 by Robert Collins
Change Transport.* to work with URL's.
398
        self.assertEqual('%25', my_store._relpath('%'))
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
399
1608.2.12 by Martin Pool
Store-escaping must quote uppercase characters too, so that they're safely
400
    def test_escaped_uppercase(self):
401
        """Uppercase letters are escaped for safety on Windows"""
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
402
        my_store = TransportStore(MemoryTransport(), prefixed=True,
3350.6.1 by Robert Collins
* New ``versionedfile.KeyMapper`` interface to abstract out the access to
403
            escaped=True)
1608.2.12 by Martin Pool
Store-escaping must quote uppercase characters too, so that they're safely
404
        # a particularly perverse file-id! :-)
3350.6.1 by Robert Collins
* New ``versionedfile.KeyMapper`` interface to abstract out the access to
405
        self.assertEquals(my_store._relpath('C:<>'), 'be/%2543%253a%253c%253e')
1608.2.12 by Martin Pool
Store-escaping must quote uppercase characters too, so that they're safely
406
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
407
408
class TestVersionFileStore(TestCaseWithTransport):
409
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
410
    def get_scope(self):
411
        return self._transaction
412
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
413
    def setUp(self):
414
        super(TestVersionFileStore, self).setUp()
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
415
        self.vfstore = VersionedFileStore(MemoryTransport(),
416
            versionedfile_class=WeaveFile)
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
417
        self.vfstore.get_scope = self.get_scope
418
        self._transaction = None
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
419
420
    def test_get_weave_registers_dirty_in_write(self):
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
421
        self._transaction = transactions.WriteTransaction()
422
        vf = self.vfstore.get_weave_or_empty('id', self._transaction)
423
        self._transaction.finish()
424
        self._transaction = None
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
425
        self.assertRaises(errors.OutSideTransaction, vf.add_lines, 'b', [], [])
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
426
        self._transaction = transactions.WriteTransaction()
427
        vf = self.vfstore.get_weave('id', self._transaction)
428
        self._transaction.finish()
429
        self._transaction = None
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
430
        self.assertRaises(errors.OutSideTransaction, vf.add_lines, 'b', [], [])
431
432
    def test_get_weave_readonly_cant_write(self):
3316.2.3 by Robert Collins
Remove manual notification of transaction finishing on versioned files.
433
        self._transaction = transactions.WriteTransaction()
434
        vf = self.vfstore.get_weave_or_empty('id', self._transaction)
435
        self._transaction.finish()
436
        self._transaction = transactions.ReadOnlyTransaction()
437
        vf = self.vfstore.get_weave_or_empty('id', self._transaction)
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
438
        self.assertRaises(errors.ReadOnlyError, vf.add_lines, 'b', [], [])
3350.6.1 by Robert Collins
* New ``versionedfile.KeyMapper`` interface to abstract out the access to
439
440
    def test___iter__escaped(self):
5582.9.21 by Jelmer Vernooij
Remove weave references from VersionedfileStore.
441
        self.vfstore = VersionedFileStore(MemoryTransport(),
442
            prefixed=True, escaped=True, versionedfile_class=WeaveFile)
3350.6.1 by Robert Collins
* New ``versionedfile.KeyMapper`` interface to abstract out the access to
443
        self.vfstore.get_scope = self.get_scope
444
        self._transaction = transactions.WriteTransaction()
445
        vf = self.vfstore.get_weave_or_empty(' ', self._transaction)
446
        vf.add_lines('a', [], [])
447
        del vf
448
        self._transaction.finish()
449
        self.assertEqual([' '], list(self.vfstore))