~bzr-pqm/bzr/bzr.dev

2697.2.2 by Martin Pool
deprecate Branch.append_revision
1
# Copyright (C) 2005, 2007 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
2929.3.8 by Vincent Ladeuil
Rename bzrlib/test/HTTPTestUtils.py to bzrlib/tests/http_utils.py and fix uses.
34
from bzrlib.tests.http_utils import TestCaseWithWebserver
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
35
from bzrlib.tests.test_revision import make_branches
36
from bzrlib.trace import mutter
1551.8.42 by Aaron Bentley
Ensure that fetch properly updates inventory root knit
37
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.
38
from bzrlib.workingtree import WorkingTree
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
39
2696.3.3 by Martin Pool
Start setting the default format to dirstate-tags
40
# These tests are a bit old; please instead add new tests into
41
# interrepository_implementations/ so they'll run on all relevant
42
# combinations.
43
1115 by Martin Pool
- split fetch tests into a separate file
44
1238 by Martin Pool
- remove a lot of dead code from fetch
45
def has_revision(branch, revision_id):
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
46
    return branch.repository.has_revision(revision_id)
1534.4.5 by Robert Collins
Turn branch format.open into a factory.
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
53
    self.assertFalse(repo_b.has_revision(br_a.revision_history()[3]))
54
    self.assertTrue(repo_b.has_revision(br_a.revision_history()[2]))
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
55
    self.assertEquals(len(br_b.revision_history()), 7)
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
56
    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.
57
    # branch.fetch is not supposed to alter the revision history
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
58
    self.assertEquals(len(br_b.revision_history()), 7)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
