~bzr-pqm/bzr/bzr.dev

5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1
# Copyright (C) 2007-2010 Canonical Ltd
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
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
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
16
17
"""Tests for fetch between repositories of the same type."""
18
19
from bzrlib import (
20
    bzrdir,
21
    errors,
2696.3.10 by Martin Pool
Add missing import
22
    gpg,
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
23
    remote,
2948.3.1 by John Arbash Meinel
Fix bug #158333, make sure that Repository.fetch(self) is properly a no-op for all Repository implementations.
24
    repository,
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
25
    )
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
26
from bzrlib.inventory import ROOT_ID
5751.2.3 by Jelmer Vernooij
More tests
27
from bzrlib.tests import (
28
    TestNotApplicable,
29
    TestSkipped,
30
    )
3689.1.1 by John Arbash Meinel
Rename repository_implementations tests into per_repository tests
31
from bzrlib.tests.per_repository import TestCaseWithRepository
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
32
33
34
class TestFetchSameRepository(TestCaseWithRepository):
35
36
    def test_fetch(self):
37
        # smoke test fetch to ensure that the convenience function works.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
38
        # it is defined as a convenience function with the underlying
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
39
        # functionality provided by an InterRepository
40
        tree_a = self.make_branch_and_tree('a')
41
        self.build_tree(['a/foo'])
42
        tree_a.add('foo', 'file1')
43
        tree_a.commit('rev1', rev_id='rev1')
44
        # fetch with a default limit (grab everything)
2711.2.6 by Martin Pool
Fix up conversion of create_repository to make_repository in test_fetch
45
        repo = self.make_repository('b')
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
46
        if (tree_a.branch.repository.supports_rich_root() and not
47
            repo.supports_rich_root()):
48
            raise TestSkipped('Cannot fetch from model2 to model1')
49
        repo.fetch(tree_a.branch.repository,
50
                   revision_id=None)
51
4145.1.1 by Robert Collins
Explicitly prevent fetching while the target repository is in a write group.
52
    def test_fetch_fails_in_write_group(self):
53
        # fetch() manages a write group itself, fetching within one isn't safe.
54
        repo = self.make_repository('a')
55
        repo.lock_write()
56
        self.addCleanup(repo.unlock)
57
        repo.start_write_group()
58
        self.addCleanup(repo.abort_write_group)
59
        # Don't need a specific class - not expecting flow control based on
60
        # this.
61
        self.assertRaises(errors.BzrError, repo.fetch, repo)
62
4060.1.4 by Robert Collins
Streaming fetch from remote servers.
63
    def test_fetch_to_knit3(self):
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
64
        # create a repository of the sort we are testing.
3242.2.17 by Aaron Bentley
Fix broken tests
65
        tree_a = self.make_branch_and_tree('a')
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
66
        self.build_tree(['a/foo'])
67
        tree_a.add('foo', 'file1')
68
        tree_a.commit('rev1', rev_id='rev1')
69
        # create a knit-3 based format to fetch into
70
        f = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
71
        try:
72
            format = tree_a.branch.repository._format
73
            format.check_conversion_target(f.repository_format)
74
            # if we cannot convert data to knit3, skip the test.
75
        except errors.BadConversionTarget, e:
76
            raise TestSkipped(str(e))
77
        self.get_transport().mkdir('b')
78
        b_bzrdir = f.initialize(self.get_url('b'))
79
        knit3_repo = b_bzrdir.create_repository()
80
        # fetch with a default limit (grab everything)
81
        knit3_repo.fetch(tree_a.branch.repository, revision_id=None)
2592.3.96 by Robert Collins
Merge index improvements (includes bzr.dev).
82
        # Reopen to avoid any in-memory caching - ensure its reading from
83
        # disk.
84
        knit3_repo = b_bzrdir.open_repository()
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
85
        rev1_tree = knit3_repo.revision_tree('rev1')
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
86
        rev1_tree.lock_read()
87
        try:
88
            lines = rev1_tree.get_file_lines(rev1_tree.get_root_id())
89
        finally:
90
            rev1_tree.unlock()
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
91
        self.assertEqual([], lines)
92
        b_branch = b_bzrdir.create_branch()
