~bzr-pqm/bzr/bzr.dev

5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2005-2011 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1115 by Martin Pool
- split fetch tests into a separate file
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1115 by Martin Pool
- split fetch tests into a separate file
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1115 by Martin Pool
- split fetch tests into a separate file
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
1238 by Martin Pool
- remove a lot of dead code from fetch
16
2323.8.2 by Aaron Bentley
Give a nicer error on fetch when repos are in incompatible formats
17
from bzrlib import (
18
    bzrdir,
19
    errors,
3871.4.2 by John Arbash Meinel
Finally a test case that reproduces bug #304841
20
    osutils,
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
21
    revision as _mod_revision,
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
22
    versionedfile,
2323.8.2 by Aaron Bentley
Give a nicer error on fetch when repos are in incompatible formats
23
    )
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
24
from bzrlib.branch import Branch
2241.1.5 by Martin Pool
Move KnitFormat2 into repofmt
25
from bzrlib.repofmt import knitrepo
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
26
from bzrlib.tests import TestCaseWithTransport
27
from bzrlib.tests.test_revision import make_branches
1551.8.42 by Aaron Bentley
Ensure that fetch properly updates inventory root knit
28
from bzrlib.upgrade import Convert
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
29
from bzrlib.workingtree import WorkingTree
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
30
2696.3.3 by Martin Pool
Start setting the default format to dirstate-tags
31
# These tests are a bit old; please instead add new tests into
4523.1.3 by Martin Pool
Rename to per_interrepository
32
# per_interrepository/ so they'll run on all relevant
2696.3.3 by Martin Pool
Start setting the default format to dirstate-tags
33
# combinations.
34
1115 by Martin Pool
- split fetch tests into a separate file
35
1238 by Martin Pool
- remove a lot of dead code from fetch
36
def has_revision(branch, revision_id):
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
37
    return branch.repository.has_revision(revision_id)
1534.4.5 by Robert Collins
Turn branch format.open into a factory.
38
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
39
40
def revision_history(branch):
6165.4.28 by Jelmer Vernooij
Fix last locking issues.
41
    branch.lock_read()
42
    try:
43
        graph = branch.repository.get_graph()
44
        history = list(graph.iter_lefthand_ancestry(branch.last_revision(),
45
            [_mod_revision.NULL_REVISION]))
46
    finally:
47
        branch.unlock()
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
48
    history.reverse()
49
    return history
50
51
1393 by Robert Collins
reenable remotebranch tests
52
def fetch_steps(self, br_a, br_b, writable_a):
53
    """A foreign test method for testing fetch locally and remotely."""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
54
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
55
    # TODO RBC 20060201 make this a repository test.
56
    repo_b = br_b.repository
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
57
    self.assertFalse(repo_b.has_revision(revision_history(br_a)[3]))
58
    self.assertTrue(repo_b.has_revision(revision_history(br_a)[2]))
59
    self.assertEquals(len(revision_history(br_b)), 7)
60
    br_b.fetch(br_a, revision_history(br_a)[2])
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
61
    # branch.fetch is not supposed to alter the revision history
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
62
    self.assertEquals(len(revision_history(br_b)), 7)
63
    self.assertFalse(repo_b.has_revision(revision_history(br_a)[3]))
1393 by Robert Collins
reenable remotebranch tests
64
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
65
    # fetching the next revision up in sample data copies one revision
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
66
    br_b.fetch(br_a, revision_history(br_a)[3])
67
    self.assertTrue(repo_b.has_revision(revision_history(br_a)[3]))
68
    self.assertFalse(has_revision(br_a, revision_history(br_b)[6]))
69
    self.assertTrue(br_a.repository.has_revision(revision_history(br_b)[5]))
1393 by Robert Collins
reenable remotebranch tests
70
1092.2.28 by Robert Collins
reenable test of fetching a branch with ghosts
71
    # When a non-branch ancestor is missing, it should be unlisted...
1415 by Robert Collins
remove the ancestry weave file
72
    # as its not reference from the inventory weave.
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
73
    br_b4 = self.make_branch('br_4')
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
74
    br_b4.fetch(br_b)
