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