93
        b_branch.pull(tree_a.branch)
94
        try:
95
            tree_b = b_bzrdir.create_workingtree()
96
        except errors.NotLocalUrl:
4060.1.4 by Robert Collins
Streaming fetch from remote servers.
97
            try:
98
                tree_b = b_branch.create_checkout('b', lightweight=True)
99
            except errors.NotLocalUrl:
100
                raise TestSkipped("cannot make working tree with transport %r"
2696.3.2 by Martin Pool
Move some per-repository tests from big test_repository to test_fetch
101
                              % b_bzrdir.transport)
102
        tree_b.commit('no change', rev_id='rev2')
103
        rev2_tree = knit3_repo.revision_tree('rev2')
104
        self.assertEqual('rev1', rev2_tree.inventory.root.revision)
2696.3.9 by Martin Pool
merge trunk
105
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
106
    def do_test_fetch_to_rich_root_sets_parents_correctly(self, result,
107
        snapshots, root_id=ROOT_ID, allow_lefthand_ghost=False):
108
        """Assert that result is the parents of 'tip' after fetching snapshots.
109
110
        This helper constructs a 1.9 format source, and a test-format target
111
        and fetches the result of building snapshots in the source, then
112
        asserts that the parents of tip are result.
113
114
        :param result: A parents list for the inventories.get_parent_map call.
115
        :param snapshots: An iterable of snapshot parameters for
116
            BranchBuilder.build_snapshot.
117
        '"""
118
        # This overlaps slightly with the tests for commit builder about graph
119
        # consistency.
120
        # Cases:
121
        repo = self.make_repository('target')
4324.3.3 by Robert Collins
Fix silly typo.
122
        remote_format = isinstance(repo, remote.RemoteRepository)
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
123
        if not repo._format.rich_root_data and not remote_format:
124
            return # not relevant
125
        builder = self.make_branch_builder('source', format='1.9')
126
        builder.start_series()
127
        for revision_id, parent_ids, actions in snapshots:
128
            builder.build_snapshot(revision_id, parent_ids, actions,
129
            allow_leftmost_as_ghost=allow_lefthand_ghost)
130
        builder.finish_series()
131
        source = builder.get_branch()
132
        if remote_format and not repo._format.rich_root_data:
133
            # use a manual rich root format to ensure the code path is tested.
134
            repo = self.make_repository('remote-target',
135
                format='1.9-rich-root')
136
        repo.lock_write()
137
        self.addCleanup(repo.unlock)
138
        repo.fetch(source.repository)
5815.5.10 by Jelmer Vernooij
Fix two issues pointed out by John.
139
        graph = repo.get_file_graph()
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
140
        self.assertEqual(result,
5815.5.10 by Jelmer Vernooij
Fix two issues pointed out by John.
141
            graph.get_parent_map([(root_id, 'tip')])[(root_id, 'tip')])
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
142
143
    def test_fetch_to_rich_root_set_parent_no_parents(self):
144
        # No parents rev -> No parents
145
        self.do_test_fetch_to_rich_root_sets_parents_correctly((),
146
            [('tip', None, [('add', ('', ROOT_ID, 'directory', ''))]),
147
            ])
148
149
    def test_fetch_to_rich_root_set_parent_1_parent(self):
4392.2.2 by John Arbash Meinel
Add tests that ensure we can fetch branches with ghosts in their ancestry.
150
        # 1 parent rev -> 1 parent
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
151
        self.do_test_fetch_to_rich_root_sets_parents_correctly(
152
            ((ROOT_ID, 'base'),),
153
            [('base', None, [('add', ('', ROOT_ID, 'directory', ''))]),
154
             ('tip', None, []),
155
            ])
156
157
    def test_fetch_to_rich_root_set_parent_1_ghost_parent(self):
158
        # 1 ghost parent -> No parents
6162.2.1 by Jelmer Vernooij
Skip tests that require ghosts on repositories that don't support ghosts.
159
        if not self.repository_format.supports_ghosts:
160
            raise TestNotApplicable("repository format does not support "
161
                 "ghosts")
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
162
        self.do_test_fetch_to_rich_root_sets_parents_correctly((),
163
            [('tip', ['ghost'], [('add', ('', ROOT_ID, 'directory', ''))]),
164
            ], allow_lefthand_ghost=True)
