~bzr-pqm/bzr/bzr.dev

974.1.44 by aaron.bentley at utoronto
Added test of double-add in ImmutableStore
1
# Copyright (C) 2005 by Canonical Development Ltd
2
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.
7
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.
12
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
24
from bzrlib.errors import BzrError, UnlistableStore, NoSuchFile
1185.11.1 by John Arbash Meinel
(broken) Transport work is merged in. Tests do not pass yet.
25
from bzrlib.transport.local import LocalTransport
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
26
from bzrlib.store.text import TextStore
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
27
from bzrlib.tests import TestCase, TestCaseInTempDir, TestCaseWithTransport
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
28
import bzrlib.store as store
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
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
974.1.44 by aaron.bentley at utoronto
Added test of double-add in ImmutableStore
32
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
33
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.
34
class TestStores(object):
1185.16.146 by Martin Pool
Fix up assert with sideeffects in CompressedTextStore._copy_one
35
    """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.
36
37
    def check_content(self, store, fileid, value):
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
38
        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.
39
        self.assertEqual(f.read(), value)
40
41
    def fill_store(self, store):
42
        store.add(StringIO('hello'), 'a')
43
        store.add(StringIO('other'), 'b')
44
        store.add(StringIO('something'), 'c')
45
        store.add(StringIO('goodbye'), '123123')
46
47
    def test_copy_all(self):
48
        """Test copying"""
49
        os.mkdir('a')
50
        store_a = self.get_store('a')
51
        store_a.add('foo', '1')
52
        os.mkdir('b')
53
        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.
54
        store_b.copy_all_ids(store_a)
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
55
        self.assertEqual(store_a.get('1').read(), 'foo')
56
        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.
57
        # TODO: Switch the exception form UnlistableStore to
58
        #       or make Stores throw UnlistableStore if their
59
        #       Transport doesn't support listing
60
        # store_c = RemoteStore('http://example.com/')
61
        # self.assertRaises(UnlistableStore, copy_all, store_c, store_b)
62
63
    def test_get(self):
64
        store = self.get_store()
65
        self.fill_store(store)
66
    
67
        self.check_content(store, 'a', 'hello')
68
        self.check_content(store, 'b', 'other')
69
        self.check_content(store, 'c', 'something')
70
    
71
        # Make sure that requesting a non-existing file fails
72
        self.assertRaises(KeyError, self.check_content, store, 'd', None)
73
974.1.44 by aaron.bentley at utoronto
Added test of double-add in ImmutableStore
74
    def test_multiple_add(self):
75
        """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.
76
        store = self.get_store()
77
        self.fill_store(store)
78
        self.assertRaises(BzrError, store.add, StringIO('goodbye'), '123123')