1393 by Robert Collins
reenable remotebranch tests
75
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
76
    writable_a.fetch(br_b)
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
77
    self.assertTrue(has_revision(br_a, revision_history(br_b)[3]))
78
    self.assertTrue(has_revision(br_a, revision_history(br_b)[4]))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
79
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
80
    br_b2 = self.make_branch('br_b2')
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
81
    br_b2.fetch(br_b)
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
82
    self.assertTrue(has_revision(br_b2, revision_history(br_b)[4]))
83
    self.assertTrue(has_revision(br_b2, revision_history(br_a)[2]))
84
    self.assertFalse(has_revision(br_b2, revision_history(br_a)[3]))
1393 by Robert Collins
reenable remotebranch tests
85
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
86
    br_a2 = self.make_branch('br_a2')
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
87
    br_a2.fetch(br_a)
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
88
    self.assertTrue(has_revision(br_a2, revision_history(br_b)[4]))
89
    self.assertTrue(has_revision(br_a2, revision_history(br_a)[3]))
90
    self.assertTrue(has_revision(br_a2, revision_history(br_a)[2]))
1393 by Robert Collins
reenable remotebranch tests
91
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
92
    br_a3 = self.make_branch('br_a3')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
93
    # pulling a branch with no revisions grabs nothing, regardless of
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
94
    # whats in the inventory.
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
95
    br_a3.fetch(br_a2)
1393 by Robert Collins
reenable remotebranch tests
96
    for revno in range(4):
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
97
        self.assertFalse(
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
98
            br_a3.repository.has_revision(revision_history(br_a)[revno]))
99
    br_a3.fetch(br_a2, revision_history(br_a)[2])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
100
    # pull the 3 revisions introduced by a@u-0-3
6165.4.25 by Jelmer Vernooij
Fix plugin use of revision_history.
101
    br_a3.fetch(br_a2, revision_history(br_a)[3])
4316.1.1 by Jonathan Lange
Don't raise InstallFailed from fetch. Instead let the search_missing_revision_ids error bubble up.
102
    # NoSuchRevision should be raised if the branch is missing the revision
1393 by Robert Collins
reenable remotebranch tests
103
    # that was requested.
4316.1.1 by Jonathan Lange
Don't raise InstallFailed from fetch. Instead let the search_missing_revision_ids error bubble up.
104
    self.assertRaises(errors.NoSuchRevision, br_a3.fetch, br_a2, 'pizza')
2697.2.2 by Martin Pool
deprecate Branch.append_revision
105
2697.2.5 by Martin Pool
Kill off append_revision
106
    # TODO: Test trying to fetch from a branch that points to a revision not
107
    # actually present in its repository.  Not every branch format allows you
108
    # to directly point to such revisions, so it's a bit complicated to
109
    # construct.  One way would be to uncommit and gc the revision, but not
110
    # every branch supports that.  -- mbp 20070814
1638.1.2 by Robert Collins
Change the basis-inventory file to not have the revision-id in the file name.
111
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
112
    #TODO: test that fetch correctly does reweaving when needed. RBC 20051008
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
113
    # Note that this means - updating the weave when ghosts are filled in to
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
114
    # add the right parents.
115
1185.13.4 by Robert Collins
make reweave visible as a weave method, and quickly integrate into fetch
116
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
117
class TestFetch(TestCaseWithTransport):
1392 by Robert Collins
reinstate testfetch test case
118
119
    def test_fetch(self):
1115 by Martin Pool
- split fetch tests into a separate file
120
        #highest indices a: 5, b: 7
2696.3.3 by Martin Pool
Start setting the default format to dirstate-tags
121
        br_a, br_b = make_branches(self, format='dirstate-tags')
1393 by Robert Collins
reenable remotebranch tests
122
        fetch_steps(self, br_a, br_b, br_a)
1404 by Robert Collins
only pull remote text weaves once per fetch operation
123
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
124
    def test_fetch_self(self):
125
        wt = self.make_branch_and_tree('br')
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
126
        wt.branch.fetch(wt.branch)