165
166
    def test_fetch_to_rich_root_set_parent_2_head_parents(self):
167
        # 2 parents both heads -> 2 parents
168
        self.do_test_fetch_to_rich_root_sets_parents_correctly(
169
            ((ROOT_ID, 'left'), (ROOT_ID, 'right')),
170
            [('base', None, [('add', ('', ROOT_ID, 'directory', ''))]),
171
             ('left', None, []),
172
             ('right', ['base'], []),
173
             ('tip', ['left', 'right'], []),
174
            ])
175
176
    def test_fetch_to_rich_root_set_parent_2_parents_1_head(self):
177
        # 2 parents one head -> 1 parent
178
        self.do_test_fetch_to_rich_root_sets_parents_correctly(
179
            ((ROOT_ID, 'right'),),
180
            [('left', None, [('add', ('', ROOT_ID, 'directory', ''))]),
181
             ('right', None, []),
182
             ('tip', ['left', 'right'], []),
183
            ])
184
185
    def test_fetch_to_rich_root_set_parent_1_parent_different_id_gone(self):
186
        # 1 parent different fileid, ours missing -> no parents
187
        self.do_test_fetch_to_rich_root_sets_parents_correctly(
188
            (),
189
            [('base', None, [('add', ('', ROOT_ID, 'directory', ''))]),
190
             ('tip', None, [('unversion', ROOT_ID),
191
                            ('add', ('', 'my-root', 'directory', '')),
192
                            ]),
193
            ], root_id='my-root')
194
195
    def test_fetch_to_rich_root_set_parent_1_parent_different_id_moved(self):
196
        # 1 parent different fileid, ours moved -> 1 parent
197
        # (and that parent honours the changing revid of the other location)
198
        self.do_test_fetch_to_rich_root_sets_parents_correctly(
199
            (('my-root', 'origin'),),
200
            [('origin', None, [('add', ('', ROOT_ID, 'directory', '')),
201
                             ('add', ('child', 'my-root', 'directory', ''))]),
202
             ('base', None, []),
203
             ('tip', None, [('unversion', 'my-root'),
204
                            ('unversion', ROOT_ID),
6008.2.5 by Andrew Bennetts
Rename 'checkpoint' to 'flush', add some unit tests and more comments.
205
                            ('flush', None),
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
206
                            ('add', ('', 'my-root', 'directory', '')),
207
                            ]),
208
            ], root_id='my-root')
209
210
    def test_fetch_to_rich_root_set_parent_2_parent_1_different_id_gone(self):
211
        # 2 parents, 1 different fileid, our second missing -> 1 parent
212
        self.do_test_fetch_to_rich_root_sets_parents_correctly(
213
            (('my-root', 'right'),),
214
            [('base', None, [('add', ('', ROOT_ID, 'directory', ''))]),
215
             ('right', None, [('unversion', ROOT_ID),
216
                              ('add', ('', 'my-root', 'directory', ''))]),
217
             ('tip', ['base', 'right'], [('unversion', ROOT_ID),
218
                            ('add', ('', 'my-root', 'directory', '')),
219
                            ]),
220
            ], root_id='my-root')
221
222
    def test_fetch_to_rich_root_set_parent_2_parent_2_different_id_moved(self):
223
        # 2 parents, 1 different fileid, our second moved -> 2 parent
224
        # (and that parent honours the changing revid of the other location)
225
        self.do_test_fetch_to_rich_root_sets_parents_correctly(
226
            (('my-root', 'right'),),
227
            # 'my-root' at 'child'.
228
            [('origin', None, [('add', ('', ROOT_ID, 'directory', '')),
229
                             ('add', ('child', 'my-root', 'directory', ''))]),
230
             ('base', None, []),
231
            # 'my-root' at root
232
             ('right', None, [('unversion', 'my-root'),
233
                              ('unversion', ROOT_ID),
6008.2.5 by Andrew Bennetts
Rename 'checkpoint' to 'flush', add some unit tests and more comments.
234
                              ('flush', None),
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
235
                              ('add', ('', 'my-root', 'directory', ''))]),
236
             ('tip', ['base', 'right'], [('unversion', 'my-root'),
237
                            ('unversion', ROOT_ID),
6008.2.5 by Andrew Bennetts
Rename 'checkpoint' to 'flush', add some unit tests and more comments.
238
                            ('flush', None),
4324.3.1 by Robert Collins
When adding rich root data follow the standard revision graph rules, so it does not create 'inconstent parents'.
239
                            ('add', ('', 'my-root', 'directory', '')),
240
                            ]),
241
            ], root_id='my-root')