79
80
81
class TestCompressedTextStore(TestCaseInTempDir, TestStores):
82
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
83
    def get_store(self, path=u'.'):
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.
84
        t = LocalTransport(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
85
        return TextStore(t, compressed=True)
1185.11.1 by John Arbash Meinel
(broken) Transport work is merged in. Tests do not pass yet.
86
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
87
    def test_total_size(self):
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
88
        store = self.get_store(u'.')
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
89
        store.register_suffix('dsc')
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
90
        store.add(StringIO('goodbye'), '123123')
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
91
        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
92
        # these get gzipped - content should be stable
93
        self.assertEqual(store.total_size(), (2, 55))
94
        
1442.1.32 by Robert Collins
Teach CompressedTextStore._relpath to support file suffixes too.
95
    def test__relpath_suffixed(self):
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
96
        my_store = TextStore(MockTransport(),
97
                             prefixed=True, compressed=True)
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
98
        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
99
        self.assertEqual('45/foo.dsc', my_store._relpath('foo', ['dsc']))
1442.1.32 by Robert Collins
Teach CompressedTextStore._relpath to support file suffixes too.
100
1404 by Robert Collins
only pull remote text weaves once per fetch operation
101
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
102
class TestMemoryStore(TestCase):
103
    
104
    def get_store(self):
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
105
        return store.ImmutableMemoryStore()
1092.2.1 by Robert Collins
minor refactors to store, create an ImmutableMemoryStore for testing or other such operations
106
    
107
    def test_imports(self):
108
        from bzrlib.store import ImmutableMemoryStore
109
110
    def test_add_and_retrieve(self):
111
        store = self.get_store()
112
        store.add(StringIO('hello'), 'aa')
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
113
        self.assertNotEqual(store.get('aa'), None)
114
        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
115
        store.add(StringIO('hello world'), 'bb')
1442.1.35 by Robert Collins
convert all users of __getitem__ into TransportStores to use .get instead
116
        self.assertNotEqual(store.get('bb'), None)
117
        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
118
119
    def test_missing_is_absent(self):
120
        store = self.get_store()
121
        self.failIf('aa' in store)
122
123
    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
124
        my_store = self.get_store()
125
        my_store.add(StringIO('hello'), 'aa')
1442.1.44 by Robert Collins
Many transport related tweaks:
126
        self.assertRaises(BzrError,
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
127
                          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
128
129
    def test_total_size(self):
130
        store = self.get_store()
131
        store.add(StringIO('goodbye'), '123123')
132
        store.add(StringIO('goodbye2'), '123123.dsc')
133
        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.
134
        # TODO: Switch the exception form UnlistableStore to
135
        #       or make Stores throw UnlistableStore if their
136
        #       Transport doesn't support listing
137
        # store_c = RemoteStore('http://example.com/')
138
        # self.assertRaises(UnlistableStore, copy_all, store_c, store_b)
139
1404 by Robert Collins
only pull remote text weaves once per fetch operation
140
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.
141
class TestTextStore(TestCaseInTempDir, TestStores):
142
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
143
    def get_store(self, path=u'.'):
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
        t = LocalTransport(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
145
        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.
146
147
    def test_total_size(self):
148
        store = self.get_store()
149
        store.add(StringIO('goodbye'), '123123')
150
        store.add(StringIO('goodbye2'), '123123.dsc')
151
        self.assertEqual(store.total_size(), (2, 15))
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
152
        # TODO: Switch the exception form UnlistableStore to
153
        #       or make Stores throw UnlistableStore if their
154
        #       Transport doesn't support listing
155
        # store_c = RemoteStore('http://example.com/')
156
        # 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
157
158
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
159
class TestMixedTextStore(TestCaseInTempDir, TestStores):
160
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
161
    def get_store(self, path=u'.', compressed=True):
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
162
        t = LocalTransport(path)
163
        return TextStore(t, compressed=compressed)
164
165
    def test_get_mixed(self):
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
166
        cs = self.get_store(u'.', compressed=True)
167
        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
168
        cs.add(StringIO('hello there'), 'a')
169
170
        self.failUnlessExists('a.gz')
171
        self.failIf(os.path.lexists('a'))
172
173
        self.assertEquals(gzip.GzipFile('a.gz').read(), 'hello there')
174
175
        self.assertEquals(cs.has_id('a'), True)
176
        self.assertEquals(s.has_id('a'), True)
177
        self.assertEquals(cs.get('a').read(), 'hello there')
178
        self.assertEquals(s.get('a').read(), 'hello there')
179
        
180
        self.assertRaises(BzrError, s.add, StringIO('goodbye'), 'a')
181
182
        s.add(StringIO('goodbye'), 'b')
183
        self.failUnlessExists('b')
184
        self.failIf(os.path.lexists('b.gz'))
185
        self.assertEquals(open('b').read(), 'goodbye')
186
187
        self.assertEquals(cs.has_id('b'), True)
188
        self.assertEquals(s.has_id('b'), True)
189
        self.assertEquals(cs.get('b').read(), 'goodbye')
190
        self.assertEquals(s.get('b').read(), 'goodbye')
191
        
192
        self.assertRaises(BzrError, cs.add, StringIO('again'), 'b')
193
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
194
class MockTransport(transport.Transport):
195
    """A fake transport for testing with."""
196
1442.1.30 by Robert Collins
Add stuf has and mkdir to MockTransport to enable testing store adds
197
    def has(self, filename):
198
        return False
199
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
200
    def __init__(self, url=None):
201
        if url is None:
202
            url = "http://example.com"
203
        super(MockTransport, self).__init__(url)
204
1442.1.30 by Robert Collins
Add stuf has and mkdir to MockTransport to enable testing store adds
205
    def mkdir(self, filename):
206
        return
207
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
208
1442.1.29 by Robert Collins
create an instrumented transport store for testing common logic.
209
class InstrumentedTransportStore(store.TransportStore):
210
    """An instrumented TransportStore.
211
212
    Here we replace template method worker methods with calls that record the
213
    expected results.
214
    """
215
216
    def _add(self, filename, file):
217
        self._calls.append(("_add", filename, file))
218
219
    def __init__(self, transport, prefixed=False):
220
        super(InstrumentedTransportStore, self).__init__(transport, prefixed)
221
        self._calls = []
222
223
224
class TestInstrumentedTransportStore(TestCase):
225
226
    def test__add_records(self):
227
        my_store = InstrumentedTransportStore(MockTransport())
1442.1.30 by Robert Collins
Add stuf has and mkdir to MockTransport to enable testing store adds
228
        my_store._add("filename", "file")
1442.1.29 by Robert Collins
create an instrumented transport store for testing common logic.
229
        self.assertEqual([("_add", "filename", "file")], my_store._calls)
230
231
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
232
class TestMockTransport(TestCase):
233
234
    def test_isinstance(self):
235
        self.failUnless(isinstance(MockTransport(), transport.Transport))
236
1442.1.30 by Robert Collins
Add stuf has and mkdir to MockTransport to enable testing store adds
237
    def test_has(self):
238
        self.assertEqual(False, MockTransport().has('foo'))
239
240
    def test_mkdir(self):
241
        MockTransport().mkdir('45')
242
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
243
244
class TestTransportStore(TestCase):
245
    
246
    def test__relpath_invalid(self):
247
        my_store = store.TransportStore(MockTransport())
248
        self.assertRaises(ValueError, my_store._relpath, '/foo')
249
        self.assertRaises(ValueError, my_store._relpath, 'foo/')
250
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
251
    def test_register_invalid_suffixes(self):
252
        my_store = store.TransportStore(MockTransport())
253
        self.assertRaises(ValueError, my_store.register_suffix, '/')
254
        self.assertRaises(ValueError, my_store.register_suffix, '.gz/bar')
255
256
    def test__relpath_unregister_suffixes(self):
257
        my_store = store.TransportStore(MockTransport())
258
        self.assertRaises(ValueError, my_store._relpath, 'foo', ['gz'])
259
        self.assertRaises(ValueError, my_store._relpath, 'foo', ['dsc', 'gz'])
1442.1.27 by Robert Collins
Check that file suffixes in TransportStore are also valid
260
1442.1.25 by Robert Collins
Test TransportStore._relpath for simple cases: pull up _prefixed attribute as a result.
261
    def test__relpath_simple(self):
262
        my_store = store.TransportStore(MockTransport())
263
        self.assertEqual("foo", my_store._relpath('foo'))
1442.1.26 by Robert Collins
Pull up _relpath with gz suffix for CompressedTextStore into TransportStore
264
265
    def test__relpath_prefixed(self):
266
        my_store = store.TransportStore(MockTransport(), True)
267
        self.assertEqual('45/foo', my_store._relpath('foo'))
268
269
    def test__relpath_simple_suffixed(self):
270
        my_store = store.TransportStore(MockTransport())
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
271
        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
272
        my_store.register_suffix('baz')
273
        self.assertEqual('foo.baz', my_store._relpath('foo', ['baz']))
274
        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
275
276
    def test__relpath_prefixed_suffixed(self):
277
        my_store = store.TransportStore(MockTransport(), True)
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
278
        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
279
        my_store.register_suffix('baz')
280
        self.assertEqual('45/foo.baz', my_store._relpath('foo', ['baz']))
281
        self.assertEqual('45/foo.bar.baz',
282
                         my_store._relpath('foo', ['bar', 'baz']))
1442.1.27 by Robert Collins
Check that file suffixes in TransportStore are also valid
283
1442.1.31 by Robert Collins
test that TransportStore.add calls _add appropriately.
284
    def test_add_simple(self):
285
        stream = StringIO("content")
286
        my_store = InstrumentedTransportStore(MockTransport())
287
        my_store.add(stream, "foo")
288
        self.assertEqual([("_add", "foo", stream)], my_store._calls)
289
290
    def test_add_prefixed(self):
291
        stream = StringIO("content")
292
        my_store = InstrumentedTransportStore(MockTransport(), True)
293
        my_store.add(stream, "foo")
294
        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.
295
296
    def test_add_simple_suffixed(self):
297
        stream = StringIO("content")
298
        my_store = InstrumentedTransportStore(MockTransport())
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
299
        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.
300
        my_store.add(stream, "foo", 'dsc')
301
        self.assertEqual([("_add", "foo.dsc", stream)], my_store._calls)
302
        
303
    def test_add_simple_suffixed(self):
304
        stream = StringIO("content")
305
        my_store = InstrumentedTransportStore(MockTransport(), True)
1442.1.43 by Robert Collins
add registration of suffixes, in preparation for ensuring iteration is regular
306
        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.
307
        my_store.add(stream, "foo", 'dsc')
308
        self.assertEqual([("_add", "45/foo.dsc", stream)], my_store._calls)
1442.1.46 by Robert Collins
test simple has_id
309
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
    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
311
            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
312
        my_store = store_class(MemoryTransport(), prefixed,
313
                               compressed=compressed)
1442.1.46 by Robert Collins
test simple has_id
314
        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
315
        stream = StringIO("signature")
1442.1.46 by Robert Collins
test simple has_id
316
        my_store.add(stream, "foo", 'sig')
317
        stream = StringIO("content")
318
        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
319
        stream = StringIO("signature for missing base")
320
        my_store.add(stream, "missing", 'sig')
1442.1.46 by Robert Collins
test simple has_id
321
        return my_store
322
        
323
    def test_has_simple(self):
324
        my_store = self.get_populated_store()
325
        self.assertEqual(True, my_store.has_id('foo'))
1442.1.47 by Robert Collins
test for has with suffixed files
326
        my_store = self.get_populated_store(True)
327
        self.assertEqual(True, my_store.has_id('foo'))
328
329
    def test_has_suffixed(self):
330
        my_store = self.get_populated_store()
331
        self.assertEqual(True, my_store.has_id('foo', 'sig'))
332
        my_store = self.get_populated_store(True)
333
        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
334
335
    def test_has_suffixed_no_base(self):
336
        my_store = self.get_populated_store()
337
        self.assertEqual(False, my_store.has_id('missing'))
338
        my_store = self.get_populated_store(True)
339
        self.assertEqual(False, my_store.has_id('missing'))
1442.1.50 by Robert Collins
test get with suffixes
340
341
    def test_get_simple(self):
342
        my_store = self.get_populated_store()
343
        self.assertEqual('content', my_store.get('foo').read())
344
        my_store = self.get_populated_store(True)
345
        self.assertEqual('content', my_store.get('foo').read())
346
347
    def test_get_suffixed(self):
348
        my_store = self.get_populated_store()
349
        self.assertEqual('signature', my_store.get('foo', 'sig').read())
350
        my_store = self.get_populated_store(True)
351
        self.assertEqual('signature', my_store.get('foo', 'sig').read())
352
353
    def test_get_suffixed_no_base(self):
354
        my_store = self.get_populated_store()
355
        self.assertEqual('signature for missing base',
356
                         my_store.get('missing', 'sig').read())
357
        my_store = self.get_populated_store(True)
358
        self.assertEqual('signature for missing base',
359
                         my_store.get('missing', 'sig').read())
1442.1.51 by Robert Collins
teach iter about suffixes
360
361
    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.
362
        my_store = TextStore(MemoryTransport(),
363
                             prefixed=False, compressed=False)
1442.1.51 by Robert Collins
teach iter about suffixes
364
        stream = StringIO("content")
365
        my_store.add(stream, "foo")
366
        self.assertEqual(set(['foo']),
367
                         set(my_store.__iter__()))
368
369
    def test___iter__(self):
370
        self.assertEqual(set(['foo']),
371
                         set(self.get_populated_store().__iter__()))
372
        self.assertEqual(set(['foo']),
373
                         set(self.get_populated_store(True).__iter__()))
374
375
    def test___iter__compressed(self):
376
        self.assertEqual(set(['foo']),
377
                         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
378
                             compressed=True).__iter__()))
1442.1.51 by Robert Collins
teach iter about suffixes
379
        self.assertEqual(set(['foo']),
380
                         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
381
                             True, compressed=True).__iter__()))