1558.4.11 by Aaron Bentley
Allow merge against self, make fetching self a noop
127
1551.8.42 by Aaron Bentley
Ensure that fetch properly updates inventory root knit
128
    def test_fetch_root_knit(self):
1551.8.43 by Aaron Bentley
Update from reviews
129
        """Ensure that knit2.fetch() updates the root knit
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
130
1551.8.43 by Aaron Bentley
Update from reviews
131
        This tests the case where the root has a new revision, but there are no
132
        corresponding filename, parent, contents or other changes.
1551.8.42 by Aaron Bentley
Ensure that fetch properly updates inventory root knit
133
        """
1551.8.43 by Aaron Bentley
Update from reviews
134
        knit1_format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
135
        knit1_format.repository_format = knitrepo.RepositoryFormatKnit1()
1551.8.43 by Aaron Bentley
Update from reviews
136
        knit2_format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
137
        knit2_format.repository_format = knitrepo.RepositoryFormatKnit3()
1551.8.43 by Aaron Bentley
Update from reviews
138
        # we start with a knit1 repository because that causes the
139
        # root revision to change for each commit, even though the content,
140
        # parent, name, and other attributes are unchanged.
141
        tree = self.make_branch_and_tree('tree', knit1_format)
1551.8.42 by Aaron Bentley
Ensure that fetch properly updates inventory root knit
142
        tree.set_root_id('tree-root')
143
        tree.commit('rev1', rev_id='rev1')
144
        tree.commit('rev2', rev_id='rev2')
1551.8.43 by Aaron Bentley
Update from reviews
145
146
        # Now we convert it to a knit2 repository so that it has a root knit
147
        Convert(tree.basedir, knit2_format)
1551.8.42 by Aaron Bentley
Ensure that fetch properly updates inventory root knit
148
        tree = WorkingTree.open(tree.basedir)
1551.8.43 by Aaron Bentley
Update from reviews
149
        branch = self.make_branch('branch', format=knit2_format)
1551.8.42 by Aaron Bentley
Ensure that fetch properly updates inventory root knit
150
        branch.pull(tree.branch, stop_revision='rev1')
151
        repo = branch.repository
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.
152
        repo.lock_read()
153
        try:
154
            # Make sure fetch retrieved only what we requested
155
            self.assertEqual({('tree-root', 'rev1'):()},
156
                repo.texts.get_parent_map(
157
                    [('tree-root', 'rev1'), ('tree-root', 'rev2')]))
158
        finally:
159
            repo.unlock()
1551.8.42 by Aaron Bentley
Ensure that fetch properly updates inventory root knit
160
        branch.pull(tree.branch)
1551.8.43 by Aaron Bentley
Update from reviews
161
        # Make sure that the next revision in the root knit was retrieved,
162
        # even though the text, name, parent_id, etc., were unchanged.
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.
163
        repo.lock_read()
164
        try:
165
            # Make sure fetch retrieved only what we requested
166
            self.assertEqual({('tree-root', 'rev2'):(('tree-root', 'rev1'),)},
167
                repo.texts.get_parent_map([('tree-root', 'rev2')]))
168
        finally:
169
            repo.unlock()
1551.8.42 by Aaron Bentley
Ensure that fetch properly updates inventory root knit
170
2323.8.2 by Aaron Bentley
Give a nicer error on fetch when repos are in incompatible formats
171
    def test_fetch_incompatible(self):
172
        knit_tree = self.make_branch_and_tree('knit', format='knit')
173
        knit3_tree = self.make_branch_and_tree('knit3',
174
            format='dirstate-with-subtree')
175
        knit3_tree.commit('blah')
3582.1.2 by Martin Pool
Default InterRepository.fetch raises IncompatibleRepositories
176
        e = self.assertRaises(errors.IncompatibleRepositories,
177
                              knit_tree.branch.fetch, knit3_tree.branch)
178
        self.assertContainsRe(str(e),
179
            r"(?m).*/knit.*\nis not compatible with\n.*/knit3/.*\n"
180
            r"different rich-root support")
2323.8.2 by Aaron Bentley
Give a nicer error on fetch when repos are in incompatible formats
181
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
182
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
183
class TestMergeFetch(TestCaseWithTransport):
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
184
185
    def test_merge_fetches_unrelated(self):
