~bzr-pqm/bzr/bzr.dev

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