bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
1 |
# Copyright (C) 2007-2011 Canonical 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
16 |
||
17 |
"""Tests for repository write groups."""
|
|
18 |
||
19 |
import sys |
|
20 |
||
|
6622.1.34
by Jelmer Vernooij
Rename brzlib => breezy. |
21 |
from breezy import ( |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
22 |
branch, |
|
6472.2.3
by Jelmer Vernooij
More control dir. |
23 |
controldir, |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
24 |
errors, |
25 |
memorytree, |
|
26 |
tests, |
|
|
6670.4.1
by Jelmer Vernooij
Update imports. |
27 |
)
|
28 |
from breezy.bzr import ( |
|
|
6670.4.3
by Jelmer Vernooij
Fix more imports. |
29 |
branch as bzrbranch, |
|
6670.4.14
by Jelmer Vernooij
Move remote to breezy.bzr. |
30 |
remote, |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
31 |
versionedfile, |
32 |
)
|
|
|
6622.1.34
by Jelmer Vernooij
Rename brzlib => breezy. |
33 |
from breezy.tests.per_repository_vf import ( |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
34 |
TestCaseWithRepository, |
35 |
all_repository_vf_format_scenarios, |
|
36 |
)
|
|
|
6622.1.34
by Jelmer Vernooij
Rename brzlib => breezy. |
37 |
from breezy.tests.scenarios import load_tests_apply_scenarios |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
38 |
|
39 |
||
40 |
load_tests = load_tests_apply_scenarios |
|
41 |
||
42 |
||
43 |
class TestGetMissingParentInventories(TestCaseWithRepository): |
|
44 |
||
45 |
scenarios = all_repository_vf_format_scenarios() |
|
46 |
||
47 |
def test_empty_get_missing_parent_inventories(self): |
|
48 |
"""A new write group has no missing parent inventories.""" |
|
49 |
repo = self.make_repository('.') |
|
50 |
repo.lock_write() |
|
51 |
repo.start_write_group() |
|
52 |
try: |
|
53 |
self.assertEqual(set(), set(repo.get_missing_parent_inventories())) |
|
54 |
finally: |
|
55 |
repo.commit_write_group() |
|
56 |
repo.unlock() |
|
57 |
||
58 |
def branch_trunk_and_make_tree(self, trunk_repo, relpath): |
|
59 |
tree = self.make_branch_and_memory_tree('branch') |
|
60 |
trunk_repo.lock_read() |
|
61 |
self.addCleanup(trunk_repo.unlock) |
|
62 |
tree.branch.repository.fetch(trunk_repo, revision_id='rev-1') |
|
63 |
tree.set_parent_ids(['rev-1']) |
|
64 |
return tree |
|
65 |
||
66 |
def make_first_commit(self, repo): |
|
|
6653.6.1
by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir. |
67 |
trunk = repo.controldir.create_branch() |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
68 |
tree = memorytree.MemoryTree.create_on_branch(trunk) |
69 |
tree.lock_write() |
|
70 |
tree.add([''], ['TREE_ROOT'], ['directory']) |
|
71 |
tree.add(['dir'], ['dir-id'], ['directory']) |
|
72 |
tree.add(['filename'], ['file-id'], ['file']) |
|
73 |
tree.put_file_bytes_non_atomic('file-id', 'content\n') |
|
74 |
tree.commit('Trunk commit', rev_id='rev-0') |
|
75 |
tree.commit('Trunk commit', rev_id='rev-1') |
|
76 |
tree.unlock() |
|
77 |
||
78 |
def make_new_commit_in_new_repo(self, trunk_repo, parents=None): |
|
79 |
tree = self.branch_trunk_and_make_tree(trunk_repo, 'branch') |
|
80 |
tree.set_parent_ids(parents) |
|
81 |
tree.commit('Branch commit', rev_id='rev-2') |
|
82 |
branch_repo = tree.branch.repository |
|
83 |
branch_repo.lock_read() |
|
84 |
self.addCleanup(branch_repo.unlock) |
|
85 |
return branch_repo |
|
86 |
||
87 |
def make_stackable_repo(self, relpath='trunk'): |
|
88 |
if isinstance(self.repository_format, remote.RemoteRepositoryFormat): |
|
89 |
# RemoteRepository by default builds a default format real
|
|
90 |
# repository, but the default format is unstackble. So explicitly
|
|
91 |
# make a stackable real repository and use that.
|
|
92 |
repo = self.make_repository(relpath, format='1.9') |
|
|
6472.2.3
by Jelmer Vernooij
More control dir. |
93 |
dir = controldir.ControlDir.open(self.get_url(relpath)) |
94 |
repo = dir.open_repository() |
|
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
95 |
else: |
96 |
repo = self.make_repository(relpath) |
|
97 |
if not repo._format.supports_external_lookups: |
|
98 |
raise tests.TestNotApplicable('format not stackable') |
|
|
6653.6.4
by Jelmer Vernooij
Merge trunk. |
99 |
repo.controldir._format.set_branch_format(bzrbranch.BzrBranchFormat7()) |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
100 |
return repo |
101 |
||
102 |
def reopen_repo_and_resume_write_group(self, repo): |
|
103 |
try: |
|
104 |
resume_tokens = repo.suspend_write_group() |
|
105 |
except errors.UnsuspendableWriteGroup: |
|
106 |
# If we got this far, and this repo does not support resuming write
|
|
107 |
# groups, then get_missing_parent_inventories works in all
|
|
108 |
# cases this repo supports.
|
|
109 |
repo.unlock() |
|
110 |
return
|
|
111 |
repo.unlock() |
|
|
6653.6.1
by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir. |
112 |
reopened_repo = repo.controldir.open_repository() |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
113 |
reopened_repo.lock_write() |
114 |
self.addCleanup(reopened_repo.unlock) |
|
115 |
reopened_repo.resume_write_group(resume_tokens) |
|
116 |
return reopened_repo |
|
117 |
||
118 |
def test_ghost_revision(self): |
|
119 |
"""A parent inventory may be absent if all the needed texts are present. |
|
120 |
i.e., a ghost revision isn't (necessarily) considered to be a missing
|
|
121 |
parent inventory.
|
|
122 |
"""
|
|
123 |
# Make a trunk with one commit.
|
|
124 |
trunk_repo = self.make_stackable_repo() |
|
125 |
self.make_first_commit(trunk_repo) |
|
126 |
trunk_repo.lock_read() |
|
127 |
self.addCleanup(trunk_repo.unlock) |
|
128 |
# Branch the trunk, add a new commit.
|
|
129 |
branch_repo = self.make_new_commit_in_new_repo( |
|
130 |
trunk_repo, parents=['rev-1', 'ghost-rev']) |
|
131 |
inv = branch_repo.get_inventory('rev-2') |
|
132 |
# Make a new repo stacked on trunk, and then copy into it:
|
|
133 |
# - all texts in rev-2
|
|
134 |
# - the new inventory (rev-2)
|
|
135 |
# - the new revision (rev-2)
|
|
136 |
repo = self.make_stackable_repo('stacked') |
|
137 |
repo.lock_write() |
|
138 |
repo.start_write_group() |
|
139 |
# Add all texts from in rev-2 inventory. Note that this has to exclude
|
|
140 |
# the root if the repo format does not support rich roots.
|
|
141 |
rich_root = branch_repo._format.rich_root_data |
|
142 |
all_texts = [ |
|
143 |
(ie.file_id, ie.revision) for ie in inv.iter_just_entries() |
|
144 |
if rich_root or inv.id2path(ie.file_id) != ''] |
|
145 |
repo.texts.insert_record_stream( |
|
146 |
branch_repo.texts.get_record_stream(all_texts, 'unordered', False)) |
|
147 |
# Add inventory and revision for rev-2.
|
|
148 |
repo.add_inventory('rev-2', inv, ['rev-1', 'ghost-rev']) |
|
149 |
repo.revisions.insert_record_stream( |
|
150 |
branch_repo.revisions.get_record_stream( |
|
151 |
[('rev-2',)], 'unordered', False)) |
|
152 |
# Now, no inventories are reported as missing, even though there is a
|
|
153 |
# ghost.
|
|
154 |
self.assertEqual(set(), repo.get_missing_parent_inventories()) |
|
155 |
# Resuming the write group does not affect
|
|
156 |
# get_missing_parent_inventories.
|
|
157 |
reopened_repo = self.reopen_repo_and_resume_write_group(repo) |
|
158 |
self.assertEqual(set(), reopened_repo.get_missing_parent_inventories()) |
|
159 |
reopened_repo.abort_write_group() |
|
160 |
||
161 |
def test_get_missing_parent_inventories(self): |
|
162 |
"""A stacked repo with a single revision and inventory (no parent |
|
163 |
inventory) in it must have all the texts in its inventory (even if not
|
|
164 |
changed w.r.t. to the absent parent), otherwise it will report missing
|
|
165 |
texts/parent inventory.
|
|
166 |
||
167 |
The core of this test is that a file was changed in rev-1, but in a
|
|
168 |
stacked repo that only has rev-2
|
|
169 |
"""
|
|
170 |
# Make a trunk with one commit.
|
|
171 |
trunk_repo = self.make_stackable_repo() |
|
172 |
self.make_first_commit(trunk_repo) |
|
173 |
trunk_repo.lock_read() |
|
174 |
self.addCleanup(trunk_repo.unlock) |
|
175 |
# Branch the trunk, add a new commit.
|
|
176 |
branch_repo = self.make_new_commit_in_new_repo( |
|
177 |
trunk_repo, parents=['rev-1']) |
|
178 |
inv = branch_repo.get_inventory('rev-2') |
|
179 |
# Make a new repo stacked on trunk, and copy the new commit's revision
|
|
180 |
# and inventory records to it.
|
|
181 |
repo = self.make_stackable_repo('stacked') |
|
182 |
repo.lock_write() |
|
183 |
repo.start_write_group() |
|
184 |
# Insert a single fulltext inv (using add_inventory because it's
|
|
185 |
# simpler than insert_record_stream)
|
|
186 |
repo.add_inventory('rev-2', inv, ['rev-1']) |
|
187 |
repo.revisions.insert_record_stream( |
|
188 |
branch_repo.revisions.get_record_stream( |
|
189 |
[('rev-2',)], 'unordered', False)) |
|
190 |
# There should be no missing compression parents
|
|
191 |
self.assertEqual(set(), |
|
192 |
repo.inventories.get_missing_compression_parent_keys()) |
|
193 |
self.assertEqual( |
|
|
6619.3.12
by Jelmer Vernooij
Use 2to3 set_literal fixer. |
194 |
{('inventories', 'rev-1')}, |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
195 |
repo.get_missing_parent_inventories()) |
196 |
# Resuming the write group does not affect
|
|
197 |
# get_missing_parent_inventories.
|
|
198 |
reopened_repo = self.reopen_repo_and_resume_write_group(repo) |
|
199 |
self.assertEqual( |
|
|
6619.3.12
by Jelmer Vernooij
Use 2to3 set_literal fixer. |
200 |
{('inventories', 'rev-1')}, |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
201 |
reopened_repo.get_missing_parent_inventories()) |
202 |
# Adding the parent inventory satisfies get_missing_parent_inventories.
|
|
203 |
reopened_repo.inventories.insert_record_stream( |
|
204 |
branch_repo.inventories.get_record_stream( |
|
205 |
[('rev-1',)], 'unordered', False)) |
|
206 |
self.assertEqual( |
|
207 |
set(), reopened_repo.get_missing_parent_inventories()) |
|
208 |
reopened_repo.abort_write_group() |
|
209 |
||
210 |
def test_get_missing_parent_inventories_check(self): |
|
211 |
builder = self.make_branch_builder('test') |
|
212 |
builder.build_snapshot('A-id', ['ghost-parent-id'], [ |
|
213 |
('add', ('', 'root-id', 'directory', None)), |
|
214 |
('add', ('file', 'file-id', 'file', 'content\n'))], |
|
215 |
allow_leftmost_as_ghost=True) |
|
216 |
b = builder.get_branch() |
|
217 |
b.lock_read() |
|
218 |
self.addCleanup(b.unlock) |
|
219 |
repo = self.make_repository('test-repo') |
|
220 |
repo.lock_write() |
|
221 |
self.addCleanup(repo.unlock) |
|
222 |
repo.start_write_group() |
|
223 |
self.addCleanup(repo.abort_write_group) |
|
224 |
# Now, add the objects manually
|
|
225 |
text_keys = [('file-id', 'A-id')] |
|
226 |
if repo.supports_rich_root(): |
|
227 |
text_keys.append(('root-id', 'A-id')) |
|
228 |
# Directly add the texts, inventory, and revision object for 'A-id'
|
|
229 |
repo.texts.insert_record_stream(b.repository.texts.get_record_stream( |
|
230 |
text_keys, 'unordered', True)) |
|
231 |
repo.add_revision('A-id', b.repository.get_revision('A-id'), |
|
232 |
b.repository.get_inventory('A-id')) |
|
233 |
get_missing = repo.get_missing_parent_inventories |
|
234 |
if repo._format.supports_external_lookups: |
|
|
6619.3.12
by Jelmer Vernooij
Use 2to3 set_literal fixer. |
235 |
self.assertEqual({('inventories', 'ghost-parent-id')}, |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
236 |
get_missing(check_for_missing_texts=False)) |
237 |
self.assertEqual(set(), get_missing(check_for_missing_texts=True)) |
|
238 |
self.assertEqual(set(), get_missing()) |
|
239 |
else: |
|
240 |
# If we don't support external lookups, we always return empty
|
|
241 |
self.assertEqual(set(), get_missing(check_for_missing_texts=False)) |
|
242 |
self.assertEqual(set(), get_missing(check_for_missing_texts=True)) |
|
243 |
self.assertEqual(set(), get_missing()) |
|
244 |
||
245 |
def test_insert_stream_passes_resume_info(self): |
|
246 |
repo = self.make_repository('test-repo') |
|
247 |
if (not repo._format.supports_external_lookups or |
|
248 |
isinstance(repo, remote.RemoteRepository)): |
|
249 |
raise tests.TestNotApplicable( |
|
250 |
'only valid for direct connections to resumable repos') |
|
251 |
# log calls to get_missing_parent_inventories, so that we can assert it
|
|
252 |
# is called with the correct parameters
|
|
253 |
call_log = [] |
|
254 |
orig = repo.get_missing_parent_inventories |
|
255 |
def get_missing(check_for_missing_texts=True): |
|
256 |
call_log.append(check_for_missing_texts) |
|
257 |
return orig(check_for_missing_texts=check_for_missing_texts) |
|
258 |
repo.get_missing_parent_inventories = get_missing |
|
259 |
repo.lock_write() |
|
260 |
self.addCleanup(repo.unlock) |
|
261 |
sink = repo._get_sink() |
|
262 |
sink.insert_stream((), repo._format, []) |
|
263 |
self.assertEqual([False], call_log) |
|
264 |
del call_log[:] |
|
265 |
repo.start_write_group() |
|
266 |
# We need to insert something, or suspend_write_group won't actually
|
|
267 |
# create a token
|
|
268 |
repo.texts.insert_record_stream([versionedfile.FulltextContentFactory( |
|
269 |
('file-id', 'rev-id'), (), None, 'lines\n')]) |
|
270 |
tokens = repo.suspend_write_group() |
|
271 |
self.assertNotEqual([], tokens) |
|
272 |
sink.insert_stream((), repo._format, tokens) |
|
273 |
self.assertEqual([True], call_log) |
|
274 |
||
275 |
def test_insert_stream_without_locking_fails_without_lock(self): |
|
276 |
repo = self.make_repository('test-repo') |
|
277 |
sink = repo._get_sink() |
|
278 |
stream = [('texts', [versionedfile.FulltextContentFactory( |
|
279 |
('file-id', 'rev-id'), (), None, 'lines\n')])] |
|
280 |
self.assertRaises(errors.ObjectNotLocked, |
|
281 |
sink.insert_stream_without_locking, stream, repo._format) |
|
282 |
||
283 |
def test_insert_stream_without_locking_fails_without_write_group(self): |
|
284 |
repo = self.make_repository('test-repo') |
|
285 |
self.addCleanup(repo.lock_write().unlock) |
|
286 |
sink = repo._get_sink() |
|
287 |
stream = [('texts', [versionedfile.FulltextContentFactory( |
|
288 |
('file-id', 'rev-id'), (), None, 'lines\n')])] |
|
289 |
self.assertRaises(errors.BzrError, |
|
290 |
sink.insert_stream_without_locking, stream, repo._format) |
|
291 |
||
292 |
def test_insert_stream_without_locking(self): |
|
293 |
repo = self.make_repository('test-repo') |
|
294 |
self.addCleanup(repo.lock_write().unlock) |
|
295 |
repo.start_write_group() |
|
296 |
sink = repo._get_sink() |
|
297 |
stream = [('texts', [versionedfile.FulltextContentFactory( |
|
298 |
('file-id', 'rev-id'), (), None, 'lines\n')])] |
|
299 |
missing_keys = sink.insert_stream_without_locking(stream, repo._format) |
|
300 |
repo.commit_write_group() |
|
301 |
self.assertEqual(set(), missing_keys) |
|
302 |
||
303 |
||
304 |
class TestResumeableWriteGroup(TestCaseWithRepository): |
|
305 |
||
306 |
scenarios = all_repository_vf_format_scenarios() |
|
307 |
||
308 |
def make_write_locked_repo(self, relpath='repo'): |
|
309 |
repo = self.make_repository(relpath) |
|
310 |
repo.lock_write() |
|
311 |
self.addCleanup(repo.unlock) |
|
312 |
return repo |
|
313 |
||
314 |
def reopen_repo(self, repo): |
|
|
6653.6.1
by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir. |
315 |
same_repo = repo.controldir.open_repository() |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
316 |
same_repo.lock_write() |
317 |
self.addCleanup(same_repo.unlock) |
|
318 |
return same_repo |
|
319 |
||
320 |
def require_suspendable_write_groups(self, reason): |
|
321 |
repo = self.make_repository('__suspend_test') |
|
322 |
repo.lock_write() |
|
323 |
self.addCleanup(repo.unlock) |
|
324 |
repo.start_write_group() |
|
325 |
try: |
|
326 |
wg_tokens = repo.suspend_write_group() |
|
327 |
except errors.UnsuspendableWriteGroup: |
|
328 |
repo.abort_write_group() |
|
329 |
raise tests.TestNotApplicable(reason) |
|
330 |
||
331 |
def test_suspend_write_group(self): |
|
332 |
repo = self.make_write_locked_repo() |
|
333 |
repo.start_write_group() |
|
334 |
# Add some content so this isn't an empty write group (which may return
|
|
335 |
# 0 tokens)
|
|
336 |
repo.texts.add_lines(('file-id', 'revid'), (), ['lines']) |
|
337 |
try: |
|
338 |
wg_tokens = repo.suspend_write_group() |
|
339 |
except errors.UnsuspendableWriteGroup: |
|
340 |
# The contract for repos that don't support suspending write groups
|
|
341 |
# is that suspend_write_group raises UnsuspendableWriteGroup, but
|
|
342 |
# is otherwise a no-op. So we can still e.g. abort the write group
|
|
343 |
# as usual.
|
|
344 |
self.assertTrue(repo.is_in_write_group()) |
|
345 |
repo.abort_write_group() |
|
346 |
else: |
|
347 |
# After suspending a write group we are no longer in a write group
|
|
348 |
self.assertFalse(repo.is_in_write_group()) |
|
349 |
# suspend_write_group returns a list of tokens, which are strs. If
|
|
350 |
# no other write groups were resumed, there will only be one token.
|
|
351 |
self.assertEqual(1, len(wg_tokens)) |
|
352 |
self.assertIsInstance(wg_tokens[0], str) |
|
353 |
# See also test_pack_repository's test of the same name.
|
|
354 |
||
355 |
def test_resume_write_group_then_abort(self): |
|
356 |
repo = self.make_write_locked_repo() |
|
357 |
repo.start_write_group() |
|
358 |
# Add some content so this isn't an empty write group (which may return
|
|
359 |
# 0 tokens)
|
|
360 |
text_key = ('file-id', 'revid') |
|
361 |
repo.texts.add_lines(text_key, (), ['lines']) |
|
362 |
try: |
|
363 |
wg_tokens = repo.suspend_write_group() |
|
364 |
except errors.UnsuspendableWriteGroup: |
|
365 |
# If the repo does not support suspending write groups, it doesn't
|
|
366 |
# support resuming them either.
|
|
367 |
repo.abort_write_group() |
|
368 |
self.assertRaises( |
|
369 |
errors.UnsuspendableWriteGroup, repo.resume_write_group, []) |
|
370 |
else: |
|
371 |
#self.assertEqual([], list(repo.texts.keys()))
|
|
372 |
same_repo = self.reopen_repo(repo) |
|
373 |
same_repo.resume_write_group(wg_tokens) |
|
374 |
self.assertEqual([text_key], list(same_repo.texts.keys())) |
|
375 |
self.assertTrue(same_repo.is_in_write_group()) |
|
376 |
same_repo.abort_write_group() |
|
377 |
self.assertEqual([], list(repo.texts.keys())) |
|
378 |
# See also test_pack_repository's test of the same name.
|
|
379 |
||
380 |
def test_multiple_resume_write_group(self): |
|
381 |
self.require_suspendable_write_groups( |
|
382 |
'Cannot test resume on repo that does not support suspending') |
|
383 |
repo = self.make_write_locked_repo() |
|
384 |
repo.start_write_group() |
|
385 |
# Add some content so this isn't an empty write group (which may return
|
|
386 |
# 0 tokens)
|
|
387 |
first_key = ('file-id', 'revid') |
|
388 |
repo.texts.add_lines(first_key, (), ['lines']) |
|
389 |
wg_tokens = repo.suspend_write_group() |
|
390 |
same_repo = self.reopen_repo(repo) |
|
391 |
same_repo.resume_write_group(wg_tokens) |
|
392 |
self.assertTrue(same_repo.is_in_write_group()) |
|
393 |
second_key = ('file-id', 'second-revid') |
|
394 |
same_repo.texts.add_lines(second_key, (first_key,), ['more lines']) |
|
395 |
try: |
|
396 |
new_wg_tokens = same_repo.suspend_write_group() |
|
397 |
except: |
|
398 |
same_repo.abort_write_group(suppress_errors=True) |
|
|
6621.14.1
by Martin
Remove remaining uses of multi-argument raise |
399 |
raise
|
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
400 |
self.assertEqual(2, len(new_wg_tokens)) |
401 |
self.assertSubset(wg_tokens, new_wg_tokens) |
|
402 |
same_repo = self.reopen_repo(repo) |
|
403 |
same_repo.resume_write_group(new_wg_tokens) |
|
|
6619.3.12
by Jelmer Vernooij
Use 2to3 set_literal fixer. |
404 |
both_keys = {first_key, second_key} |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
405 |
self.assertEqual(both_keys, same_repo.texts.keys()) |
406 |
same_repo.abort_write_group() |
|
407 |
||
408 |
def test_no_op_suspend_resume(self): |
|
409 |
self.require_suspendable_write_groups( |
|
410 |
'Cannot test resume on repo that does not support suspending') |
|
411 |
repo = self.make_write_locked_repo() |
|
412 |
repo.start_write_group() |
|
413 |
# Add some content so this isn't an empty write group (which may return
|
|
414 |
# 0 tokens)
|
|
415 |
text_key = ('file-id', 'revid') |
|
416 |
repo.texts.add_lines(text_key, (), ['lines']) |
|
417 |
wg_tokens = repo.suspend_write_group() |
|
418 |
same_repo = self.reopen_repo(repo) |
|
419 |
same_repo.resume_write_group(wg_tokens) |
|
420 |
new_wg_tokens = same_repo.suspend_write_group() |
|
421 |
self.assertEqual(wg_tokens, new_wg_tokens) |
|
422 |
same_repo = self.reopen_repo(repo) |
|
423 |
same_repo.resume_write_group(wg_tokens) |
|
424 |
self.assertEqual([text_key], list(same_repo.texts.keys())) |
|
425 |
same_repo.abort_write_group() |
|
426 |
||
427 |
def test_read_after_suspend_fails(self): |
|
428 |
self.require_suspendable_write_groups( |
|
429 |
'Cannot test suspend on repo that does not support suspending') |
|
430 |
repo = self.make_write_locked_repo() |
|
431 |
repo.start_write_group() |
|
432 |
# Add some content so this isn't an empty write group (which may return
|
|
433 |
# 0 tokens)
|
|
434 |
text_key = ('file-id', 'revid') |
|
435 |
repo.texts.add_lines(text_key, (), ['lines']) |
|
436 |
wg_tokens = repo.suspend_write_group() |
|
437 |
self.assertEqual([], list(repo.texts.keys())) |
|
438 |
||
439 |
def test_read_after_second_suspend_fails(self): |
|
440 |
self.require_suspendable_write_groups( |
|
441 |
'Cannot test suspend on repo that does not support suspending') |
|
442 |
repo = self.make_write_locked_repo() |
|
443 |
repo.start_write_group() |
|
444 |
# Add some content so this isn't an empty write group (which may return
|
|
445 |
# 0 tokens)
|
|
446 |
text_key = ('file-id', 'revid') |
|
447 |
repo.texts.add_lines(text_key, (), ['lines']) |
|
448 |
wg_tokens = repo.suspend_write_group() |
|
449 |
same_repo = self.reopen_repo(repo) |
|
450 |
same_repo.resume_write_group(wg_tokens) |
|
451 |
same_repo.suspend_write_group() |
|
452 |
self.assertEqual([], list(same_repo.texts.keys())) |
|
453 |
||
454 |
def test_read_after_resume_abort_fails(self): |
|
455 |
self.require_suspendable_write_groups( |
|
456 |
'Cannot test suspend on repo that does not support suspending') |
|
457 |
repo = self.make_write_locked_repo() |
|
458 |
repo.start_write_group() |
|
459 |
# Add some content so this isn't an empty write group (which may return
|
|
460 |
# 0 tokens)
|
|
461 |
text_key = ('file-id', 'revid') |
|
462 |
repo.texts.add_lines(text_key, (), ['lines']) |
|
463 |
wg_tokens = repo.suspend_write_group() |
|
464 |
same_repo = self.reopen_repo(repo) |
|
465 |
same_repo.resume_write_group(wg_tokens) |
|
466 |
same_repo.abort_write_group() |
|
467 |
self.assertEqual([], list(same_repo.texts.keys())) |
|
468 |
||
469 |
def test_cannot_resume_aborted_write_group(self): |
|
470 |
self.require_suspendable_write_groups( |
|
471 |
'Cannot test resume on repo that does not support suspending') |
|
472 |
repo = self.make_write_locked_repo() |
|
473 |
repo.start_write_group() |
|
474 |
# Add some content so this isn't an empty write group (which may return
|
|
475 |
# 0 tokens)
|
|
476 |
text_key = ('file-id', 'revid') |
|
477 |
repo.texts.add_lines(text_key, (), ['lines']) |
|
478 |
wg_tokens = repo.suspend_write_group() |
|
479 |
same_repo = self.reopen_repo(repo) |
|
480 |
same_repo.resume_write_group(wg_tokens) |
|
481 |
same_repo.abort_write_group() |
|
482 |
same_repo = self.reopen_repo(repo) |
|
483 |
self.assertRaises( |
|
484 |
errors.UnresumableWriteGroup, same_repo.resume_write_group, |
|
485 |
wg_tokens) |
|
486 |
||
487 |
def test_commit_resumed_write_group_no_new_data(self): |
|
488 |
self.require_suspendable_write_groups( |
|
489 |
'Cannot test resume on repo that does not support suspending') |
|
490 |
repo = self.make_write_locked_repo() |
|
491 |
repo.start_write_group() |
|
492 |
# Add some content so this isn't an empty write group (which may return
|
|
493 |
# 0 tokens)
|
|
494 |
text_key = ('file-id', 'revid') |
|
495 |
repo.texts.add_lines(text_key, (), ['lines']) |
|
496 |
wg_tokens = repo.suspend_write_group() |
|
497 |
same_repo = self.reopen_repo(repo) |
|
498 |
same_repo.resume_write_group(wg_tokens) |
|
499 |
same_repo.commit_write_group() |
|
500 |
self.assertEqual([text_key], list(same_repo.texts.keys())) |
|
501 |
self.assertEqual( |
|
502 |
'lines', same_repo.texts.get_record_stream([text_key], |
|
503 |
'unordered', True).next().get_bytes_as('fulltext')) |
|
504 |
self.assertRaises( |
|
505 |
errors.UnresumableWriteGroup, same_repo.resume_write_group, |
|
506 |
wg_tokens) |
|
507 |
||
508 |
def test_commit_resumed_write_group_plus_new_data(self): |
|
509 |
self.require_suspendable_write_groups( |
|
510 |
'Cannot test resume on repo that does not support suspending') |
|
511 |
repo = self.make_write_locked_repo() |
|
512 |
repo.start_write_group() |
|
513 |
# Add some content so this isn't an empty write group (which may return
|
|
514 |
# 0 tokens)
|
|
515 |
first_key = ('file-id', 'revid') |
|
516 |
repo.texts.add_lines(first_key, (), ['lines']) |
|
517 |
wg_tokens = repo.suspend_write_group() |
|
518 |
same_repo = self.reopen_repo(repo) |
|
519 |
same_repo.resume_write_group(wg_tokens) |
|
520 |
second_key = ('file-id', 'second-revid') |
|
521 |
same_repo.texts.add_lines(second_key, (first_key,), ['more lines']) |
|
522 |
same_repo.commit_write_group() |
|
523 |
self.assertEqual( |
|
|
6619.3.12
by Jelmer Vernooij
Use 2to3 set_literal fixer. |
524 |
{first_key, second_key}, set(same_repo.texts.keys())) |
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
525 |
self.assertEqual( |
526 |
'lines', same_repo.texts.get_record_stream([first_key], |
|
527 |
'unordered', True).next().get_bytes_as('fulltext')) |
|
528 |
self.assertEqual( |
|
529 |
'more lines', same_repo.texts.get_record_stream([second_key], |
|
530 |
'unordered', True).next().get_bytes_as('fulltext')) |
|
531 |
||
532 |
def make_source_with_delta_record(self): |
|
533 |
# Make a source repository with a delta record in it.
|
|
534 |
source_repo = self.make_write_locked_repo('source') |
|
535 |
source_repo.start_write_group() |
|
536 |
key_base = ('file-id', 'base') |
|
537 |
key_delta = ('file-id', 'delta') |
|
538 |
def text_stream(): |
|
539 |
yield versionedfile.FulltextContentFactory( |
|
540 |
key_base, (), None, 'lines\n') |
|
541 |
yield versionedfile.FulltextContentFactory( |
|
542 |
key_delta, (key_base,), None, 'more\nlines\n') |
|
543 |
source_repo.texts.insert_record_stream(text_stream()) |
|
544 |
source_repo.commit_write_group() |
|
545 |
return source_repo |
|
546 |
||
547 |
def test_commit_resumed_write_group_with_missing_parents(self): |
|
548 |
self.require_suspendable_write_groups( |
|
549 |
'Cannot test resume on repo that does not support suspending') |
|
550 |
source_repo = self.make_source_with_delta_record() |
|
551 |
key_base = ('file-id', 'base') |
|
552 |
key_delta = ('file-id', 'delta') |
|
553 |
# Start a write group, insert just a delta.
|
|
554 |
repo = self.make_write_locked_repo() |
|
555 |
repo.start_write_group() |
|
556 |
stream = source_repo.texts.get_record_stream( |
|
557 |
[key_delta], 'unordered', False) |
|
558 |
repo.texts.insert_record_stream(stream) |
|
559 |
# It's either not commitable due to the missing compression parent, or
|
|
560 |
# the stacked location has already filled in the fulltext.
|
|
561 |
try: |
|
562 |
repo.commit_write_group() |
|
563 |
except errors.BzrCheckError: |
|
564 |
# It refused to commit because we have a missing parent
|
|
565 |
pass
|
|
566 |
else: |
|
567 |
same_repo = self.reopen_repo(repo) |
|
568 |
same_repo.lock_read() |
|
|
6634.2.1
by Martin
Apply 2to3 next fixer and make compatible |
569 |
record = next(same_repo.texts.get_record_stream([key_delta], |
570 |
'unordered', True)) |
|
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
571 |
self.assertEqual('more\nlines\n', record.get_bytes_as('fulltext')) |
572 |
return
|
|
573 |
# Merely suspending and resuming doesn't make it commitable either.
|
|
574 |
wg_tokens = repo.suspend_write_group() |
|
575 |
same_repo = self.reopen_repo(repo) |
|
576 |
same_repo.resume_write_group(wg_tokens) |
|
577 |
self.assertRaises( |
|
578 |
errors.BzrCheckError, same_repo.commit_write_group) |
|
579 |
same_repo.abort_write_group() |
|
580 |
||
581 |
def test_commit_resumed_write_group_adding_missing_parents(self): |
|
582 |
self.require_suspendable_write_groups( |
|
583 |
'Cannot test resume on repo that does not support suspending') |
|
584 |
source_repo = self.make_source_with_delta_record() |
|
585 |
key_base = ('file-id', 'base') |
|
586 |
key_delta = ('file-id', 'delta') |
|
587 |
# Start a write group.
|
|
588 |
repo = self.make_write_locked_repo() |
|
589 |
repo.start_write_group() |
|
590 |
# Add some content so this isn't an empty write group (which may return
|
|
591 |
# 0 tokens)
|
|
592 |
text_key = ('file-id', 'revid') |
|
593 |
repo.texts.add_lines(text_key, (), ['lines']) |
|
594 |
# Suspend it, then resume it.
|
|
595 |
wg_tokens = repo.suspend_write_group() |
|
596 |
same_repo = self.reopen_repo(repo) |
|
597 |
same_repo.resume_write_group(wg_tokens) |
|
598 |
# Add a record with a missing compression parent
|
|
599 |
stream = source_repo.texts.get_record_stream( |
|
600 |
[key_delta], 'unordered', False) |
|
601 |
same_repo.texts.insert_record_stream(stream) |
|
602 |
# Just like if we'd added that record without a suspend/resume cycle,
|
|
603 |
# commit_write_group fails.
|
|
604 |
try: |
|
605 |
same_repo.commit_write_group() |
|
606 |
except errors.BzrCheckError: |
|
607 |
pass
|
|
608 |
else: |
|
609 |
# If the commit_write_group didn't fail, that is because the
|
|
610 |
# insert_record_stream already gave it a fulltext.
|
|
611 |
same_repo = self.reopen_repo(repo) |
|
612 |
same_repo.lock_read() |
|
|
6634.2.1
by Martin
Apply 2to3 next fixer and make compatible |
613 |
record = next(same_repo.texts.get_record_stream([key_delta], |
614 |
'unordered', True)) |
|
|
5844.2.2
by Jelmer Vernooij
Move vf-specific write group tests to per_repository_vf. |
615 |
self.assertEqual('more\nlines\n', record.get_bytes_as('fulltext')) |
616 |
return
|
|
617 |
same_repo.abort_write_group() |
|
618 |
||
619 |
def test_add_missing_parent_after_resume(self): |
|
620 |
self.require_suspendable_write_groups( |
|
621 |
'Cannot test resume on repo that does not support suspending') |
|
622 |
source_repo = self.make_source_with_delta_record() |
|
623 |
key_base = ('file-id', 'base') |
|
624 |
key_delta = ('file-id', 'delta') |
|
625 |
# Start a write group, insert just a delta.
|
|
626 |
repo = self.make_write_locked_repo() |
|
627 |
repo.start_write_group() |
|
628 |
stream = source_repo.texts.get_record_stream( |
|
629 |
[key_delta], 'unordered', False) |
|
630 |
repo.texts.insert_record_stream(stream) |
|
631 |
# Suspend it, then resume it.
|
|
632 |
wg_tokens = repo.suspend_write_group() |
|
633 |
same_repo = self.reopen_repo(repo) |
|
634 |
same_repo.resume_write_group(wg_tokens) |
|
635 |
# Fill in the missing compression parent.
|
|
636 |
stream = source_repo.texts.get_record_stream( |
|
637 |
[key_base], 'unordered', False) |
|
638 |
same_repo.texts.insert_record_stream(stream) |
|
639 |
same_repo.commit_write_group() |
|
640 |
||
641 |
def test_suspend_empty_initial_write_group(self): |
|
642 |
"""Suspending a write group with no writes returns an empty token |
|
643 |
list.
|
|
644 |
"""
|
|
645 |
self.require_suspendable_write_groups( |
|
646 |
'Cannot test suspend on repo that does not support suspending') |
|
647 |
repo = self.make_write_locked_repo() |
|
648 |
repo.start_write_group() |
|
649 |
wg_tokens = repo.suspend_write_group() |
|
650 |
self.assertEqual([], wg_tokens) |
|
651 |
||
652 |
def test_resume_empty_initial_write_group(self): |
|
653 |
"""Resuming an empty token list is equivalent to start_write_group.""" |
|
654 |
self.require_suspendable_write_groups( |
|
655 |
'Cannot test resume on repo that does not support suspending') |
|
656 |
repo = self.make_write_locked_repo() |
|
657 |
repo.resume_write_group([]) |
|
658 |
repo.abort_write_group() |