~bzr-pqm/bzr/bzr.dev

3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
1
# Copyright (C) 2005, 2006, 2008 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
16
17
18
import sys
19
20
import bzrlib
21
from bzrlib import (
22
    errors,
3735.2.135 by Robert Collins
Permit fetching bzr.dev [deal with inconsistent inventories.]
23
    inventory,
24
    osutils,
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
25
    repository,
3735.2.135 by Robert Collins
Permit fetching bzr.dev [deal with inconsistent inventories.]
26
    versionedfile,
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
27
    )
28
from bzrlib.errors import (
29
    NoSuchRevision,
30
    )
31
from bzrlib.revision import (
32
    NULL_REVISION,
33
    Revision,
34
    )
35
from bzrlib.tests import (
36
    TestNotApplicable,
37
    )
4523.1.3 by Martin Pool
Rename to per_interrepository
38
from bzrlib.tests.per_interrepository import (
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
39
    TestCaseWithInterRepository,
40
    )
4523.1.3 by Martin Pool
Rename to per_interrepository
41
from bzrlib.tests.per_interrepository.test_interrepository import (
3616.2.3 by Mark Hammond
Fix test failures due to missing check_repo_format_for_funky_id_on_win32
42
    check_repo_format_for_funky_id_on_win32
43
    )
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
44
45
46
class TestInterRepository(TestCaseWithInterRepository):
47
48
    def test_fetch(self):
49
        tree_a = self.make_branch_and_tree('a')
50
        self.build_tree(['a/foo'])
51
        tree_a.add('foo', 'file1')
52
        tree_a.commit('rev1', rev_id='rev1')
53
        def check_push_rev1(repo):
54
            # ensure the revision is missing.
55
            self.assertRaises(NoSuchRevision, repo.get_revision, 'rev1')
4110.2.5 by Martin Pool
Deprecate passing pbs in to fetch()
56
            # fetch with a limit of NULL_REVISION
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
57
            repo.fetch(tree_a.branch.repository,
4110.2.5 by Martin Pool
Deprecate passing pbs in to fetch()
58
                       revision_id=NULL_REVISION)
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
59
            # nothing should have been pushed
60
            self.assertFalse(repo.has_revision('rev1'))
61
            # fetch with a default limit (grab everything)
62
            repo.fetch(tree_a.branch.repository)
63
            # check that b now has all the data from a's first commit.
64
            rev = repo.get_revision('rev1')
65
            tree = repo.revision_tree('rev1')
66
            tree.lock_read()
67
            self.addCleanup(tree.unlock)
68
            tree.get_file_text('file1')
69
            for file_id in tree:
70
                if tree.inventory[file_id].kind == "file":
71
                    tree.get_file(file_id).read()
72
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
73
        # makes a target version repo
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
74
        repo_b = self.make_to_repository('b')
75
        check_push_rev1(repo_b)
76
3735.2.135 by Robert Collins
Permit fetching bzr.dev [deal with inconsistent inventories.]
77
    def test_fetch_inconsistent_last_changed_entries(self):
78
        """If an inventory has odd data we should still get what it references.
3735.31.2 by John Arbash Meinel
Cleanup trailing whitespace, get test_source to pass by removing asserts.
79
3735.2.135 by Robert Collins
Permit fetching bzr.dev [deal with inconsistent inventories.]
80
        This test tests that we do fetch a file text created in a revision not
81
        being fetched, but referenced from the revision we are fetching when the
82
        adjacent revisions to the one being fetched do not reference that text.
83
        """
84
        tree = self.make_branch_and_tree('source')
85
        revid = tree.commit('old')
86
        to_repo = self.make_to_repository('to_repo')
87
        to_repo.fetch(tree.branch.repository, revid)
88
        # Make a broken revision and fetch it.
89
        source = tree.branch.repository
90
        source.lock_write()
91
        self.addCleanup(source.unlock)