1442.1.51 by Robert Collins
teach iter about suffixes
382
383
    def test___len__(self):
384
        self.assertEqual(1, len(self.get_populated_store()))
1442.1.54 by Robert Collins
Teach store.copy_all about fileid suffixes
385
386
    def test_copy_suffixes(self):
387
        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.
388
        to_store = TextStore(MemoryTransport(),
389
                             prefixed=True, compressed=True)
1442.1.54 by Robert Collins
Teach store.copy_all about fileid suffixes
390
        to_store.register_suffix('sig')
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
391
        to_store.copy_all_ids(from_store)
1442.1.54 by Robert Collins
Teach store.copy_all about fileid suffixes
392
        self.assertEqual(1, len(to_store))
393
        self.assertEqual(set(['foo']), set(to_store.__iter__()))
394
        self.assertEqual('content', to_store.get('foo').read())
395
        self.assertEqual('signature', to_store.get('foo', 'sig').read())
396
        self.assertRaises(KeyError, to_store.get, 'missing', 'sig')
1469 by Robert Collins
Change Transport.* to work with URL's.
397
398
    def test_relpath_escaped(self):
399
        my_store = store.TransportStore(MemoryTransport())
400
        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.
401
402
403
class TestVersionFileStore(TestCaseWithTransport):
404
405
    def setUp(self):
