77
66
self.addCleanup(tree.unlock)
78
67
tree.get_file_text('file1')
79
for file_id in tree.all_file_ids():
80
if tree.kind(file_id) == "file":
69
if tree.inventory[file_id].kind == "file":
81
70
tree.get_file(file_id).read()
83
# makes a target version repo
72
# makes a target version repo
84
73
repo_b = self.make_to_repository('b')
85
74
check_push_rev1(repo_b)
87
def test_fetch_inconsistent_last_changed_entries(self):
88
"""If an inventory has odd data we should still get what it references.
90
This test tests that we do fetch a file text created in a revision not
91
being fetched, but referenced from the revision we are fetching when the
92
adjacent revisions to the one being fetched do not reference that text.
94
tree = self.make_branch_and_tree('source')
95
revid = tree.commit('old')
96
to_repo = self.make_to_repository('to_repo')
97
to_repo.fetch(tree.branch.repository, revid)
98
# Make a broken revision and fetch it.
99
source = tree.branch.repository
101
self.addCleanup(source.unlock)
102
source.start_write_group()
104
# We need two revisions: OLD and NEW. NEW will claim to need a file
105
# 'FOO' changed in 'OLD'. OLD will not have that file at all.
106
source.texts.insert_record_stream([
107
versionedfile.FulltextContentFactory(('foo', revid), (), None,
109
basis = source.revision_tree(revid)
110
parent_id = basis.path2id('')
111
entry = inventory.make_entry('file', 'foo-path', parent_id, 'foo')
112
entry.revision = revid
113
entry.text_size = len('contents')
114
entry.text_sha1 = osutils.sha_string('contents')
115
inv_sha1, _ = source.add_inventory_by_delta(revid, [
116
(None, 'foo-path', 'foo', entry)], 'new', [revid])
117
rev = Revision(timestamp=0,
119
committer="Foo Bar <foo@example.com>",
121
inventory_sha1=inv_sha1,
124
source.add_revision(rev.revision_id, rev)
126
source.abort_write_group()
129
source.commit_write_group()
130
to_repo.fetch(source, 'new')
132
self.addCleanup(to_repo.unlock)
133
self.assertEqual('contents',
134
to_repo.texts.get_record_stream([('foo', revid)],
135
'unordered', True).next().get_bytes_as('fulltext'))
137
def test_fetch_from_stacked_smart(self):
138
self.setup_smart_server_with_call_log()
139
self.test_fetch_from_stacked()
141
def test_fetch_from_stacked_smart_old(self):
142
self.setup_smart_server_with_call_log()
143
self.disable_verb('Repository.get_stream_1.19')
144
self.test_fetch_from_stacked()
146
def test_fetch_from_stacked(self):
147
"""Fetch from a stacked branch succeeds."""
148
if not self.repository_format.supports_external_lookups:
149
raise TestNotApplicable("Need stacking support in the source.")
150
builder = self.make_branch_builder('full-branch')
151
builder.start_series()
152
builder.build_snapshot('first', None, [
153
('add', ('', 'root-id', 'directory', '')),
154
('add', ('file', 'file-id', 'file', 'content\n'))])
155
builder.build_snapshot('second', ['first'], [
156
('modify', ('file-id', 'second content\n'))])
157
builder.build_snapshot('third', ['second'], [
158
('modify', ('file-id', 'third content\n'))])
159
builder.finish_series()
160
branch = builder.get_branch()
161
repo = self.make_repository('stacking-base')
162
trunk = repo.bzrdir.create_branch()
163
trunk.repository.fetch(branch.repository, 'second')
164
repo = self.make_repository('stacked')
165
stacked_branch = repo.bzrdir.create_branch()
166
stacked_branch.set_stacked_on_url(trunk.base)
167
stacked_branch.repository.fetch(branch.repository, 'third')
168
target = self.make_to_repository('target')
169
target.fetch(stacked_branch.repository, 'third')
171
self.addCleanup(target.unlock)
172
all_revs = set(['first', 'second', 'third'])
173
self.assertEqual(all_revs, set(target.get_parent_map(all_revs)))
175
def test_fetch_parent_inventories_at_stacking_boundary_smart(self):
176
self.setup_smart_server_with_call_log()
177
self.test_fetch_parent_inventories_at_stacking_boundary()
179
def test_fetch_parent_inventories_at_stacking_boundary_smart_old(self):
180
self.setup_smart_server_with_call_log()
181
self.disable_verb('Repository.insert_stream_1.19')
183
self.test_fetch_parent_inventories_at_stacking_boundary()
184
except errors.ConnectionReset:
185
self.knownFailure("Random spurious failure, see bug 874153")
187
def test_fetch_parent_inventories_at_stacking_boundary(self):
188
"""Fetch to a stacked branch copies inventories for parents of
189
revisions at the stacking boundary.
191
This is necessary so that the server is able to determine the file-ids
192
altered by all revisions it contains, which means that it needs both
193
the inventory for any revision it has, and the inventories of all that
196
However, we should also skip any revisions which are ghosts in the
199
if not self.repository_format_to.supports_external_lookups:
200
raise TestNotApplicable("Need stacking support in the target.")
201
builder = self.make_branch_builder('branch')
202
builder.start_series()
203
builder.build_snapshot('base', None, [
204
('add', ('', 'root-id', 'directory', '')),
205
('add', ('file', 'file-id', 'file', 'content\n'))])
206
builder.build_snapshot('left', ['base'], [
207
('modify', ('file-id', 'left content\n'))])
208
builder.build_snapshot('right', ['base'], [
209
('modify', ('file-id', 'right content\n'))])
210
builder.build_snapshot('merge', ['left', 'right'], [
211
('modify', ('file-id', 'left and right content\n'))])
212
builder.finish_series()
213
branch = builder.get_branch()
214
repo = self.make_to_repository('trunk')
215
trunk = repo.bzrdir.create_branch()
216
trunk.repository.fetch(branch.repository, 'left')
217
trunk.repository.fetch(branch.repository, 'right')
218
repo = self.make_to_repository('stacked')
219
stacked_branch = repo.bzrdir.create_branch()
220
stacked_branch.set_stacked_on_url(trunk.base)
221
stacked_branch.repository.fetch(branch.repository, 'merge')
222
unstacked_repo = stacked_branch.bzrdir.open_repository()
223
unstacked_repo.lock_read()
224
self.addCleanup(unstacked_repo.unlock)
225
self.assertFalse(unstacked_repo.has_revision('left'))
226
self.assertFalse(unstacked_repo.has_revision('right'))
228
set([('left',), ('right',), ('merge',)]),
229
unstacked_repo.inventories.keys())
230
# And the basis inventories have been copied correctly
232
self.addCleanup(trunk.unlock)
233
left_tree, right_tree = trunk.repository.revision_trees(
235
stacked_branch.lock_read()
236
self.addCleanup(stacked_branch.unlock)
238
stacked_right_tree) = stacked_branch.repository.revision_trees(
241
left_tree.root_inventory, stacked_left_tree.root_inventory)
243
right_tree.root_inventory, stacked_right_tree.root_inventory)
245
# Finally, it's not enough to see that the basis inventories are
246
# present. The texts introduced in merge (and only those) should be
247
# present, and also generating a stream should succeed without blowing
249
self.assertTrue(unstacked_repo.has_revision('merge'))
250
expected_texts = set([('file-id', 'merge')])
251
if stacked_branch.repository.texts.get_parent_map([('root-id',
253
# If a (root-id,merge) text exists, it should be in the stacked
255
expected_texts.add(('root-id', 'merge'))
256
self.assertEqual(expected_texts, unstacked_repo.texts.keys())
257
self.assertCanStreamRevision(unstacked_repo, 'merge')
259
def assertCanStreamRevision(self, repo, revision_id):
260
exclude_keys = set(repo.all_revision_ids()) - set([revision_id])
261
search = SearchResult([revision_id], exclude_keys, 1, [revision_id])
262
source = repo._get_source(repo._format)
263
for substream_kind, substream in source.get_stream(search):
264
# Consume the substream
267
def test_fetch_across_stacking_boundary_ignores_ghost(self):
268
if not self.repository_format_to.supports_external_lookups:
269
raise TestNotApplicable("Need stacking support in the target.")
270
to_repo = self.make_to_repository('to')
271
builder = self.make_branch_builder('branch')
272
builder.start_series()
273
builder.build_snapshot('base', None, [
274
('add', ('', 'root-id', 'directory', '')),
275
('add', ('file', 'file-id', 'file', 'content\n'))])
276
builder.build_snapshot('second', ['base'], [
277
('modify', ('file-id', 'second content\n'))])
278
builder.build_snapshot('third', ['second', 'ghost'], [
279
('modify', ('file-id', 'third content\n'))])
280
builder.finish_series()
281
branch = builder.get_branch()
282
repo = self.make_to_repository('trunk')
283
trunk = repo.bzrdir.create_branch()
284
trunk.repository.fetch(branch.repository, 'second')
285
repo = self.make_to_repository('stacked')
286
stacked_branch = repo.bzrdir.create_branch()
287
stacked_branch.set_stacked_on_url(trunk.base)
288
stacked_branch.repository.fetch(branch.repository, 'third')
289
unstacked_repo = stacked_branch.bzrdir.open_repository()
290
unstacked_repo.lock_read()
291
self.addCleanup(unstacked_repo.unlock)
292
self.assertFalse(unstacked_repo.has_revision('second'))
293
self.assertFalse(unstacked_repo.has_revision('ghost'))
295
set([('second',), ('third',)]),
296
unstacked_repo.inventories.keys())
297
# And the basis inventories have been copied correctly
299
self.addCleanup(trunk.unlock)
300
second_tree = trunk.repository.revision_tree('second')
301
stacked_branch.lock_read()
302
self.addCleanup(stacked_branch.unlock)
303
stacked_second_tree = stacked_branch.repository.revision_tree('second')
304
self.assertEqual(second_tree, stacked_second_tree)
305
# Finally, it's not enough to see that the basis inventories are
306
# present. The texts introduced in merge (and only those) should be
307
# present, and also generating a stream should succeed without blowing
309
self.assertTrue(unstacked_repo.has_revision('third'))
310
expected_texts = set([('file-id', 'third')])
311
if stacked_branch.repository.texts.get_parent_map([('root-id',
313
# If a (root-id,third) text exists, it should be in the stacked
315
expected_texts.add(('root-id', 'third'))
316
self.assertEqual(expected_texts, unstacked_repo.texts.keys())
317
self.assertCanStreamRevision(unstacked_repo, 'third')
319
def test_fetch_from_stacked_to_stacked_copies_parent_inventories(self):
320
"""Fetch from a stacked branch copies inventories for parents of
321
revisions at the stacking boundary.
323
Specifically, fetch will copy the parent inventories from the
324
source for which the corresponding revisions are not present. This
325
will happen even when the source repository has no fallbacks configured
326
(as is the case during upgrade).
328
if not self.repository_format.supports_external_lookups:
329
raise TestNotApplicable("Need stacking support in the source.")
330
if not self.repository_format_to.supports_external_lookups:
331
raise TestNotApplicable("Need stacking support in the target.")
332
builder = self.make_branch_builder('branch')
333
builder.start_series()
334
builder.build_snapshot('base', None, [
335
('add', ('', 'root-id', 'directory', '')),
336
('add', ('file', 'file-id', 'file', 'content\n'))])
337
builder.build_snapshot('left', ['base'], [
338
('modify', ('file-id', 'left content\n'))])
339
builder.build_snapshot('right', ['base'], [
340
('modify', ('file-id', 'right content\n'))])
341
builder.build_snapshot('merge', ['left', 'right'], [
342
('modify', ('file-id', 'left and right content\n'))])
343
builder.finish_series()
344
branch = builder.get_branch()
345
repo = self.make_repository('old-trunk')
346
# Make a pair of equivalent trunk repos in the from and to formats.
347
old_trunk = repo.bzrdir.create_branch()
348
old_trunk.repository.fetch(branch.repository, 'left')
349
old_trunk.repository.fetch(branch.repository, 'right')
350
repo = self.make_to_repository('new-trunk')
351
new_trunk = repo.bzrdir.create_branch()
352
new_trunk.repository.fetch(branch.repository, 'left')
353
new_trunk.repository.fetch(branch.repository, 'right')
354
# Make the source; a repo stacked on old_trunk contained just the data
356
repo = self.make_repository('old-stacked')
357
old_stacked_branch = repo.bzrdir.create_branch()
358
old_stacked_branch.set_stacked_on_url(old_trunk.base)
359
old_stacked_branch.repository.fetch(branch.repository, 'merge')
360
# Make the target, a repo stacked on new_trunk.
361
repo = self.make_to_repository('new-stacked')
362
new_stacked_branch = repo.bzrdir.create_branch()
363
new_stacked_branch.set_stacked_on_url(new_trunk.base)
364
old_unstacked_repo = old_stacked_branch.bzrdir.open_repository()
365
new_unstacked_repo = new_stacked_branch.bzrdir.open_repository()
366
# Reopen the source and target repos without any fallbacks, and fetch
368
new_unstacked_repo.fetch(old_unstacked_repo, 'merge')
369
# Now check the results. new_unstacked_repo should contain all the
370
# data necessary to stream 'merge' (i.e. the parent inventories).
371
new_unstacked_repo.lock_read()
372
self.addCleanup(new_unstacked_repo.unlock)
373
self.assertFalse(new_unstacked_repo.has_revision('left'))
374
self.assertFalse(new_unstacked_repo.has_revision('right'))
376
set([('left',), ('right',), ('merge',)]),
377
new_unstacked_repo.inventories.keys())
378
# And the basis inventories have been copied correctly
379
new_trunk.lock_read()
380
self.addCleanup(new_trunk.unlock)
381
left_tree, right_tree = new_trunk.repository.revision_trees(
383
new_stacked_branch.lock_read()
384
self.addCleanup(new_stacked_branch.unlock)
386
stacked_right_tree) = new_stacked_branch.repository.revision_trees(
388
self.assertEqual(left_tree, stacked_left_tree)
389
self.assertEqual(right_tree, stacked_right_tree)
390
# Finally, it's not enough to see that the basis inventories are
391
# present. The texts introduced in merge (and only those) should be
392
# present, and also generating a stream should succeed without blowing
394
self.assertTrue(new_unstacked_repo.has_revision('merge'))
395
expected_texts = set([('file-id', 'merge')])
396
if new_stacked_branch.repository.texts.get_parent_map([('root-id',
398
# If a (root-id,merge) text exists, it should be in the stacked
400
expected_texts.add(('root-id', 'merge'))
401
self.assertEqual(expected_texts, new_unstacked_repo.texts.keys())
402
self.assertCanStreamRevision(new_unstacked_repo, 'merge')
404
76
def test_fetch_missing_basis_text(self):
405
77
"""If fetching a delta, we should die if a basis is not present."""
406
78
tree = self.make_branch_and_tree('tree')