186
        """Merge brings across history from unrelated source"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
187
        wt1 = self.make_branch_and_tree('br1')
188
        br1 = wt1.branch
189
        wt1.commit(message='rev 1-1', rev_id='1-1')
190
        wt1.commit(message='rev 1-2', rev_id='1-2')
191
        wt2 = self.make_branch_and_tree('br2')
192
        br2 = wt2.branch
193
        wt2.commit(message='rev 2-1', rev_id='2-1')
1551.15.70 by Aaron Bentley
Avoid using builtins.merge
194
        wt2.merge_from_branch(br1, from_revision='null:')
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
195
        self._check_revs_present(br2)
196
1185.16.94 by mbp at sourcefrog
New test that merge fetches revisions from source
197
    def test_merge_fetches(self):
198
        """Merge brings across history from source"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
199
        wt1 = self.make_branch_and_tree('br1')
200
        br1 = wt1.branch
201
        wt1.commit(message='rev 1-1', rev_id='1-1')
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
202
        dir_2 = br1.bzrdir.sprout('br2')
203
        br2 = dir_2.open_branch()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
204
        wt1.commit(message='rev 1-2', rev_id='1-2')
1551.15.70 by Aaron Bentley
Avoid using builtins.merge
205
        wt2 = dir_2.open_workingtree()
206
        wt2.commit(message='rev 2-1', rev_id='2-1')
207
        wt2.merge_from_branch(br1)
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
208
        self._check_revs_present(br2)
209
210
    def _check_revs_present(self, br2):
1185.16.94 by mbp at sourcefrog
New test that merge fetches revisions from source
211
        for rev_id in '1-1', '1-2', '2-1':
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
212
            self.assertTrue(br2.repository.has_revision(rev_id))
213
            rev = br2.repository.get_revision(rev_id)
1185.16.94 by mbp at sourcefrog
New test that merge fetches revisions from source
214
            self.assertEqual(rev.revision_id, rev_id)
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
215
            self.assertTrue(br2.repository.get_inventory(rev_id))