92
        source.start_write_group()
93
        try:
94
            # We need two revisions: OLD and NEW. NEW will claim to need a file
95
            # 'FOO' changed in 'OLD'. OLD will not have that file at all.
96
            source.texts.insert_record_stream([
97
                versionedfile.FulltextContentFactory(('foo', revid), (), None,
98
                'contents')])
99
            basis = source.revision_tree(revid)
100
            parent_id = basis.path2id('')
101
            entry = inventory.make_entry('file', 'foo-path', parent_id, 'foo')
102
            entry.revision = revid
103
            entry.text_size = len('contents')
104
            entry.text_sha1 = osutils.sha_string('contents')
105
            inv_sha1, _ = source.add_inventory_by_delta(revid, [
106
                (None, 'foo-path', 'foo', entry)], 'new', [revid])
107
            rev = Revision(timestamp=0,
108
                           timezone=None,
109
                           committer="Foo Bar <foo@example.com>",
110
                           message="Message",
111
                           inventory_sha1=inv_sha1,
112
                           revision_id='new',
113
                           parent_ids=[revid])
114
            source.add_revision(rev.revision_id, rev)
115
        except:
116
            source.abort_write_group()
117
            raise
118
        else:
119
            source.commit_write_group()
120
        to_repo.fetch(source, 'new')
121
        to_repo.lock_read()
122
        self.addCleanup(to_repo.unlock)
123
        self.assertEqual('contents',
124
            to_repo.texts.get_record_stream([('foo', revid)],
125
            'unordered', True).next().get_bytes_as('fulltext'))
126
4257.3.1 by Andrew Bennetts
Add failing test.
127
    def test_fetch_parent_inventories_at_stacking_boundary(self):
4257.3.9 by Andrew Bennetts
Add fix to InterDifferingSerializer too, although it's pretty ugly.
128
        """Fetch to a stacked branch copies inventories for parents of
129
        revisions at the stacking boundary.
130
131
        This is necessary so that the server is able to determine the file-ids
132
        altered by all revisions it contains, which means that it needs both
133
        the inventory for any revision it has, and the inventories of all that
134
        revision's parents.
135
        """
4257.3.1 by Andrew Bennetts
Add failing test.
136
        to_repo = self.make_to_repository('to')
137
        if not to_repo._format.supports_external_lookups:
138
            raise TestNotApplicable("Need stacking support in the target.")
139
        builder = self.make_branch_builder('branch')
140
        builder.start_series()
141
        builder.build_snapshot('base', None, [
142
            ('add', ('', 'root-id', 'directory', ''))])
143
        builder.build_snapshot('left', ['base'], [])
144
        builder.build_snapshot('right', ['base'], [])
145
        builder.build_snapshot('merge', ['left', 'right'], [])
146
        builder.finish_series()
147
        branch = builder.get_branch()
148
        repo = self.make_to_repository('trunk')
149
        trunk = repo.bzrdir.create_branch()
150
        trunk.repository.fetch(branch.repository, 'left')
151
        trunk.repository.fetch(branch.repository, 'right')
152
        repo = self.make_to_repository('stacked')
153
        stacked_branch = repo.bzrdir.create_branch()
154
        stacked_branch.set_stacked_on_url(trunk.base)
155
        stacked_branch.repository.fetch(branch.repository, 'merge')
156
        unstacked_repo = stacked_branch.bzrdir.open_repository()
157
        unstacked_repo.lock_read()
158
        self.addCleanup(unstacked_repo.unlock)
159
        self.assertFalse(unstacked_repo.has_revision('left'))
160
        self.assertFalse(unstacked_repo.has_revision('right'))
161
        self.assertEqual(
4257.3.2 by Andrew Bennetts
Check during fetch if we are going to be missing data necessary to calculate altered fileids for stacked revisions.
162
            set([('left',), ('right',), ('merge',)]),
4257.3.1 by Andrew Bennetts
Add failing test.
163
            unstacked_repo.inventories.keys())