242
2948.3.1 by John Arbash Meinel
Fix bug #158333, make sure that Repository.fetch(self) is properly a no-op for all Repository implementations.
243
    def test_fetch_all_from_self(self):
244
        tree = self.make_branch_and_tree('.')
245
        rev_id = tree.commit('one')
246
        # This needs to be a new copy of the repository, if this changes, the
247
        # test needs to be rewritten
248
        repo = tree.branch.repository.bzrdir.open_repository()
249
        # This fetch should be a no-op see bug #158333
250
        tree.branch.repository.fetch(repo, None)
251
252
    def test_fetch_from_self(self):
253
        tree = self.make_branch_and_tree('.')
254
        rev_id = tree.commit('one')
255
        repo = tree.branch.repository.bzrdir.open_repository()
256
        # This fetch should be a no-op see bug #158333
257
        tree.branch.repository.fetch(repo, rev_id)
258
259
    def test_fetch_missing_from_self(self):
260
        tree = self.make_branch_and_tree('.')
261
        rev_id = tree.commit('one')
262
        # Even though the fetch() is a NO-OP it should assert the revision id
263
        # is present
264
        repo = tree.branch.repository.bzrdir.open_repository()
265
        self.assertRaises(errors.NoSuchRevision, tree.branch.repository.fetch,
266
                          repo, 'no-such-revision')
267
2696.3.9 by Martin Pool
merge trunk
268
    def makeARepoWithSignatures(self):
269
        wt = self.make_branch_and_tree('a-repo-with-sigs')
270
        wt.commit('rev1', allow_pointless=True, rev_id='rev1')
271
        repo = wt.branch.repository
2592.3.96 by Robert Collins
Merge index improvements (includes bzr.dev).
272
        repo.lock_write()
273
        repo.start_write_group()
5751.2.3 by Jelmer Vernooij
More tests
274
        try:
275
            repo.sign_revision('rev1', gpg.LoopbackGPGStrategy(None))
276
        except errors.UnsupportedOperation:
277
            self.assertFalse(repo._format.supports_revision_signatures)
278
            raise TestNotApplicable("repository format does not support signatures")
2592.3.96 by Robert Collins
Merge index improvements (includes bzr.dev).
279
        repo.commit_write_group()
280
        repo.unlock()
2696.3.9 by Martin Pool
merge trunk
281
        return repo
282
283
    def test_fetch_copies_signatures(self):
284
        source_repo = self.makeARepoWithSignatures()
285
        target_repo = self.make_repository('target')
286
        target_repo.fetch(source_repo, revision_id=None)
287
        self.assertEqual(
288
            source_repo.get_signature_text('rev1'),
289
            target_repo.get_signature_text('rev1'))
2535.3.48 by Andrew Bennetts
Merge from bzr.dev.
290
291
    def make_repository_with_one_revision(self):
3242.2.17 by Aaron Bentley
Fix broken tests
292
        wt = self.make_branch_and_tree('source')
2535.3.48 by Andrew Bennetts
Merge from bzr.dev.
293
        wt.commit('rev1', allow_pointless=True, rev_id='rev1')
294
        return wt.branch.repository
295
296
    def test_fetch_revision_already_exists(self):
297
        # Make a repository with one revision.
298
        source_repo = self.make_repository_with_one_revision()
299
        # Fetch that revision into a second repository.
300
        target_repo = self.make_repository('target')
301
        target_repo.fetch(source_repo, revision_id='rev1')
302
        # Now fetch again; there will be nothing to do.  This should work
303
        # without causing any errors.
304
        target_repo.fetch(source_repo, revision_id='rev1')