59
    self.assertFalse(repo_b.has_revision(br_a.revision_history()[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
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
62
    br_b.fetch(br_a, br_a.revision_history()[3])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
63
    self.assertTrue(repo_b.has_revision(br_a.revision_history()[3]))
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
64
    self.assertFalse(has_revision(br_a, br_b.revision_history()[6]))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
65
    self.assertTrue(br_a.repository.has_revision(br_b.revision_history()[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)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
73
    self.assertTrue(has_revision(br_a, br_b.revision_history()[3]))
74
    self.assertTrue(has_revision(br_a, br_b.revision_history()[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)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
78
    self.assertTrue(has_revision(br_b2, br_b.revision_history()[4]))
79
    self.assertTrue(has_revision(br_b2, br_a.revision_history()[2]))
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
80
    self.assertFalse(has_revision(br_b2, br_a.revision_history()[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)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
84
    self.assertTrue(has_revision(br_a2, br_b.revision_history()[4]))
85
    self.assertTrue(has_revision(br_a2, br_a.revision_history()[3]))
86
    self.assertTrue(has_revision(br_a2, br_a.revision_history()[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(
94
            br_a3.repository.has_revision(br_a.revision_history()[revno]))
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
95
    br_a3.fetch(br_a2, br_a.revision_history()[2])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
96
    # pull the 3 revisions introduced by a@u-0-3
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
97
    br_a3.fetch(br_a2, br_a.revision_history()[3])
1393 by Robert Collins
reenable remotebranch tests
98
    # InstallFailed should be raised if the branch is missing the revision
99
    # that was requested.
2697.2.2 by Martin Pool
deprecate Branch.append_revision
100
    self.assertRaises(errors.InstallFailed, br_a3.fetch, br_a2, 'pizza')
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
1404 by Robert Collins
only pull remote text weaves once per fetch operation
251
class TestHttpFetch(TestCaseWithWebserver):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
252
    # FIXME RBC 20060124 this really isn't web specific, perhaps an
253
    # instrumented readonly transport? Can we do an instrumented
254
    # adapter and use self.get_readonly_url ?
1404 by Robert Collins
only pull remote text weaves once per fetch operation
255
256
    def test_fetch(self):
257
        #highest indices a: 5, b: 7
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
258
        br_a, br_b = make_branches(self)
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.
259
        br_rem_a = Branch.open(self.get_readonly_url('branch1'))
1404 by Robert Collins
only pull remote text weaves once per fetch operation
260
        fetch_steps(self, br_rem_a, br_b, br_a)
261
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
262
    def _count_log_matches(self, target, logs):
263
        """Count the number of times the target file pattern was fetched in an http log"""
2004.1.22 by v.ladeuil+lp at free
Implements Range header handling for GET requests. Fix a test.
264
        get_succeeds_re = re.compile(
265
            '.*"GET .*%s HTTP/1.1" 20[06] - "-" "bzr/%s' %
266
            (     target,                    bzrlib.__version__))
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
267
        c = 0
268
        for line in logs:
2004.1.22 by v.ladeuil+lp at free
Implements Range header handling for GET requests. Fix a test.
269
            if get_succeeds_re.match(line):
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
270
                c += 1
271
        return c
272
1404 by Robert Collins
only pull remote text weaves once per fetch operation
273
    def test_weaves_are_retrieved_once(self):
274
        self.build_tree(("source/", "source/file", "target/"))
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.
275
        # This test depends on knit dasta storage.
276
        wt = self.make_branch_and_tree('source', format='dirstate-tags')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
277
        branch = wt.branch
278
        wt.add(["file"], ["id"])
279
        wt.commit("added file")
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
280
        open("source/file", 'w').write("blah\n")
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
281
        wt.commit("changed file")
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
282
        target = BzrDir.create_branch_and_repo("target/")
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.
283
        source = Branch.open(self.get_readonly_url("source/"))
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
284
        target.fetch(source)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
285
        # this is the path to the literal file. As format changes
1430 by Robert Collins
touchup the prefixed-store patch
286
        # occur it needs to be updated. FIXME: ask the store for the
287
        # path.
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
288
        self.log("web server logs are:")
289
        http_logs = self.get_readonly_server().logs
290
        self.log('\n'.join(http_logs))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
291
        # unfortunately this log entry is branch format specific. We could
292
        # factor out the 'what files does this format use' to a method on the
1666.1.6 by Robert Collins
Make knit the default format.
293
        # repository, which would let us to this generically. RBC 20060419
3422.1.1 by John Arbash Meinel
merge in bzr-1.5rc1, revert the transaction cache change
294
        # RBC 20080408: Or perhaps we can assert that no files are fully read
295
        # twice?
1666.1.6 by Robert Collins
Make knit the default format.
296
        self.assertEqual(1, self._count_log_matches('/ce/id.kndx', http_logs))
297
        self.assertEqual(1, self._count_log_matches('/ce/id.knit', http_logs))
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.
298
        self.assertEqual(1, self._count_log_matches('inventory.kndx', http_logs))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
299
        # this r-h check test will prevent regressions, but it currently already
1417.1.12 by Robert Collins
cache revision history during read transactions
300
        # passes, before the patch to cache-rh is applied :[
2230.3.10 by Aaron Bentley
Genericised test_fetch to handle branch 6 retrieval patterns
301
        self.assertTrue(1 >= self._count_log_matches('revision-history',
302
                                                     http_logs))
303
        self.assertTrue(1 >= self._count_log_matches('last-revision',
304
                                                     http_logs))
1530.1.18 by Robert Collins
unbreak test_fetch
305
        # FIXME naughty poking in there.
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.
306
        self.get_readonly_server().logs = []
3241.1.4 by Andrew Bennetts
Use get_smart_medium as suggested by Robert, and deal with the fallout.
307
        # check there is nothing more to fetch.  We take care to re-use the
308
        # existing transport so that the request logs we're about to examine
309
        # aren't cluttered with redundant probes for a smart server.
3241.1.5 by Andrew Bennetts
Add comment suggested by Robert.
310
        # XXX: Perhaps this further parameterisation: test http with smart
311
        # server, and test http without smart server?
3241.1.4 by Andrew Bennetts
Use get_smart_medium as suggested by Robert, and deal with the fallout.
312
        source = Branch.open(
313
            self.get_readonly_url("source/"),
314
            possible_transports=[source.bzrdir.root_transport])
4065.1.1 by Robert Collins
Change the return value of fetch() to None.
315
        target.fetch(source)
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
316
        # should make just two requests
317
        http_logs = self.get_readonly_server().logs
318
        self.log("web server logs are:")
319
        self.log('\n'.join(http_logs))
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
320
        self.assertEqual(1, self._count_log_matches('branch-format', http_logs))
321
        self.assertEqual(1, self._count_log_matches('branch/format', http_logs))
3422.1.1 by John Arbash Meinel
merge in bzr-1.5rc1, revert the transaction cache change
322
        self.assertEqual(1, self._count_log_matches('repository/format',
323
            http_logs))
2230.3.11 by Aaron Bentley
Fix line endings
324
        self.assertTrue(1 >= self._count_log_matches('revision-history',
325
                                                     http_logs))
326
        self.assertTrue(1 >= self._count_log_matches('last-revision',
327
                                                     http_logs))
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
328
        self.assertEqual(4, len(http_logs))
3380.1.1 by Aaron Bentley
Fix inventory insertion to work in topological order
329
330
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
331
class TestKnitToPackFetch(TestCaseWithTransport):
332
4098.4.3 by Robert Collins
Change fetch effort tests to reflect the new change to read the adjacent inventories to ensure accurate fetching.
333
    def find_get_record_stream(self, calls, expected_count=1):
334
        """In a list of calls, find the last 'get_record_stream'.
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
335
4098.4.3 by Robert Collins
Change fetch effort tests to reflect the new change to read the adjacent inventories to ensure accurate fetching.
336
        :param expected_count: The number of calls we should exepect to find.
337
            If a different number is found, an assertion is raised.
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
338
        """
339
        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.
340
        call_count = 0
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
341
        for call in calls:
342
            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.
343
                call_count += 1
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
344
                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.
345
        self.assertEqual(expected_count, call_count)
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
346
        return get_record_call
347
348
    def test_fetch_with_deltas_no_delta_closure(self):
349
        tree = self.make_branch_and_tree('source', format='dirstate')
350
        target = self.make_repository('target', format='pack-0.92')
351
        self.build_tree(['source/file'])
352
        tree.set_root_id('root-id')
353
        tree.add('file', 'file-id')
354
        tree.commit('one', rev_id='rev-one')
355
        source = tree.branch.repository
356
        source.texts = versionedfile.RecordingVersionedFilesDecorator(
357
                        source.texts)
358
        source.signatures = versionedfile.RecordingVersionedFilesDecorator(
359
                        source.signatures)
360
        source.revisions = versionedfile.RecordingVersionedFilesDecorator(
361
                        source.revisions)
362
        source.inventories = versionedfile.RecordingVersionedFilesDecorator(
363
                        source.inventories)
364
        # precondition
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
365
        self.assertTrue(target._format._fetch_uses_deltas)
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
366
        target.fetch(source, revision_id='rev-one')
367
        self.assertEqual(('get_record_stream', [('file-id', 'rev-one')],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
368
                          target._format._fetch_order, False),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
369
                         self.find_get_record_stream(source.texts.calls))
370
        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.
371
          target._format._fetch_order, False),
372
          self.find_get_record_stream(source.inventories.calls, 2))
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
373
        self.assertEqual(('get_record_stream', [('rev-one',)],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
374
                          target._format._fetch_order, False),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
375
                         self.find_get_record_stream(source.revisions.calls))
376
        # XXX: Signatures is special, and slightly broken. The
377
        # standard item_keys_introduced_by actually does a lookup for every
378
        # signature to see if it exists, rather than waiting to do them all at
379
        # once at the end. The fetch code then does an all-at-once and just
380
        # allows for some of them to be missing.
381
        # So we know there will be extra calls, but the *last* one is the one
382
        # we care about.
383
        signature_calls = source.signatures.calls[-1:]
384
        self.assertEqual(('get_record_stream', [('rev-one',)],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
385
                          target._format._fetch_order, False),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
386
                         self.find_get_record_stream(signature_calls))
387
388
    def test_fetch_no_deltas_with_delta_closure(self):
389
        tree = self.make_branch_and_tree('source', format='dirstate')
390
        target = self.make_repository('target', format='pack-0.92')
391
        self.build_tree(['source/file'])
392
        tree.set_root_id('root-id')
393
        tree.add('file', 'file-id')
394
        tree.commit('one', rev_id='rev-one')
395
        source = tree.branch.repository
396
        source.texts = versionedfile.RecordingVersionedFilesDecorator(
397
                        source.texts)
398
        source.signatures = versionedfile.RecordingVersionedFilesDecorator(
399
                        source.signatures)
400
        source.revisions = versionedfile.RecordingVersionedFilesDecorator(
401
                        source.revisions)
402
        source.inventories = versionedfile.RecordingVersionedFilesDecorator(
403
                        source.inventories)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
404
        # XXX: This won't work in general, but for the dirstate format it does.
405
        old_fetch_uses_deltas_setting = target._format._fetch_uses_deltas
406
        def restore():
407
            target._format._fetch_uses_deltas = old_fetch_uses_deltas_setting
408
        self.addCleanup(restore)
409
        target._format._fetch_uses_deltas = False
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
410
        target.fetch(source, revision_id='rev-one')
411
        self.assertEqual(('get_record_stream', [('file-id', 'rev-one')],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
412
                          target._format._fetch_order, True),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
413
                         self.find_get_record_stream(source.texts.calls))
414
        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.
415
            target._format._fetch_order, True),
416
            self.find_get_record_stream(source.inventories.calls, 2))
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
417
        self.assertEqual(('get_record_stream', [('rev-one',)],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
418
                          target._format._fetch_order, True),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
419
                         self.find_get_record_stream(source.revisions.calls))
420
        # XXX: Signatures is special, and slightly broken. The
421
        # standard item_keys_introduced_by actually does a lookup for every
422
        # signature to see if it exists, rather than waiting to do them all at
423
        # once at the end. The fetch code then does an all-at-once and just
424
        # allows for some of them to be missing.
425
        # So we know there will be extra calls, but the *last* one is the one
426
        # we care about.
427
        signature_calls = source.signatures.calls[-1:]
428
        self.assertEqual(('get_record_stream', [('rev-one',)],
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
429
                          target._format._fetch_order, True),
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
430
                         self.find_get_record_stream(signature_calls))
431
3849.3.1 by John Arbash Meinel
Part of bug #300289, stop requiring plain fulltexts for revisions.
432
    def test_fetch_revisions_with_deltas_into_pack(self):
433
        # See BUG #261339, dev versions of bzr could accidentally create deltas
434
        # in revision texts in knit branches (when fetching from packs). So we
435
        # ensure that *if* a knit repository has a delta in revisions, that it
436
        # gets properly expanded back into a fulltext when stored in the pack
437
        # file.
438
        tree = self.make_branch_and_tree('source', format='dirstate')
439
        target = self.make_repository('target', format='pack-0.92')
440
        self.build_tree(['source/file'])
441
        tree.set_root_id('root-id')
442
        tree.add('file', 'file-id')
443
        tree.commit('one', rev_id='rev-one')
444
        # Hack the KVF for revisions so that it "accidentally" allows a delta
445
        tree.branch.repository.revisions._max_delta_chain = 200
446
        tree.commit('two', rev_id='rev-two')
447
        source = tree.branch.repository
448
        # Ensure that we stored a delta
449
        source.lock_read()
450
        self.addCleanup(source.unlock)
451
        record = source.revisions.get_record_stream([('rev-two',)],
452
            'unordered', False).next()
453
        self.assertEqual('knit-delta-gz', record.storage_kind)
454
        target.fetch(tree.branch.repository, revision_id='rev-two')
455
        # The record should get expanded back to a fulltext
456
        target.lock_read()
457
        self.addCleanup(target.unlock)
458
        record = target.revisions.get_record_stream([('rev-two',)],
459
            'unordered', False).next()
460
        self.assertEqual('knit-ft-gz', record.storage_kind)
461
3871.4.2 by John Arbash Meinel
Finally a test case that reproduces bug #304841
462
    def test_fetch_with_fallback_and_merge(self):
463
        builder = self.make_branch_builder('source', format='pack-0.92')
464
        builder.start_series()
465
        # graph
466
        #   A
467
        #   |\
468
        #   B C
469
        #   | |
470
        #   | D
471
        #   | |
472
        #   | E
473
        #    \|
474
        #     F
475
        # A & B are present in the base (stacked-on) repository, A-E are
476
        # present in the source.
3871.4.4 by John Arbash Meinel
Another fix for bug #304841. As a broad-spectrum solution,
477
        # This reproduces bug #304841
3871.4.2 by John Arbash Meinel
Finally a test case that reproduces bug #304841
478
        # We need a large enough inventory that total size of compressed deltas
479
        # is shorter than the size of a compressed fulltext. We have to use
480
        # random ids because otherwise the inventory fulltext compresses too
481
        # well and the deltas get bigger.
482
        to_add = [
483
            ('add', ('', 'TREE_ROOT', 'directory', None))]
484
        for i in xrange(10):
485
            fname = 'file%03d' % (i,)
486
            fileid = '%s-%s' % (fname, osutils.rand_chars(64))
487
            to_add.append(('add', (fname, fileid, 'file', 'content\n')))
488
        builder.build_snapshot('A', None, to_add)
489
        builder.build_snapshot('B', ['A'], [])
490
        builder.build_snapshot('C', ['A'], [])
491
        builder.build_snapshot('D', ['C'], [])
492
        builder.build_snapshot('E', ['D'], [])
493
        builder.build_snapshot('F', ['E', 'B'], [])
494
        builder.finish_series()
495
        source_branch = builder.get_branch()
496
        source_branch.bzrdir.sprout('base', revision_id='B')
497
        target_branch = self.make_branch('target', format='1.6')
498
        target_branch.set_stacked_on_url('../base')
499
        source = source_branch.repository
500
        source.lock_read()
501
        self.addCleanup(source.unlock)
502
        source.inventories = versionedfile.OrderingVersionedFilesDecorator(
503
                        source.inventories,
504
                        key_priority={('E',): 1, ('D',): 2, ('C',): 4,
505
                                      ('F',): 3})
506
        # Ensure that the content is yielded in the proper order, and given as
507
        # the expected kinds
508
        records = [(record.key, record.storage_kind)
509
                   for record in source.inventories.get_record_stream(
510
                        [('D',), ('C',), ('E',), ('F',)], 'unordered', False)]
511
        self.assertEqual([(('E',), 'knit-delta-gz'), (('D',), 'knit-delta-gz'),
512
                          (('F',), 'knit-delta-gz'), (('C',), 'knit-delta-gz')],
513
                          records)
514
515
        target_branch.lock_write()
516
        self.addCleanup(target_branch.unlock)
517
        target = target_branch.repository
518
        target.fetch(source, revision_id='F')
519
        # 'C' should be expanded to a fulltext, but D and E should still be
520
        # deltas
521
        stream = target.inventories.get_record_stream(
522
            [('C',), ('D',), ('E',), ('F',)],
523
            'unordered', False)
524
        kinds = dict((record.key, record.storage_kind) for record in stream)
525
        self.assertEqual({('C',): 'knit-ft-gz', ('D',): 'knit-delta-gz',
526
                          ('E',): 'knit-delta-gz', ('F',): 'knit-delta-gz'},
527
                         kinds)
3849.3.1 by John Arbash Meinel
Part of bug #300289, stop requiring plain fulltexts for revisions.
528
3606.7.7 by John Arbash Meinel
Add tests for the fetching behavior.
529
3380.1.1 by Aaron Bentley
Fix inventory insertion to work in topological order
530
class Test1To2Fetch(TestCaseWithTransport):
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
531
    """Tests for Model1To2 failure modes"""
3380.1.1 by Aaron Bentley
Fix inventory insertion to work in topological order
532
3380.2.4 by Aaron Bentley
Updates from review
533
    def make_tree_and_repo(self):
534
        self.tree = self.make_branch_and_tree('tree', format='pack-0.92')
535
        self.repo = self.make_repository('rich-repo', format='rich-root-pack')
536
        self.repo.lock_write()
537
        self.addCleanup(self.repo.unlock)
538
539
    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
540
        """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
541
542
        This test depends on the order of items in a set, which is
543
        implementation-dependant, so we test A, B and then B, A.
544
        """
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
545
        self.make_tree_and_repo()
546
        self.tree.commit('Commit 1', rev_id=first)
547
        self.tree.commit('Commit 2', rev_id=second)
548
        self.repo.fetch(self.tree.branch.repository, second)
549
3380.2.4 by Aaron Bentley
Updates from review
550
    def test_fetch_order_AB(self):
3380.2.7 by Aaron Bentley
Update docs
551
        """See do_fetch_order_test"""
3380.2.4 by Aaron Bentley
Updates from review
552
        self.do_fetch_order_test('A', 'B')
553
554
    def test_fetch_order_BA(self):
3380.2.7 by Aaron Bentley
Update docs
555
        """See do_fetch_order_test"""
3380.2.4 by Aaron Bentley
Updates from review
556
        self.do_fetch_order_test('B', 'A')
557
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
558
    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.
559
        self.repo.lock_read()
560
        try:
561
            parent_map = self.repo.texts.get_parent_map([(file_id, revision_id)])
562
            return parent_map[(file_id, revision_id)]
563
        finally:
564
            self.repo.unlock()
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
565
3380.1.2 by Aaron Bentley
Improve handling ghosts and changing root_ids
566
    def test_fetch_ghosts(self):
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
567
        self.make_tree_and_repo()
568
        self.tree.commit('first commit', rev_id='left-parent')
569
        self.tree.add_parent_tree_id('ghost-parent')
570
        fork = self.tree.bzrdir.sprout('fork', 'null:').open_workingtree()
3380.1.2 by Aaron Bentley
Improve handling ghosts and changing root_ids
571
        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
572
        self.tree.branch.repository.fetch(fork.branch.repository,
3380.1.2 by Aaron Bentley
Improve handling ghosts and changing root_ids
573
                                     'not-ghost-parent')
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
574
        self.tree.add_parent_tree_id('not-ghost-parent')
575
        self.tree.commit('second commit', rev_id='second-id')
576
        self.repo.fetch(self.tree.branch.repository, 'second-id')
577
        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.
578
        self.assertEqual(
579
            ((root_id, 'left-parent'), (root_id, 'ghost-parent'),
580
             (root_id, 'not-ghost-parent')),
581
            self.get_parents(root_id, 'second-id'))
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
582
583
    def make_two_commits(self, change_root, fetch_twice):
584
        self.make_tree_and_repo()
585
        self.tree.commit('first commit', rev_id='first-id')
586
        if change_root:
587
            self.tree.set_root_id('unique-id')
588
        self.tree.commit('second commit', rev_id='second-id')
589
        if fetch_twice:
590
            self.repo.fetch(self.tree.branch.repository, 'first-id')
591
        self.repo.fetch(self.tree.branch.repository, 'second-id')
3380.1.2 by Aaron Bentley
Improve handling ghosts and changing root_ids
592
593
    def test_fetch_changed_root(self):
3380.1.3 by Aaron Bentley
Fix model-change fetching with ghosts and when fetch is resumed
594
        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.
595
        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
596
597
    def test_two_fetch_changed_root(self):
598
        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.
599
        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
600
601
    def test_two_fetches(self):
602
        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.
603
        self.assertEqual((('TREE_ROOT', 'first-id'),),
604
            self.get_parents('TREE_ROOT', 'second-id'))