/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.10 by John Arbash Meinel
Add StreamSink.insert_stream_without_locking
1
# Copyright (C) 2007-2011 Canonical Ltd
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
16
17
"""Tests for repository write groups."""
18
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
19
import sys
20
4343.3.2 by John Arbash Meinel
All stacking tests seem to be passing for dev6 repos
21
from bzrlib import (
5010.2.7 by Vincent Ladeuil
Fix per_repository/test_write_group.py imports.
22
    branch,
4343.3.2 by John Arbash Meinel
All stacking tests seem to be passing for dev6 repos
23
    bzrdir,
24
    errors,
25
    graph,
26
    memorytree,
27
    osutils,
28
    remote,
5010.2.7 by Vincent Ladeuil
Fix per_repository/test_write_group.py imports.
29
    tests,
4343.3.6 by John Arbash Meinel
Take out the _delta_across_repos flag.
30
    versionedfile,
4343.3.2 by John Arbash Meinel
All stacking tests seem to be passing for dev6 repos
31
    )
5017.3.43 by Vincent Ladeuil
-s bt.per_repository.test_write_group passing
32
from bzrlib.tests import (
33
    per_repository,
34
    test_server,
35
    )
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
36
from bzrlib.transport import memory
5010.2.7 by Vincent Ladeuil
Fix per_repository/test_write_group.py imports.
37
38
39
class TestWriteGroup(per_repository.TestCaseWithRepository):
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
40
41
    def test_start_write_group_unlocked_needs_write_lock(self):
42
        repo = self.make_repository('.')
43
        self.assertRaises(errors.NotWriteLocked, repo.start_write_group)
44
45
    def test_start_write_group_read_locked_needs_write_lock(self):
46
        repo = self.make_repository('.')
47
        repo.lock_read()
48
        try:
49
            self.assertRaises(errors.NotWriteLocked, repo.start_write_group)
50
        finally:
51
            repo.unlock()
52
53
    def test_start_write_group_write_locked_gets_None(self):
54
        repo = self.make_repository('.')
55
        repo.lock_write()
56
        self.assertEqual(None, repo.start_write_group())
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
57
        repo.commit_write_group()
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
58
        repo.unlock()
59
60
    def test_start_write_group_twice_errors(self):
61
        repo = self.make_repository('.')
62
        repo.lock_write()
63
        repo.start_write_group()
64
        try:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
65
            # don't need a specific exception for now - this is
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
66
            # really to be sure it's used right, not for signalling
67
            # semantic information.
68
            self.assertRaises(errors.BzrError, repo.start_write_group)
69
        finally:
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
70
            repo.commit_write_group()
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
71
            repo.unlock()
72
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
73
    def test_commit_write_group_does_not_error(self):
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
74
        repo = self.make_repository('.')
75
        repo.lock_write()
76
        repo.start_write_group()
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
77
        # commit_write_group can either return None (for repositories without
78
        # isolated transactions) or a hint for pack(). So we only check it
79
        # works in this interface test, because all repositories are exercised.
80
        repo.commit_write_group()
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
81
        repo.unlock()
82
2592.3.242 by Martin Pool
New method TestCase.call_catch_warnings
83
    def test_unlock_in_write_group(self):
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
84
        repo = self.make_repository('.')
85
        repo.lock_write()
86
        repo.start_write_group()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
87
        # don't need a specific exception for now - this is
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
88
        # really to be sure it's used right, not for signalling
89
        # semantic information.
4634.85.10 by Andrew Bennetts
Change test_unlock_in_write_group to expect a log_exception_quietly rather than a raise.
90
        self.assertLogsError(errors.BzrError, repo.unlock)
2592.3.244 by Martin Pool
unlock while in a write group now aborts the write group, unlocks, and errors.
91
        # after this error occurs, the repository is unlocked, and the write
92
        # group is gone.  you've had your chance, and you blew it. ;-)
93
        self.assertFalse(repo.is_locked())
94
        self.assertRaises(errors.BzrError, repo.commit_write_group)
95
        self.assertRaises(errors.BzrError, repo.unlock)
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
96
97
    def test_is_in_write_group(self):
98
        repo = self.make_repository('.')
99
        self.assertFalse(repo.is_in_write_group())
100
        repo.lock_write()
101
        repo.start_write_group()
102
        self.assertTrue(repo.is_in_write_group())
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
103
        repo.commit_write_group()
104
        self.assertFalse(repo.is_in_write_group())
105
        # abort also removes the in_write_group status.
106
        repo.start_write_group()
107
        self.assertTrue(repo.is_in_write_group())
108
        repo.abort_write_group()
109
        self.assertFalse(repo.is_in_write_group())
110
        repo.unlock()
111
112
    def test_abort_write_group_gets_None(self):
113
        repo = self.make_repository('.')
114
        repo.lock_write()
115
        repo.start_write_group()
116
        self.assertEqual(None, repo.abort_write_group())
2617.6.1 by Robert Collins
* New method on Repository - ``start_write_group``, ``end_write_group``
117
        repo.unlock()
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
118
119
    def test_abort_write_group_does_not_raise_when_suppressed(self):
5017.3.43 by Vincent Ladeuil
-s bt.per_repository.test_write_group passing
120
        if self.transport_server is test_server.LocalURLServer:
3825.4.3 by Andrew Bennetts
Conditionally replace LocalURLServer in the test rather than changing the default_transport behaviour of per_repository tests.
121
            self.transport_server = None
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
122
        self.vfs_transport_factory = memory.MemoryServer
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
123
        repo = self.make_repository('repo')
124
        token = repo.lock_write()
125
        self.addCleanup(repo.unlock)
126
        repo.start_write_group()
127
        # Damage the repository on the filesystem
4327.1.9 by Vincent Ladeuil
Fix 4 more lock-related test failures.
128
        t = self.get_transport('')
129
        t.rename('repo', 'foo')
130
        self.addCleanup(t.rename, 'foo', 'repo')
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
131
        # abort_write_group will not raise an error, because either an
132
        # exception was not generated, or the exception was caught and
133
        # suppressed.  See also test_pack_repository's test of the same name.
134
        self.assertEqual(None, repo.abort_write_group(suppress_errors=True))
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
135
4617.1.1 by Robert Collins
Teach the check for get_missing_parent_inventories that this test applies to direct repositories not RemoteRepository.
136
5010.2.7 by Vincent Ladeuil
Fix per_repository/test_write_group.py imports.
137
class TestGetMissingParentInventories(per_repository.TestCaseWithRepository):
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
138
4257.4.6 by Andrew Bennetts
Make get_missing_parent_inventories work for all repo formats (it's a no-op for unstackable formats).
139
    def test_empty_get_missing_parent_inventories(self):
140
        """A new write group has no missing parent inventories."""
141
        repo = self.make_repository('.')
142
        repo.lock_write()
143
        repo.start_write_group()
144
        try:
145
            self.assertEqual(set(), set(repo.get_missing_parent_inventories()))
146
        finally:
147
            repo.commit_write_group()
148
            repo.unlock()
149
4309.1.5 by Andrew Bennetts
Remove lots of cruft.
150
    def branch_trunk_and_make_tree(self, trunk_repo, relpath):
151
        tree = self.make_branch_and_memory_tree('branch')
152
        trunk_repo.lock_read()
153
        self.addCleanup(trunk_repo.unlock)
154
        tree.branch.repository.fetch(trunk_repo, revision_id='rev-1')
155
        tree.set_parent_ids(['rev-1'])
156
        return tree 
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
157
158
    def make_first_commit(self, repo):
4257.4.8 by Andrew Bennetts
Add a (messy) test for get_missing_parent_inventories.
159
        trunk = repo.bzrdir.create_branch()
4309.1.5 by Andrew Bennetts
Remove lots of cruft.
160
        tree = memorytree.MemoryTree.create_on_branch(trunk)
4257.4.8 by Andrew Bennetts
Add a (messy) test for get_missing_parent_inventories.
161
        tree.lock_write()
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
162
        tree.add([''], ['TREE_ROOT'], ['directory'])
163
        tree.add(['dir'], ['dir-id'], ['directory'])
164
        tree.add(['filename'], ['file-id'], ['file'])
165
        tree.put_file_bytes_non_atomic('file-id', 'content\n')
166
        tree.commit('Trunk commit', rev_id='rev-0')
4257.4.8 by Andrew Bennetts
Add a (messy) test for get_missing_parent_inventories.
167
        tree.commit('Trunk commit', rev_id='rev-1')
168
        tree.unlock()
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
169
170
    def make_new_commit_in_new_repo(self, trunk_repo, parents=None):
171
        tree = self.branch_trunk_and_make_tree(trunk_repo, 'branch')
172
        tree.set_parent_ids(parents)
4257.4.8 by Andrew Bennetts
Add a (messy) test for get_missing_parent_inventories.
173
        tree.commit('Branch commit', rev_id='rev-2')
174
        branch_repo = tree.branch.repository
175
        branch_repo.lock_read()
4257.4.9 by Andrew Bennetts
Add more test coverage, but make a long test even longer in the process.
176
        self.addCleanup(branch_repo.unlock)
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
177
        return branch_repo
178
4309.1.5 by Andrew Bennetts
Remove lots of cruft.
179
    def make_stackable_repo(self, relpath='trunk'):
180
        if isinstance(self.repository_format, remote.RemoteRepositoryFormat):
181
            # RemoteRepository by default builds a default format real
182
            # repository, but the default format is unstackble.  So explicitly
183
            # make a stackable real repository and use that.
184
            repo = self.make_repository(relpath, format='1.9')
185
            repo = bzrdir.BzrDir.open(self.get_url(relpath)).open_repository()
186
        else:
187
            repo = self.make_repository(relpath)
188
        if not repo._format.supports_external_lookups:
5010.2.7 by Vincent Ladeuil
Fix per_repository/test_write_group.py imports.
189
            raise tests.TestNotApplicable('format not stackable')
190
        repo.bzrdir._format.set_branch_format(branch.BzrBranchFormat7())
4309.1.5 by Andrew Bennetts
Remove lots of cruft.
191
        return repo
192
193
    def reopen_repo_and_resume_write_group(self, repo):
194
        try:
195
            resume_tokens = repo.suspend_write_group()
196
        except errors.UnsuspendableWriteGroup:
197
            # If we got this far, and this repo does not support resuming write
198
            # groups, then get_missing_parent_inventories works in all
199
            # cases this repo supports.
200
            repo.unlock()
201
            return
202
        repo.unlock()
203
        reopened_repo = repo.bzrdir.open_repository()
204
        reopened_repo.lock_write()
205
        self.addCleanup(reopened_repo.unlock)
206
        reopened_repo.resume_write_group(resume_tokens)
207
        return reopened_repo
208
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
209
    def test_ghost_revision(self):
210
        """A parent inventory may be absent if all the needed texts are present.
211
        i.e., a ghost revision isn't (necessarily) considered to be a missing
212
        parent inventory.
213
        """
214
        # Make a trunk with one commit.
215
        trunk_repo = self.make_stackable_repo()
216
        self.make_first_commit(trunk_repo)
217
        trunk_repo.lock_read()
218
        self.addCleanup(trunk_repo.unlock)
219
        # Branch the trunk, add a new commit.
220
        branch_repo = self.make_new_commit_in_new_repo(
221
            trunk_repo, parents=['rev-1', 'ghost-rev'])
222
        inv = branch_repo.get_inventory('rev-2')
223
        # Make a new repo stacked on trunk, and then copy into it:
224
        #  - all texts in rev-2
225
        #  - the new inventory (rev-2)
226
        #  - the new revision (rev-2)
227
        repo = self.make_stackable_repo('stacked')
4257.4.8 by Andrew Bennetts
Add a (messy) test for get_missing_parent_inventories.
228
        repo.lock_write()
229
        repo.start_write_group()
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
230
        # Add all texts from in rev-2 inventory.  Note that this has to exclude
231
        # the root if the repo format does not support rich roots.
232
        rich_root = branch_repo._format.rich_root_data
233
        all_texts = [
234
            (ie.file_id, ie.revision) for ie in inv.iter_just_entries()
235
             if rich_root or inv.id2path(ie.file_id) != '']
236
        repo.texts.insert_record_stream(
237
            branch_repo.texts.get_record_stream(all_texts, 'unordered', False))
238
        # Add inventory and revision for rev-2.
239
        repo.add_inventory('rev-2', inv, ['rev-1', 'ghost-rev'])
4257.4.8 by Andrew Bennetts
Add a (messy) test for get_missing_parent_inventories.
240
        repo.revisions.insert_record_stream(
241
            branch_repo.revisions.get_record_stream(
242
                [('rev-2',)], 'unordered', False))
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
243
        # Now, no inventories are reported as missing, even though there is a
244
        # ghost.
245
        self.assertEqual(set(), repo.get_missing_parent_inventories())
246
        # Resuming the write group does not affect
247
        # get_missing_parent_inventories.
248
        reopened_repo = self.reopen_repo_and_resume_write_group(repo)
249
        self.assertEqual(set(), reopened_repo.get_missing_parent_inventories())
250
        reopened_repo.abort_write_group()
251
252
    def test_get_missing_parent_inventories(self):
253
        """A stacked repo with a single revision and inventory (no parent
254
        inventory) in it must have all the texts in its inventory (even if not
255
        changed w.r.t. to the absent parent), otherwise it will report missing
256
        texts/parent inventory.
4343.3.29 by John Arbash Meinel
Add 'check_for_missing_texts' flag to get_missing_parent_inv..
257
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
258
        The core of this test is that a file was changed in rev-1, but in a
4343.3.29 by John Arbash Meinel
Add 'check_for_missing_texts' flag to get_missing_parent_inv..
259
        stacked repo that only has rev-2
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
260
        """
261
        # Make a trunk with one commit.
262
        trunk_repo = self.make_stackable_repo()
263
        self.make_first_commit(trunk_repo)
4309.1.4 by Andrew Bennetts
Remove some cruft.
264
        trunk_repo.lock_read()
265
        self.addCleanup(trunk_repo.unlock)
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
266
        # Branch the trunk, add a new commit.
4309.1.4 by Andrew Bennetts
Remove some cruft.
267
        branch_repo = self.make_new_commit_in_new_repo(
268
            trunk_repo, parents=['rev-1'])
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
269
        inv = branch_repo.get_inventory('rev-2')
270
        # Make a new repo stacked on trunk, and copy the new commit's revision
271
        # and inventory records to it.
272
        repo = self.make_stackable_repo('stacked')
273
        repo.lock_write()
274
        repo.start_write_group()
4309.1.4 by Andrew Bennetts
Remove some cruft.
275
        # Insert a single fulltext inv (using add_inventory because it's
276
        # simpler than insert_record_stream)
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
277
        repo.add_inventory('rev-2', inv, ['rev-1'])
278
        repo.revisions.insert_record_stream(
279
            branch_repo.revisions.get_record_stream(
280
                [('rev-2',)], 'unordered', False))
281
        # There should be no missing compression parents
282
        self.assertEqual(set(),
283
                repo.inventories.get_missing_compression_parent_keys())
284
        self.assertEqual(
285
            set([('inventories', 'rev-1')]),
286
            repo.get_missing_parent_inventories())
287
        # Resuming the write group does not affect
288
        # get_missing_parent_inventories.
289
        reopened_repo = self.reopen_repo_and_resume_write_group(repo)
4257.4.9 by Andrew Bennetts
Add more test coverage, but make a long test even longer in the process.
290
        self.assertEqual(
291
            set([('inventories', 'rev-1')]),
4257.4.10 by Andrew Bennetts
Observe new revisions in _KnitGraphIndex.add_record rather than iterating all the uncommitted packs' indices.
292
            reopened_repo.get_missing_parent_inventories())
4309.1.3 by Andrew Bennetts
Start testing more cases, and start factoring those tests a little more clearly.
293
        # Adding the parent inventory satisfies get_missing_parent_inventories.
4257.4.10 by Andrew Bennetts
Observe new revisions in _KnitGraphIndex.add_record rather than iterating all the uncommitted packs' indices.
294
        reopened_repo.inventories.insert_record_stream(
4257.4.9 by Andrew Bennetts
Add more test coverage, but make a long test even longer in the process.
295
            branch_repo.inventories.get_record_stream(
296
                [('rev-1',)], 'unordered', False))
297
        self.assertEqual(
4257.4.10 by Andrew Bennetts
Observe new revisions in _KnitGraphIndex.add_record rather than iterating all the uncommitted packs' indices.
298
            set(), reopened_repo.get_missing_parent_inventories())
299
        reopened_repo.abort_write_group()
4257.4.8 by Andrew Bennetts
Add a (messy) test for get_missing_parent_inventories.
300
4343.3.29 by John Arbash Meinel
Add 'check_for_missing_texts' flag to get_missing_parent_inv..
301
    def test_get_missing_parent_inventories_check(self):
302
        builder = self.make_branch_builder('test')
303
        builder.build_snapshot('A-id', ['ghost-parent-id'], [
304
            ('add', ('', 'root-id', 'directory', None)),
305
            ('add', ('file', 'file-id', 'file', 'content\n'))],
306
            allow_leftmost_as_ghost=True)
307
        b = builder.get_branch()
308
        b.lock_read()
309
        self.addCleanup(b.unlock)
310
        repo = self.make_repository('test-repo')
311
        repo.lock_write()
312
        self.addCleanup(repo.unlock)
313
        repo.start_write_group()
314
        self.addCleanup(repo.abort_write_group)
315
        # Now, add the objects manually
316
        text_keys = [('file-id', 'A-id')]
317
        if repo.supports_rich_root():
318
            text_keys.append(('root-id', 'A-id'))
319
        # Directly add the texts, inventory, and revision object for 'A-id'
320
        repo.texts.insert_record_stream(b.repository.texts.get_record_stream(
321
            text_keys, 'unordered', True))
322
        repo.add_revision('A-id', b.repository.get_revision('A-id'),
323
                          b.repository.get_inventory('A-id'))
4343.3.30 by John Arbash Meinel
Add tests that when resuming a write group, we start checking if
324
        get_missing = repo.get_missing_parent_inventories
4343.3.29 by John Arbash Meinel
Add 'check_for_missing_texts' flag to get_missing_parent_inv..
325
        if repo._format.supports_external_lookups:
326
            self.assertEqual(set([('inventories', 'ghost-parent-id')]),
4343.3.30 by John Arbash Meinel
Add tests that when resuming a write group, we start checking if
327
                get_missing(check_for_missing_texts=False))
328
            self.assertEqual(set(), get_missing(check_for_missing_texts=True))
329
            self.assertEqual(set(), get_missing())
4343.3.29 by John Arbash Meinel
Add 'check_for_missing_texts' flag to get_missing_parent_inv..
330
        else:
4343.3.30 by John Arbash Meinel
Add tests that when resuming a write group, we start checking if
331
            # If we don't support external lookups, we always return empty
332
            self.assertEqual(set(), get_missing(check_for_missing_texts=False))
333
            self.assertEqual(set(), get_missing(check_for_missing_texts=True))
334
            self.assertEqual(set(), get_missing())
335
336
    def test_insert_stream_passes_resume_info(self):
337
        repo = self.make_repository('test-repo')
4617.1.1 by Robert Collins
Teach the check for get_missing_parent_inventories that this test applies to direct repositories not RemoteRepository.
338
        if (not repo._format.supports_external_lookups or
339
            isinstance(repo, remote.RemoteRepository)):
5010.2.7 by Vincent Ladeuil
Fix per_repository/test_write_group.py imports.
340
            raise tests.TestNotApplicable(
4617.1.1 by Robert Collins
Teach the check for get_missing_parent_inventories that this test applies to direct repositories not RemoteRepository.
341
                'only valid for direct connections to resumable repos')
4343.3.30 by John Arbash Meinel
Add tests that when resuming a write group, we start checking if
342
        # log calls to get_missing_parent_inventories, so that we can assert it
343
        # is called with the correct parameters
344
        call_log = []
345
        orig = repo.get_missing_parent_inventories
346
        def get_missing(check_for_missing_texts=True):
347
            call_log.append(check_for_missing_texts)
348
            return orig(check_for_missing_texts=check_for_missing_texts)
349
        repo.get_missing_parent_inventories = get_missing
350
        repo.lock_write()
351
        self.addCleanup(repo.unlock)
352
        sink = repo._get_sink()
353
        sink.insert_stream((), repo._format, [])
354
        self.assertEqual([False], call_log)
355
        del call_log[:]
356
        repo.start_write_group()
357
        # We need to insert something, or suspend_write_group won't actually
358
        # create a token
359
        repo.texts.insert_record_stream([versionedfile.FulltextContentFactory(
360
            ('file-id', 'rev-id'), (), None, 'lines\n')])
361
        tokens = repo.suspend_write_group()
362
        self.assertNotEqual([], tokens)
363
        sink.insert_stream((), repo._format, tokens)
364
        self.assertEqual([True], call_log)
4343.3.29 by John Arbash Meinel
Add 'check_for_missing_texts' flag to get_missing_parent_inv..
365
5557.1.10 by John Arbash Meinel
Add StreamSink.insert_stream_without_locking
366
    def test_insert_stream_without_locking_fails_without_lock(self):
367
        repo = self.make_repository('test-repo')
368
        sink = repo._get_sink()
369
        stream = [('texts', [versionedfile.FulltextContentFactory(
370
            ('file-id', 'rev-id'), (), None, 'lines\n')])]
371
        self.assertRaises(errors.ObjectNotLocked,
372
            sink.insert_stream_without_locking, stream, repo._format)
373
374
    def test_insert_stream_without_locking_fails_without_write_group(self):
375
        repo = self.make_repository('test-repo')
376
        self.addCleanup(repo.lock_write().unlock)
377
        sink = repo._get_sink()
378
        stream = [('texts', [versionedfile.FulltextContentFactory(
379
            ('file-id', 'rev-id'), (), None, 'lines\n')])]
380
        self.assertRaises(errors.BzrError,
381
            sink.insert_stream_without_locking, stream, repo._format)
382
383
    def test_insert_stream_without_locking(self):
384
        repo = self.make_repository('test-repo')
385
        self.addCleanup(repo.lock_write().unlock)
386
        repo.start_write_group()
387
        sink = repo._get_sink()
388
        stream = [('texts', [versionedfile.FulltextContentFactory(
389
            ('file-id', 'rev-id'), (), None, 'lines\n')])]
390
        missing_keys = sink.insert_stream_without_locking(stream, repo._format)
391
        repo.commit_write_group()
392
        self.assertEqual(set(), missing_keys)
393
394
4002.1.3 by Andrew Bennetts
Remove more duplication, put resumable write group tests in separate TestCase.
395
5010.2.7 by Vincent Ladeuil
Fix per_repository/test_write_group.py imports.
396
class TestResumeableWriteGroup(per_repository.TestCaseWithRepository):
4002.1.3 by Andrew Bennetts
Remove more duplication, put resumable write group tests in separate TestCase.
397
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
398
    def make_write_locked_repo(self, relpath='repo'):
399
        repo = self.make_repository(relpath)
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
400
        repo.lock_write()
401
        self.addCleanup(repo.unlock)
402
        return repo
403
404
    def reopen_repo(self, repo):
405
        same_repo = repo.bzrdir.open_repository()
406
        same_repo.lock_write()
407
        self.addCleanup(same_repo.unlock)
408
        return same_repo
409
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
410
    def require_suspendable_write_groups(self, reason):
411
        repo = self.make_repository('__suspend_test')
412
        repo.lock_write()
413
        self.addCleanup(repo.unlock)
414
        repo.start_write_group()
415
        try:
416
            wg_tokens = repo.suspend_write_group()
417
        except errors.UnsuspendableWriteGroup:
418
            repo.abort_write_group()
5010.2.7 by Vincent Ladeuil
Fix per_repository/test_write_group.py imports.
419
            raise tests.TestNotApplicable(reason)
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
420
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
421
    def test_suspend_write_group(self):
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
422
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
423
        repo.start_write_group()
424
        # Add some content so this isn't an empty write group (which may return
425
        # 0 tokens)
426
        repo.texts.add_lines(('file-id', 'revid'), (), ['lines'])
427
        try:
428
            wg_tokens = repo.suspend_write_group()
429
        except errors.UnsuspendableWriteGroup:
430
            # The contract for repos that don't support suspending write groups
431
            # is that suspend_write_group raises UnsuspendableWriteGroup, but
432
            # is otherwise a no-op.  So we can still e.g. abort the write group
433
            # as usual.
434
            self.assertTrue(repo.is_in_write_group())
435
            repo.abort_write_group()
436
        else:
437
            # After suspending a write group we are no longer in a write group
438
            self.assertFalse(repo.is_in_write_group())
439
            # suspend_write_group returns a list of tokens, which are strs.  If
440
            # no other write groups were resumed, there will only be one token.
441
            self.assertEqual(1, len(wg_tokens))
442
            self.assertIsInstance(wg_tokens[0], str)
443
            # See also test_pack_repository's test of the same name.
444
445
    def test_resume_write_group_then_abort(self):
4002.1.3 by Andrew Bennetts
Remove more duplication, put resumable write group tests in separate TestCase.
446
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
447
        repo.start_write_group()
448
        # Add some content so this isn't an empty write group (which may return
449
        # 0 tokens)
450
        text_key = ('file-id', 'revid')
451
        repo.texts.add_lines(text_key, (), ['lines'])
452
        try:
453
            wg_tokens = repo.suspend_write_group()
454
        except errors.UnsuspendableWriteGroup:
455
            # If the repo does not support suspending write groups, it doesn't
456
            # support resuming them either.
457
            repo.abort_write_group()
458
            self.assertRaises(
459
                errors.UnsuspendableWriteGroup, repo.resume_write_group, [])
460
        else:
461
            #self.assertEqual([], list(repo.texts.keys()))
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
462
            same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
463
            same_repo.resume_write_group(wg_tokens)
464
            self.assertEqual([text_key], list(same_repo.texts.keys()))
465
            self.assertTrue(same_repo.is_in_write_group())
466
            same_repo.abort_write_group()
467
            self.assertEqual([], list(repo.texts.keys()))
468
            # See also test_pack_repository's test of the same name.
469
470
    def test_multiple_resume_write_group(self):
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
471
        self.require_suspendable_write_groups(
472
            'Cannot test resume on repo that does not support suspending')
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
473
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
474
        repo.start_write_group()
475
        # Add some content so this isn't an empty write group (which may return
476
        # 0 tokens)
477
        first_key = ('file-id', 'revid')
478
        repo.texts.add_lines(first_key, (), ['lines'])
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
479
        wg_tokens = repo.suspend_write_group()
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
480
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
481
        same_repo.resume_write_group(wg_tokens)
482
        self.assertTrue(same_repo.is_in_write_group())
483
        second_key = ('file-id', 'second-revid')
484
        same_repo.texts.add_lines(second_key, (first_key,), ['more lines'])
485
        try:
486
            new_wg_tokens = same_repo.suspend_write_group()
487
        except:
488
            e = sys.exc_info()
489
            same_repo.abort_write_group(suppress_errors=True)
490
            raise e[0], e[1], e[2]
491
        self.assertEqual(2, len(new_wg_tokens))
492
        self.assertSubset(wg_tokens, new_wg_tokens)
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
493
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
494
        same_repo.resume_write_group(new_wg_tokens)
495
        both_keys = set([first_key, second_key])
496
        self.assertEqual(both_keys, same_repo.texts.keys())
497
        same_repo.abort_write_group()
498
499
    def test_no_op_suspend_resume(self):
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
500
        self.require_suspendable_write_groups(
501
            'Cannot test resume on repo that does not support suspending')
4002.1.3 by Andrew Bennetts
Remove more duplication, put resumable write group tests in separate TestCase.
502
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
503
        repo.start_write_group()
504
        # Add some content so this isn't an empty write group (which may return
505
        # 0 tokens)
506
        text_key = ('file-id', 'revid')
507
        repo.texts.add_lines(text_key, (), ['lines'])
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
508
        wg_tokens = repo.suspend_write_group()
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
509
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
510
        same_repo.resume_write_group(wg_tokens)
511
        new_wg_tokens = same_repo.suspend_write_group()
512
        self.assertEqual(wg_tokens, new_wg_tokens)
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
513
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
514
        same_repo.resume_write_group(wg_tokens)
515
        self.assertEqual([text_key], list(same_repo.texts.keys()))
516
        same_repo.abort_write_group()
517
518
    def test_read_after_suspend_fails(self):
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
519
        self.require_suspendable_write_groups(
520
            'Cannot test suspend on repo that does not support suspending')
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
521
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
522
        repo.start_write_group()
523
        # Add some content so this isn't an empty write group (which may return
524
        # 0 tokens)
525
        text_key = ('file-id', 'revid')
526
        repo.texts.add_lines(text_key, (), ['lines'])
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
527
        wg_tokens = repo.suspend_write_group()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
528
        self.assertEqual([], list(repo.texts.keys()))
529
530
    def test_read_after_second_suspend_fails(self):
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
531
        self.require_suspendable_write_groups(
532
            'Cannot test suspend on repo that does not support suspending')
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
533
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
534
        repo.start_write_group()
535
        # Add some content so this isn't an empty write group (which may return
536
        # 0 tokens)
537
        text_key = ('file-id', 'revid')
538
        repo.texts.add_lines(text_key, (), ['lines'])
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
539
        wg_tokens = repo.suspend_write_group()
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
540
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
541
        same_repo.resume_write_group(wg_tokens)
542
        same_repo.suspend_write_group()
543
        self.assertEqual([], list(same_repo.texts.keys()))
544
545
    def test_read_after_resume_abort_fails(self):
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
546
        self.require_suspendable_write_groups(
547
            'Cannot test suspend on repo that does not support suspending')
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
548
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
549
        repo.start_write_group()
550
        # Add some content so this isn't an empty write group (which may return
551
        # 0 tokens)
552
        text_key = ('file-id', 'revid')
553
        repo.texts.add_lines(text_key, (), ['lines'])
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
554
        wg_tokens = repo.suspend_write_group()
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
555
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
556
        same_repo.resume_write_group(wg_tokens)
557
        same_repo.abort_write_group()
558
        self.assertEqual([], list(same_repo.texts.keys()))
559
560
    def test_cannot_resume_aborted_write_group(self):
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
561
        self.require_suspendable_write_groups(
562
            'Cannot test resume on repo that does not support suspending')
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
563
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
564
        repo.start_write_group()
565
        # Add some content so this isn't an empty write group (which may return
566
        # 0 tokens)
567
        text_key = ('file-id', 'revid')
568
        repo.texts.add_lines(text_key, (), ['lines'])
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
569
        wg_tokens = repo.suspend_write_group()
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
570
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
571
        same_repo.resume_write_group(wg_tokens)
572
        same_repo.abort_write_group()
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
573
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
574
        self.assertRaises(
4002.1.7 by Andrew Bennetts
Rename UnresumableWriteGroups to UnresumableWriteGroup.
575
            errors.UnresumableWriteGroup, same_repo.resume_write_group,
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
576
            wg_tokens)
577
578
    def test_commit_resumed_write_group_no_new_data(self):
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
579
        self.require_suspendable_write_groups(
580
            'Cannot test resume on repo that does not support suspending')
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
581
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
582
        repo.start_write_group()
583
        # Add some content so this isn't an empty write group (which may return
584
        # 0 tokens)
585
        text_key = ('file-id', 'revid')
586
        repo.texts.add_lines(text_key, (), ['lines'])
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
587
        wg_tokens = repo.suspend_write_group()
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
588
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
589
        same_repo.resume_write_group(wg_tokens)
590
        same_repo.commit_write_group()
591
        self.assertEqual([text_key], list(same_repo.texts.keys()))
592
        self.assertEqual(
593
            'lines', same_repo.texts.get_record_stream([text_key],
594
                'unordered', True).next().get_bytes_as('fulltext'))
595
        self.assertRaises(
4002.1.7 by Andrew Bennetts
Rename UnresumableWriteGroups to UnresumableWriteGroup.
596
            errors.UnresumableWriteGroup, same_repo.resume_write_group,
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
597
            wg_tokens)
598
599
    def test_commit_resumed_write_group_plus_new_data(self):
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
600
        self.require_suspendable_write_groups(
601
            'Cannot test resume on repo that does not support suspending')
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
602
        repo = self.make_write_locked_repo()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
603
        repo.start_write_group()
604
        # Add some content so this isn't an empty write group (which may return
605
        # 0 tokens)
606
        first_key = ('file-id', 'revid')
607
        repo.texts.add_lines(first_key, (), ['lines'])
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
608
        wg_tokens = repo.suspend_write_group()
4002.1.2 by Andrew Bennetts
Refactor out some duplication in write_group tests.
609
        same_repo = self.reopen_repo(repo)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
610
        same_repo.resume_write_group(wg_tokens)
611
        second_key = ('file-id', 'second-revid')
612
        same_repo.texts.add_lines(second_key, (first_key,), ['more lines'])
613
        same_repo.commit_write_group()
614
        self.assertEqual(
615
            set([first_key, second_key]), set(same_repo.texts.keys()))
616
        self.assertEqual(
617
            'lines', same_repo.texts.get_record_stream([first_key],
618
                'unordered', True).next().get_bytes_as('fulltext'))
619
        self.assertEqual(
620
            'more lines', same_repo.texts.get_record_stream([second_key],
621
                'unordered', True).next().get_bytes_as('fulltext'))
622
4002.1.10 by Andrew Bennetts
Fix some existing tests, add a new test that fails.
623
    def make_source_with_delta_record(self):
624
        # Make a source repository with a delta record in it.
625
        source_repo = self.make_write_locked_repo('source')
626
        source_repo.start_write_group()
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
627
        key_base = ('file-id', 'base')
628
        key_delta = ('file-id', 'delta')
4343.3.6 by John Arbash Meinel
Take out the _delta_across_repos flag.
629
        def text_stream():
630
            yield versionedfile.FulltextContentFactory(
631
                key_base, (), None, 'lines\n')
632
            yield versionedfile.FulltextContentFactory(
633
                key_delta, (key_base,), None, 'more\nlines\n')
634
        source_repo.texts.insert_record_stream(text_stream())
4002.1.10 by Andrew Bennetts
Fix some existing tests, add a new test that fails.
635
        source_repo.commit_write_group()
636
        return source_repo
637
4002.1.12 by Andrew Bennetts
Add another test, fix the code so it passes, and remove some cruft.
638
    def test_commit_resumed_write_group_with_missing_parents(self):
639
        self.require_suspendable_write_groups(
640
            'Cannot test resume on repo that does not support suspending')
641
        source_repo = self.make_source_with_delta_record()
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
642
        key_base = ('file-id', 'base')
643
        key_delta = ('file-id', 'delta')
4002.1.12 by Andrew Bennetts
Add another test, fix the code so it passes, and remove some cruft.
644
        # Start a write group, insert just a delta.
645
        repo = self.make_write_locked_repo()
646
        repo.start_write_group()
647
        stream = source_repo.texts.get_record_stream(
648
            [key_delta], 'unordered', False)
649
        repo.texts.insert_record_stream(stream)
4343.3.6 by John Arbash Meinel
Take out the _delta_across_repos flag.
650
        # It's either not commitable due to the missing compression parent, or
651
        # the stacked location has already filled in the fulltext.
652
        try:
653
            repo.commit_write_group()
654
        except errors.BzrCheckError:
655
            # It refused to commit because we have a missing parent
656
            pass
657
        else:
658
            same_repo = self.reopen_repo(repo)
659
            same_repo.lock_read()
660
            record = same_repo.texts.get_record_stream([key_delta],
661
                                                       'unordered', True).next()
662
            self.assertEqual('more\nlines\n', record.get_bytes_as('fulltext'))
663
            return
4002.1.12 by Andrew Bennetts
Add another test, fix the code so it passes, and remove some cruft.
664
        # Merely suspending and resuming doesn't make it commitable either.
665
        wg_tokens = repo.suspend_write_group()
666
        same_repo = self.reopen_repo(repo)
667
        same_repo.resume_write_group(wg_tokens)
668
        self.assertRaises(
669
            errors.BzrCheckError, same_repo.commit_write_group)
670
        same_repo.abort_write_group()
671
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
672
    def test_commit_resumed_write_group_adding_missing_parents(self):
673
        self.require_suspendable_write_groups(
674
            'Cannot test resume on repo that does not support suspending')
4002.1.10 by Andrew Bennetts
Fix some existing tests, add a new test that fails.
675
        source_repo = self.make_source_with_delta_record()
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
676
        key_base = ('file-id', 'base')
677
        key_delta = ('file-id', 'delta')
4002.1.10 by Andrew Bennetts
Fix some existing tests, add a new test that fails.
678
        # Start a write group.
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
679
        repo = self.make_write_locked_repo()
680
        repo.start_write_group()
681
        # Add some content so this isn't an empty write group (which may return
682
        # 0 tokens)
683
        text_key = ('file-id', 'revid')
684
        repo.texts.add_lines(text_key, (), ['lines'])
4002.1.10 by Andrew Bennetts
Fix some existing tests, add a new test that fails.
685
        # Suspend it, then resume it.
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
686
        wg_tokens = repo.suspend_write_group()
687
        same_repo = self.reopen_repo(repo)
688
        same_repo.resume_write_group(wg_tokens)
4002.1.10 by Andrew Bennetts
Fix some existing tests, add a new test that fails.
689
        # Add a record with a missing compression parent
690
        stream = source_repo.texts.get_record_stream(
691
            [key_delta], 'unordered', False)
692
        same_repo.texts.insert_record_stream(stream)
693
        # Just like if we'd added that record without a suspend/resume cycle,
694
        # commit_write_group fails.
4343.3.6 by John Arbash Meinel
Take out the _delta_across_repos flag.
695
        try:
696
            same_repo.commit_write_group()
697
        except errors.BzrCheckError:
698
            pass
699
        else:
700
            # If the commit_write_group didn't fail, that is because the
701
            # insert_record_stream already gave it a fulltext.
702
            same_repo = self.reopen_repo(repo)
703
            same_repo.lock_read()
704
            record = same_repo.texts.get_record_stream([key_delta],
705
                                                       'unordered', True).next()
706
            self.assertEqual('more\nlines\n', record.get_bytes_as('fulltext'))
707
            return
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
708
        same_repo.abort_write_group()
709
4002.1.10 by Andrew Bennetts
Fix some existing tests, add a new test that fails.
710
    def test_add_missing_parent_after_resume(self):
711
        self.require_suspendable_write_groups(
712
            'Cannot test resume on repo that does not support suspending')
713
        source_repo = self.make_source_with_delta_record()
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
714
        key_base = ('file-id', 'base')
715
        key_delta = ('file-id', 'delta')
4002.1.10 by Andrew Bennetts
Fix some existing tests, add a new test that fails.
716
        # Start a write group, insert just a delta.
717
        repo = self.make_write_locked_repo()
718
        repo.start_write_group()
719
        stream = source_repo.texts.get_record_stream(
720
            [key_delta], 'unordered', False)
721
        repo.texts.insert_record_stream(stream)
722
        # Suspend it, then resume it.
723
        wg_tokens = repo.suspend_write_group()
724
        same_repo = self.reopen_repo(repo)
4002.1.11 by Andrew Bennetts
Fix latest test.
725
        same_repo.resume_write_group(wg_tokens)
4002.1.10 by Andrew Bennetts
Fix some existing tests, add a new test that fails.
726
        # Fill in the missing compression parent.
727
        stream = source_repo.texts.get_record_stream(
728
            [key_base], 'unordered', False)
729
        same_repo.texts.insert_record_stream(stream)
730
        same_repo.commit_write_group()
731
4002.1.4 by Andrew Bennetts
Remove a little more duplication, add some more tests (some passing, some not).
732
    def test_suspend_empty_initial_write_group(self):
733
        """Suspending a write group with no writes returns an empty token
734
        list.
735
        """
736
        self.require_suspendable_write_groups(
737
            'Cannot test suspend on repo that does not support suspending')
738
        repo = self.make_write_locked_repo()
739
        repo.start_write_group()
740
        wg_tokens = repo.suspend_write_group()
741
        self.assertEqual([], wg_tokens)
742
743
    def test_suspend_empty_initial_write_group(self):
744
        """Resuming an empty token list is equivalent to start_write_group."""
745
        self.require_suspendable_write_groups(
746
            'Cannot test resume on repo that does not support suspending')
747
        repo = self.make_write_locked_repo()
748
        repo.resume_write_group([])
749
        repo.abort_write_group()
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
750
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
751