164
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
165
    def test_fetch_missing_basis_text(self):
166
        """If fetching a delta, we should die if a basis is not present."""
167
        tree = self.make_branch_and_tree('tree')
168
        self.build_tree(['tree/a'])
169
        tree.add(['a'], ['a-id'])
170
        tree.commit('one', rev_id='rev-one')
171
        self.build_tree_contents([('tree/a', 'new contents\n')])
172
        tree.commit('two', rev_id='rev-two')
173
174
        to_repo = self.make_to_repository('to_repo')
175
        # We build a broken revision so that we can test the fetch code dies
176
        # properly. So copy the inventory and revision, but not the text.
177
        to_repo.lock_write()
178
        try:
179
            to_repo.start_write_group()
180
            inv = tree.branch.repository.get_inventory('rev-one')
181
            to_repo.add_inventory('rev-one', inv, [])
182
            rev = tree.branch.repository.get_revision('rev-one')
183
            to_repo.add_revision('rev-one', rev, inv=inv)
184
            to_repo.commit_write_group()
185
        finally:
186
            to_repo.unlock()
187
3350.3.21 by Robert Collins
Merge bzr.dev.
188
        # Implementations can either ensure that the target of the delta is
189
        # reconstructable, or raise an exception (which stream based copies
190
        # generally do).
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
191
        try:
192
            to_repo.fetch(tree.branch.repository, 'rev-two')
3830.3.12 by Martin Pool
Review cleanups: unify has_key impls, add missing_keys(), clean up exception blocks
193
        except (errors.BzrCheckError, errors.RevisionNotPresent), e:
194
            # If an exception is raised, the revision should not be in the
195
            # target.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
196
            #
3830.3.9 by Martin Pool
Simplify kvf insert_record_stream; add has_key shorthand methods; update stacking effort tests
197
            # Can also just raise a generic check errors; stream insertion
198
            # does this to include all the missing data
199
            self.assertRaises((errors.NoSuchRevision, errors.RevisionNotPresent),
200
                              to_repo.revision_tree, 'rev-two')
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
201
        else:
3350.3.21 by Robert Collins
Merge bzr.dev.
202
            # If not exception is raised, then the text should be
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
203
            # available.
204
            to_repo.lock_read()
205
            try:
3350.3.21 by Robert Collins
Merge bzr.dev.
206
                rt = to_repo.revision_tree('rev-two')
207
                self.assertEqual('new contents\n',
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
208
                                 rt.get_file_text('a-id'))
209
            finally:
210
                to_repo.unlock()
211
212
    def test_fetch_missing_revision_same_location_fails(self):
213
        repo_a = self.make_repository('.')
214
        repo_b = repository.Repository.open('.')
215
        try:
3350.3.21 by Robert Collins
Merge bzr.dev.
216
            self.assertRaises(errors.NoSuchRevision, repo_b.fetch, repo_a, revision_id='XXX')
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
217
        except errors.LockError, e:
218
            check_old_format_lock_error(self.repository_format)
219
220
    def test_fetch_same_location_trivial_works(self):
221
        repo_a = self.make_repository('.')
222
        repo_b = repository.Repository.open('.')
223
        try:
224
            repo_a.fetch(repo_b)
225
        except errors.LockError, e:
226
            check_old_format_lock_error(self.repository_format)
227
228
    def test_fetch_missing_text_other_location_fails(self):
229
        source_tree = self.make_branch_and_tree('source')
230
        source = source_tree.branch.repository
231
        target = self.make_to_repository('target')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
232
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
233
        # start by adding a file so the data knit for the file exists in
234
        # repositories that have specific files for each fileid.
235
        self.build_tree(['source/id'])
236
        source_tree.add(['id'], ['id'])
237
        source_tree.commit('a', rev_id='a')