305
1551.19.36 by Aaron Bentley
Prevent fetch all from causing pack collisions
306
    def test_fetch_all_same_revisions_twice(self):
307
        # Blind-fetching all the same revisions twice should succeed and be a
308
        # no-op the second time.
309
        repo = self.make_repository('repo')
310
        tree = self.make_branch_and_tree('tree')
311
        revision_id = tree.commit('test')
312
        repo.fetch(tree.branch.repository)
313
        repo.fetch(tree.branch.repository)
4360.2.1 by Robert Collins
Don't return ghosts in the keyset for PendingAncestryResult.
314
4392.2.2 by John Arbash Meinel
Add tests that ensure we can fetch branches with ghosts in their ancestry.
315
    def make_simple_branch_with_ghost(self):
4476.3.59 by Andrew Bennetts
Undo changes that aren't needed anymore.
316
        builder = self.make_branch_builder('source')
4392.2.2 by John Arbash Meinel
Add tests that ensure we can fetch branches with ghosts in their ancestry.
317
        builder.start_series()
318
        builder.build_snapshot('A-id', None, [
4476.3.59 by Andrew Bennetts
Undo changes that aren't needed anymore.
319
            ('add', ('', 'root-id', 'directory', None)),
4392.2.2 by John Arbash Meinel
Add tests that ensure we can fetch branches with ghosts in their ancestry.
320
            ('add', ('file', 'file-id', 'file', 'content\n'))])
321
        builder.build_snapshot('B-id', ['A-id', 'ghost-id'], [])
322
        builder.finish_series()
323
        source_b = builder.get_branch()
324
        source_b.lock_read()
325
        self.addCleanup(source_b.unlock)
326
        return source_b
327
328
    def test_fetch_with_ghost(self):
329
        source_b = self.make_simple_branch_with_ghost()
330
        target = self.make_repository('target')
331
        target.lock_write()
332
        self.addCleanup(target.unlock)
333
        target.fetch(source_b.repository, revision_id='B-id')
334
335
    def test_fetch_into_smart_with_ghost(self):
336
        trans = self.make_smart_server('target')
337
        source_b = self.make_simple_branch_with_ghost()
6205.3.1 by Jelmer Vernooij
Add ControlDirFormat.supports_transport.
338
        if not source_b.bzrdir._format.supports_transport(trans):
339
            raise TestNotApplicable("format does not support transport")
4392.2.2 by John Arbash Meinel
Add tests that ensure we can fetch branches with ghosts in their ancestry.
340
        target = self.make_repository('target')
341
        # Re-open the repository over the smart protocol
342
        target = repository.Repository.open(trans.base)
343
        target.lock_write()
344
        self.addCleanup(target.unlock)
345
        try:
346
            target.fetch(source_b.repository, revision_id='B-id')
347
        except errors.TokenLockingNotSupported:
348
            # The code inside fetch() that tries to lock and then fails, also
349
            # causes weird problems with 'lock_not_held' later on...
350
            target.lock_read()
6050.1.2 by Martin
Make tests raising KnownFailure use the knownFailure method instead
351
            self.knownFailure('some repositories fail to fetch'
4392.2.2 by John Arbash Meinel
Add tests that ensure we can fetch branches with ghosts in their ancestry.
352
                ' via the smart server because of locking issues.')
353
354
    def test_fetch_from_smart_with_ghost(self):
355
        trans = self.make_smart_server('source')
356
        source_b = self.make_simple_branch_with_ghost()
6205.3.1 by Jelmer Vernooij
Add ControlDirFormat.supports_transport.
357
        if not source_b.bzrdir._format.supports_transport(trans):
358
            raise TestNotApplicable("format does not support transport")
4392.2.2 by John Arbash Meinel
Add tests that ensure we can fetch branches with ghosts in their ancestry.
359
        target = self.make_repository('target')
360
        target.lock_write()
361
        self.addCleanup(target.unlock)
362
        # Re-open the repository over the smart protocol
363
        source = repository.Repository.open(trans.base)
364
        source.lock_read()
365
        self.addCleanup(source.unlock)
366
        target.fetch(source, revision_id='B-id')
367