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