238
        # now we manually insert a revision with an inventory referencing
239
        # 'id' at revision 'b', but we do not insert revision b.
240
        # this should ensure that the new versions of files are being checked
241
        # for during pull operations
242
        inv = source.get_inventory('a')
243
        source.lock_write()
3380.1.5 by Aaron Bentley
Merge with make-it-work
244
        self.addCleanup(source.unlock)
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
245
        source.start_write_group()
246
        inv['id'].revision = 'b'
247
        inv.revision_id = 'b'
248
        sha1 = source.add_inventory('b', inv, ['a'])
249
        rev = Revision(timestamp=0,
250
                       timezone=None,
251
                       committer="Foo Bar <foo@example.com>",
252
                       message="Message",
253
                       inventory_sha1=sha1,
254
                       revision_id='b')
255
        rev.parent_ids = ['a']
256
        source.add_revision('b', rev)
257
        source.commit_write_group()
258
        self.assertRaises(errors.RevisionNotPresent, target.fetch, source)
259
        self.assertFalse(target.has_revision('b'))
260
261
    def test_fetch_funky_file_id(self):
262
        from_tree = self.make_branch_and_tree('tree')
263
        if sys.platform == 'win32':
264
            from_repo = from_tree.branch.repository
265
            check_repo_format_for_funky_id_on_win32(from_repo)
266
        self.build_tree(['tree/filename'])
267
        from_tree.add('filename', 'funky-chars<>%&;"\'')
268
        from_tree.commit('commit filename')
269
        to_repo = self.make_to_repository('to')
3350.3.21 by Robert Collins
Merge bzr.dev.
270
        to_repo.fetch(from_tree.branch.repository, from_tree.get_parent_ids()[0])
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
271
3380.1.6 by Aaron Bentley
Ensure fetching munges sha1s
272
    def test_fetch_revision_hash(self):
273
        """Ensure that inventory hashes are updated by fetch"""
274
        from_tree = self.make_branch_and_tree('tree')
275
        from_tree.commit('foo', rev_id='foo-id')
276
        to_repo = self.make_to_repository('to')
277
        to_repo.fetch(from_tree.branch.repository)
278
        recorded_inv_sha1 = to_repo.get_inventory_sha1('foo-id')
279
        xml = to_repo.get_inventory_xml('foo-id')
280
        computed_inv_sha1 = osutils.sha_string(xml)
281
        self.assertEqual(computed_inv_sha1, recorded_inv_sha1)
282
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
283
284
class TestFetchDependentData(TestCaseWithInterRepository):
285
286
    def test_reference(self):
287
        from_tree = self.make_branch_and_tree('tree')
288
        to_repo = self.make_to_repository('to')
289
        if (not from_tree.supports_tree_reference() or
290
            not from_tree.branch.repository._format.supports_tree_reference or
291
            not to_repo._format.supports_tree_reference):
292
            raise TestNotApplicable("Need subtree support.")
293
        subtree = self.make_branch_and_tree('tree/subtree')
294
        subtree.commit('subrev 1')
295
        from_tree.add_reference(subtree)
296
        tree_rev = from_tree.commit('foo')
297
        # now from_tree has a last-modified of subtree of the rev id of the
298
        # commit for foo, and a reference revision of the rev id of the commit
299
        # for subrev 1
300
        to_repo.fetch(from_tree.branch.repository, tree_rev)
301
        # to_repo should have a file_graph for from_tree.path2id('subtree') and
302
        # revid tree_rev.
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.
303
        file_id = from_tree.path2id('subtree')
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
304
        to_repo.lock_read()
305
        try:
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.
306
            self.assertEqual({(file_id, tree_rev):()},
307
                to_repo.texts.get_parent_map([(file_id, tree_rev)]))
3380.1.4 by Aaron Bentley
Split interrepository fetch tests into their own file
308
        finally:
309
            to_repo.unlock()