406
        super(TestVersionFileStore, self).setUp()
407
        self.vfstore = store.versioned.VersionedFileStore(MemoryTransport())
408
409
    def test_get_weave_registers_dirty_in_write(self):
410
        transaction = transactions.WriteTransaction()
411
        vf = self.vfstore.get_weave_or_empty('id', transaction)
412
        transaction.finish()
413
        self.assertRaises(errors.OutSideTransaction, vf.add_lines, 'b', [], [])
414
        transaction = transactions.WriteTransaction()
415
        vf = self.vfstore.get_weave('id', transaction)
416
        transaction.finish()
417
        self.assertRaises(errors.OutSideTransaction, vf.add_lines, 'b', [], [])
418
419
    def test_get_weave_or_empty_readonly_fails(self):
420
        transaction = transactions.ReadOnlyTransaction()
421
        vf = self.assertRaises(errors.ReadOnlyError,
422
                               self.vfstore.get_weave_or_empty,
423
                               'id',
424
                               transaction)
425
426
    def test_get_weave_readonly_cant_write(self):
427
        transaction = transactions.WriteTransaction()
428
        vf = self.vfstore.get_weave_or_empty('id', transaction)
429
        transaction.finish()
430
        transaction = transactions.ReadOnlyTransaction()
431
        vf = self.vfstore.get_weave_or_empty('id', transaction)
432
        self.assertRaises(errors.ReadOnlyError, vf.add_lines, 'b', [], [])
433