1185.16.94 by mbp at sourcefrog
New test that merge fetches revisions from source
216
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
217
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
218
class TestMergeFileHistory(TestCaseWithTransport):
219
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
220
    def setUp(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
221
        super(TestMergeFileHistory, self).setUp()
222
        wt1 = self.make_branch_and_tree('br1')
223
        br1 = wt1.branch
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
224
        self.build_tree_contents([('br1/file', 'original contents\n')])
1534.4.28 by Robert Collins
first cut at merge from integration.
225
        wt1.add('file', 'this-file-id')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
226
        wt1.commit(message='rev 1-1', rev_id='1-1')
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
227
        dir_2 = br1.bzrdir.sprout('br2')
228
        br2 = dir_2.open_branch()
229
        wt2 = dir_2.open_workingtree()
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
230
        self.build_tree_contents([('br1/file', 'original from 1\n')])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
231
        wt1.commit(message='rev 1-2', rev_id='1-2')
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
232
        self.build_tree_contents([('br1/file', 'agreement\n')])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
233
        wt1.commit(message='rev 1-3', rev_id='1-3')
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
234
        self.build_tree_contents([('br2/file', 'contents in 2\n')])
1534.4.28 by Robert Collins
first cut at merge from integration.
235
        wt2.commit(message='rev 2-1', rev_id='2-1')
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
236
        self.build_tree_contents([('br2/file', 'agreement\n')])
1534.4.28 by Robert Collins
first cut at merge from integration.
237
        wt2.commit(message='rev 2-2', rev_id='2-2')
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
238
239
    def test_merge_fetches_file_history(self):
240
        """Merge brings across file histories"""
241
        br2 = Branch.open('br2')
1551.15.70 by Aaron Bentley
Avoid using builtins.merge
242
        br1 = Branch.open('br1')
243
        wt2 = WorkingTree.open('br2').merge_from_branch(br1)
3010.1.4 by Robert Collins
Make the knit specific fetch tests knit specific, and lock the branch when looking at historical texts in test_fetch.
244
        br2.lock_read()
245
        self.addCleanup(br2.unlock)
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
246
        for rev_id, text in [('1-2', 'original from 1\n'),
247
                             ('1-3', 'agreement\n'),
248
                             ('2-1', 'contents in 2\n'),
249
                             ('2-2', 'agreement\n')]:
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
250
            self.assertEqualDiff(
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
251
                br2.repository.revision_tree(
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
252
                    rev_id).get_file_text('this-file-id'), text)
1185.16.96 by mbp at sourcefrog
More merge/fetch tests
253
254
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
255
class TestKnitToPackFetch(TestCaseWithTransport):
256
4098.4.3 by Robert Collins
Change fetch effort tests to reflect the new change to read the adjacent inventories to ensure accurate fetching.
257
    def find_get_record_stream(self, calls, expected_count=1):
258
        """In a list of calls, find the last 'get_record_stream'.
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
259
4098.4.3 by Robert Collins
Change fetch effort tests to reflect the new change to read the adjacent inventories to ensure accurate fetching.
260
        :param expected_count: The number of calls we should exepect to find.
261
            If a different number is found, an assertion is raised.
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
262
        """
263
        get_record_call = None
4098.4.3 by Robert Collins
Change fetch effort tests to reflect the new change to read the adjacent inventories to ensure accurate fetching.
264
        call_count = 0
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
265
        for call in calls:
266
            if call[0] == 'get_record_stream':
4098.4.3 by Robert Collins
Change fetch effort tests to reflect the new change to read the adjacent inventories to ensure accurate fetching.
267
                call_count += 1
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
268
                get_record_call = call
4098.4.3 by Robert Collins
Change fetch effort tests to reflect the new change to read the adjacent inventories to ensure accurate fetching.
269
        self.assertEqual(expected_count, call_count)
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
270
        return get_record_call
271
272
    def test_fetch_with_deltas_no_delta_closure(self):
273
        tree = self.make_branch_and_tree('source', format='dirstate')
274
        target = self.make_repository('target', format='pack-0.92')
275
        self.build_tree(['source/file'])
276
        tree.set_root_id('root-id')
277
        tree.add('file', 'file-id')
278
        tree.commit('one', rev_id='rev-one')
279
        source = tree.branch.repository
280
        source.texts = versionedfile.RecordingVersionedFilesDecorator(
281
                        source.texts)
282
        source.signatures = versionedfile.RecordingVersionedFilesDecorator(
283
                        source.signatures)
284
        source.revisions = versionedfile.RecordingVersionedFilesDecorator(
285
                        source.revisions)
286
        source.inventories = versionedfile.RecordingVersionedFilesDecorator(
287
                        source.inventories)
288
        # precondition
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
289
        self.assertTrue(target._format._fetch_uses_deltas)
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
290
        target.fetch(source, revision_id='rev-one')
291
        self.assertEqual(('get_record_stream', [('file-id', 'rev-one')],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
292
                          target._format._fetch_order, False),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
293
                         self.find_get_record_stream(source.texts.calls))
294
        self.assertEqual(('get_record_stream', [('rev-one',)],
4098.4.3 by Robert Collins
Change fetch effort tests to reflect the new change to read the adjacent inventories to ensure accurate fetching.
295
          target._format._fetch_order, False),
296
          self.find_get_record_stream(source.inventories.calls, 2))
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
297
        self.assertEqual(('get_record_stream', [('rev-one',)],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
298
                          target._format._fetch_order, False),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
299
                         self.find_get_record_stream(source.revisions.calls))
300
        # XXX: Signatures is special, and slightly broken. The
301
        # standard item_keys_introduced_by actually does a lookup for every
302
        # signature to see if it exists, rather than waiting to do them all at
303
        # once at the end. The fetch code then does an all-at-once and just
304
        # allows for some of them to be missing.
305
        # So we know there will be extra calls, but the *last* one is the one
306
        # we care about.
307
        signature_calls = source.signatures.calls[-1:]
308
        self.assertEqual(('get_record_stream', [('rev-one',)],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
309
                          target._format._fetch_order, False),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
310
                         self.find_get_record_stream(signature_calls))
311
312
    def test_fetch_no_deltas_with_delta_closure(self):
313
        tree = self.make_branch_and_tree('source', format='dirstate')
314
        target = self.make_repository('target', format='pack-0.92')
315
        self.build_tree(['source/file'])
316
        tree.set_root_id('root-id')
317
        tree.add('file', 'file-id')
318
        tree.commit('one', rev_id='rev-one')
319
        source = tree.branch.repository
320
        source.texts = versionedfile.RecordingVersionedFilesDecorator(
321
                        source.texts)
322
        source.signatures = versionedfile.RecordingVersionedFilesDecorator(
323
                        source.signatures)
324
        source.revisions = versionedfile.RecordingVersionedFilesDecorator(
325
                        source.revisions)
326
        source.inventories = versionedfile.RecordingVersionedFilesDecorator(
327
                        source.inventories)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
328
        # XXX: This won't work in general, but for the dirstate format it does.
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
329
        self.overrideAttr(target._format, '_fetch_uses_deltas', False)
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
330
        target.fetch(source, revision_id='rev-one')
331
        self.assertEqual(('get_record_stream', [('file-id', 'rev-one')],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
332
                          target._format._fetch_order, True),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
333
                         self.find_get_record_stream(source.texts.calls))
334
        self.assertEqual(('get_record_stream', [('rev-one',)],
4098.4.3 by Robert Collins
Change fetch effort tests to reflect the new change to read the adjacent inventories to ensure accurate fetching.
335
            target._format._fetch_order, True),
336
            self.find_get_record_stream(source.inventories.calls, 2))
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
337
        self.assertEqual(('get_record_stream', [('rev-one',)],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
338
                          target._format._fetch_order, True),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
339
                         self.find_get_record_stream(source.revisions.calls))
340
        # XXX: Signatures is special, and slightly broken. The
341
        # standard item_keys_introduced_by actually does a lookup for every
342
        # signature to see if it exists, rather than waiting to do them all at
343
        # once at the end. The fetch code then does an all-at-once and just
344
        # allows for some of them to be missing.
345
        # So we know there will be extra calls, but the *last* one is the one
346
        # we care about.
347
        signature_calls = source.signatures.calls[-1:]
348
        self.assertEqual(('get_record_stream', [('rev-one',)],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
349
                          target._format._fetch_order, True),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
350
                         self.find_get_record_stream(signature_calls))
351
3849.3.1 by John Arbash Meinel
Part of bug #300289, stop requiring plain fulltexts for revisions.
352
    def test_fetch_revisions_with_deltas_into_pack(self):
353
        # See BUG #261339, dev versions of bzr could accidentally create deltas
354
        # in revision texts in knit branches (when fetching from packs). So we
355
        # ensure that *if* a knit repository has a delta in revisions, that it
356
        # gets properly expanded back into a fulltext when stored in the pack
357
        # file.
358
        tree = self.make_branch_and_tree('source', format='dirstate')
359
        target = self.make_repository('target', format='pack-0.92')
360
        self.build_tree(['source/file'])
361
        tree.set_root_id('root-id')
362
        tree.add('file', 'file-id')
363
        tree.commit('one', rev_id='rev-one')
364
        # Hack the KVF for revisions so that it "accidentally" allows a delta
365
        tree.branch.repository.revisions._max_delta_chain = 200
366
        tree.commit('two', rev_id='rev-two')
367
        source = tree.branch.repository
368
        # Ensure that we stored a delta
369
        source.lock_read()
370
        self.addCleanup(source.unlock)
371
        record = source.revisions.get_record_stream([('rev-two',)],
372
            'unordered', False).next()
373
        self.assertEqual('knit-delta-gz', record.storage_kind)
374
        target.fetch(tree.branch.repository, revision_id='rev-two')
375
        # The record should get expanded back to a fulltext
376
        target.lock_read()
377
        self.addCleanup(target.unlock)
378
        record = target.revisions.get_record_stream([('rev-two',)],
379
            'unordered', False).next()
380
        self.assertEqual('knit-ft-gz', record.storage_kind)
381
3871.4.2 by John Arbash Meinel
Finally a test case that reproduces bug #304841
382
    def test_fetch_with_fallback_and_merge(self):
383
        builder = self.make_branch_builder('source', format='pack-0.92')
384
        builder.start_series()
385
        # graph
386
        #   A
387
        #   |\
388
        #   B C
389
        #   | |
390
        #   | D
391
        #   | |
392
        #   | E
393
        #    \|
394
        #     F
395
        # A & B are present in the base (stacked-on) repository, A-E are
396
        # present in the source.
3871.4.4 by John Arbash Meinel
Another fix for bug #304841. As a broad-spectrum solution,
397
        # This reproduces bug #304841
3871.4.2 by John Arbash Meinel
Finally a test case that reproduces bug #304841
398
        # We need a large enough inventory that total size of compressed deltas
399
        # is shorter than the size of a compressed fulltext. We have to use
400
        # random ids because otherwise the inventory fulltext compresses too
401
        # well and the deltas get bigger.
402
        to_add = [
403
            ('add', ('', 'TREE_ROOT', 'directory', None))]
404
        for i in xrange(10):
405
            fname = 'file%03d' % (i,)
406
            fileid = '%s-%s' % (fname, osutils.rand_chars(64))
407
            to_add.append(('add', (fname, fileid, 'file', 'content\n')))
408
        builder.build_snapshot('A', None, to_add)
409
        builder.build_snapshot('B', ['A'], [])
410
        builder.build_snapshot('C', ['A'], [])
411
        builder.build_snapshot('D', ['C'], [])
412
        builder.build_snapshot('E', ['D'], [])
413
        builder.build_snapshot('F', ['E', 'B'], [])
414
        builder.finish_series()
415
        source_branch = builder.get_branch()
416
        source_branch.bzrdir.sprout('base', revision_id='B')
417
        target_branch = self.make_branch('target', format='1.6')
418
        target_branch.set_stacked_on_url('../base')
419
        source = source_branch.repository
420
        source.lock_read()
421
        self.addCleanup(source.unlock)
422
        source.inventories = versionedfile.OrderingVersionedFilesDecorator(
423
                        source.inventories,
424
                        key_priority={('E',): 1, ('D',): 2, ('C',): 4,
425
                                      ('F',): 3})
426
        # Ensure that the content is yielded in the proper order, and given as
427
        # the expected kinds
428
        records = [(record.key, record.storage_kind)
429
                   for record in source.inventories.get_record_stream(
430
                        [('D',), ('C',), ('E',), ('F',)], 'unordered', False)]
431
        self.assertEqual([(('E',), 'knit-delta-gz'), (('D',), 'knit-delta-gz'),
432
                          (('F',), 'knit-delta-gz'), (('C',), 'knit-delta-gz')],
433
                          records)
434
435
        target_branch.lock_write()
436
        self.addCleanup(target_branch.unlock)
437
        target = target_branch.repository
438
        target.fetch(source, revision_id='F')
439
        # 'C' should be expanded to a fulltext, but D and E should still be
440
        # deltas
441
        stream = target.inventories.get_record_stream(
442
            [('C',), ('D',), ('E',), ('F',)],
443
            'unordered', False)
444
        kinds = dict((record.key, record.storage_kind) for record in stream)
445
        self.assertEqual({('C',): 'knit-ft-gz', ('D',): 'knit-delta-gz',
446
                          ('E',): 'knit-delta-gz', ('F',): 'knit-delta-gz'},
447
                         kinds)
3849.3.1 by John Arbash Meinel
Part of bug #300289, stop requiring plain fulltexts for revisions.
448
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
449
3380.1.1 by Aaron Bentley
Fix inventory insertion to work in topological order
450
class Test1To2Fetch(TestCaseWithTransport):
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
451
    """Tests for Model1To2 failure modes"""
3380.1.1 by Aaron Bentley
Fix inventory insertion to work in topological order
452
3380.2.4 by Aaron Bentley
Updates from review
453
    def make_tree_and_repo(self):
454
        self.tree = self.make_branch_and_tree('tree', format='pack-0.92')
455
        self.repo = self.make_repository('rich-repo', format='rich-root-pack')
456
        self.repo.lock_write()
457
        self.addCleanup(self.repo.unlock)
458
459
    def do_fetch_order_test(self, first, second):
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
460
        """Test that fetch works no matter what the set order of revision is.
3380.1.1 by Aaron Bentley
Fix inventory insertion to work in topological order
461
462
        This test depends on the order of items in a set, which is
463
        implementation-dependant, so we test A, B and then B, A.
464
        """
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
465
        self.make_tree_and_repo()
466
        self.tree.commit('Commit 1', rev_id=first)
467
        self.tree.commit('Commit 2', rev_id=second)
468
        self.repo.fetch(self.tree.branch.repository, second)
469
3380.2.4 by Aaron Bentley
Updates from review
470
    def test_fetch_order_AB(self):
3380.2.7 by Aaron Bentley
Update docs
471
        """See do_fetch_order_test"""
3380.2.4 by Aaron Bentley
Updates from review
472
        self.do_fetch_order_test('A', 'B')
473
474
    def test_fetch_order_BA(self):
3380.2.7 by Aaron Bentley
Update docs
475
        """See do_fetch_order_test"""
3380.2.4 by Aaron Bentley
Updates from review
476
        self.do_fetch_order_test('B', 'A')
477
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
478
    def get_parents(self, file_id, revision_id):
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.
479
        self.repo.lock_read()
480
        try:
481
            parent_map = self.repo.texts.get_parent_map([(file_id, revision_id)])
482
            return parent_map[(file_id, revision_id)]
483
        finally:
484
            self.repo.unlock()
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
485
3380.1.2 by Aaron Bentley
Improve handling ghosts and changing root_ids
486
    def test_fetch_ghosts(self):
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
487
        self.make_tree_and_repo()
488
        self.tree.commit('first commit', rev_id='left-parent')
489
        self.tree.add_parent_tree_id('ghost-parent')
490
        fork = self.tree.bzrdir.sprout('fork', 'null:').open_workingtree()
3380.1.2 by Aaron Bentley
Improve handling ghosts and changing root_ids
491
        fork.commit('not a ghost', rev_id='not-ghost-parent')
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
492
        self.tree.branch.repository.fetch(fork.branch.repository,
3380.1.2 by Aaron Bentley
Improve handling ghosts and changing root_ids
493
                                     'not-ghost-parent')
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
494
        self.tree.add_parent_tree_id('not-ghost-parent')
495
        self.tree.commit('second commit', rev_id='second-id')
496
        self.repo.fetch(self.tree.branch.repository, 'second-id')
497
        root_id = self.tree.get_root_id()
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.
498
        self.assertEqual(
4324.3.4 by Robert Collins
Update static rich root test to support new, reconcile-compatible algorithm.
499
            ((root_id, 'left-parent'), (root_id, 'not-ghost-parent')),
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.
500
            self.get_parents(root_id, 'second-id'))
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
501
502
    def make_two_commits(self, change_root, fetch_twice):
503
        self.make_tree_and_repo()
504
        self.tree.commit('first commit', rev_id='first-id')
505
        if change_root:
506
            self.tree.set_root_id('unique-id')
507
        self.tree.commit('second commit', rev_id='second-id')
508
        if fetch_twice:
509
            self.repo.fetch(self.tree.branch.repository, 'first-id')
510
        self.repo.fetch(self.tree.branch.repository, 'second-id')
3380.1.2 by Aaron Bentley
Improve handling ghosts and changing root_ids
511
512
    def test_fetch_changed_root(self):
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
513
        self.make_two_commits(change_root=True, fetch_twice=False)
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.
514
        self.assertEqual((), self.get_parents('unique-id', 'second-id'))
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
515
516
    def test_two_fetch_changed_root(self):
517
        self.make_two_commits(change_root=True, fetch_twice=True)
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.
518
        self.assertEqual((), self.get_parents('unique-id', 'second-id'))
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
519
520
    def test_two_fetches(self):
521
        self.make_two_commits(change_root=False, fetch_twice=True)
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.
522
        self.assertEqual((('TREE_ROOT', 'first-id'),),
523
            self.get_parents('TREE_ROOT', 'second-id'))