/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_fetch.py

  • Committer: Martin Pool
  • Date: 2007-02-06 08:16:13 UTC
  • mto: This revision was merged to the branch mainline in revision 2283.
  • Revision ID: mbp@sourcefrog.net-20070206081613-dxop566k13bll6j0
Move KnitFormat2 into repofmt

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
import os
 
18
import re
 
19
import sys
 
20
 
 
21
from bzrlib import bzrdir, repository
 
22
from bzrlib.branch import Branch
 
23
from bzrlib.bzrdir import BzrDir
 
24
from bzrlib.builtins import merge
 
25
import bzrlib.errors
 
26
from bzrlib.repofmt import knitrepo
 
27
from bzrlib.tests import TestCaseWithTransport
 
28
from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver
 
29
from bzrlib.tests.test_revision import make_branches
 
30
from bzrlib.trace import mutter
 
31
from bzrlib.upgrade import Convert
 
32
from bzrlib.workingtree import WorkingTree
 
33
 
 
34
 
 
35
def has_revision(branch, revision_id):
 
36
    return branch.repository.has_revision(revision_id)
 
37
 
 
38
def fetch_steps(self, br_a, br_b, writable_a):
 
39
    """A foreign test method for testing fetch locally and remotely."""
 
40
     
 
41
    # TODO RBC 20060201 make this a repository test.
 
42
    repo_b = br_b.repository
 
43
    self.assertFalse(repo_b.has_revision(br_a.revision_history()[3]))
 
44
    self.assertTrue(repo_b.has_revision(br_a.revision_history()[2]))
 
45
    self.assertEquals(len(br_b.revision_history()), 7)
 
46
    self.assertEquals(br_b.fetch(br_a, br_a.revision_history()[2])[0], 0)
 
47
    # branch.fetch is not supposed to alter the revision history
 
48
    self.assertEquals(len(br_b.revision_history()), 7)
 
49
    self.assertFalse(repo_b.has_revision(br_a.revision_history()[3]))
 
50
 
 
51
    # fetching the next revision up in sample data copies one revision
 
52
    self.assertEquals(br_b.fetch(br_a, br_a.revision_history()[3])[0], 1)
 
53
    self.assertTrue(repo_b.has_revision(br_a.revision_history()[3]))
 
54
    self.assertFalse(has_revision(br_a, br_b.revision_history()[6]))
 
55
    self.assertTrue(br_a.repository.has_revision(br_b.revision_history()[5]))
 
56
 
 
57
    # When a non-branch ancestor is missing, it should be unlisted...
 
58
    # as its not reference from the inventory weave.
 
59
    br_b4 = self.make_branch('br_4')
 
60
    count, failures = br_b4.fetch(br_b)
 
61
    self.assertEqual(count, 7)
 
62
    self.assertEqual(failures, [])
 
63
 
 
64
    self.assertEqual(writable_a.fetch(br_b)[0], 1)
 
65
    self.assertTrue(has_revision(br_a, br_b.revision_history()[3]))
 
66
    self.assertTrue(has_revision(br_a, br_b.revision_history()[4]))
 
67
        
 
68
    br_b2 = self.make_branch('br_b2')
 
69
    self.assertEquals(br_b2.fetch(br_b)[0], 7)
 
70
    self.assertTrue(has_revision(br_b2, br_b.revision_history()[4]))
 
71
    self.assertTrue(has_revision(br_b2, br_a.revision_history()[2]))
 
72
    self.assertFalse(has_revision(br_b2, br_a.revision_history()[3]))
 
73
 
 
74
    br_a2 = self.make_branch('br_a2')
 
75
    self.assertEquals(br_a2.fetch(br_a)[0], 9)
 
76
    self.assertTrue(has_revision(br_a2, br_b.revision_history()[4]))
 
77
    self.assertTrue(has_revision(br_a2, br_a.revision_history()[3]))
 
78
    self.assertTrue(has_revision(br_a2, br_a.revision_history()[2]))
 
79
 
 
80
    br_a3 = self.make_branch('br_a3')
 
81
    # pulling a branch with no revisions grabs nothing, regardless of 
 
82
    # whats in the inventory.
 
83
    self.assertEquals(br_a3.fetch(br_a2)[0], 0)
 
84
    for revno in range(4):
 
85
        self.assertFalse(
 
86
            br_a3.repository.has_revision(br_a.revision_history()[revno]))
 
87
    self.assertEqual(br_a3.fetch(br_a2, br_a.revision_history()[2])[0], 3)
 
88
    # pull the 3 revisions introduced by a@u-0-3
 
89
    fetched = br_a3.fetch(br_a2, br_a.revision_history()[3])[0]
 
90
    self.assertEquals(fetched, 3, "fetched %d instead of 3" % fetched)
 
91
    # InstallFailed should be raised if the branch is missing the revision
 
92
    # that was requested.
 
93
    self.assertRaises(bzrlib.errors.InstallFailed, br_a3.fetch, br_a2, 'pizza')
 
94
    # InstallFailed should be raised if the branch is missing a revision
 
95
    # from its own revision history
 
96
    br_a2.append_revision('a-b-c')
 
97
    self.assertRaises(bzrlib.errors.InstallFailed, br_a3.fetch, br_a2)
 
98
 
 
99
    # TODO: jam 20051218 Branch should no longer allow append_revision for revisions
 
100
    #       which don't exist. So this test needs to be rewritten
 
101
    #       RBC 20060403 the way to do this is to uncommit the revision from the
 
102
    #           repository after the commit
 
103
 
 
104
    #TODO: test that fetch correctly does reweaving when needed. RBC 20051008
 
105
    # Note that this means - updating the weave when ghosts are filled in to 
 
106
    # add the right parents.
 
107
 
 
108
 
 
109
class TestFetch(TestCaseWithTransport):
 
110
 
 
111
    def test_fetch(self):
 
112
        #highest indices a: 5, b: 7
 
113
        br_a, br_b = make_branches(self)
 
114
        fetch_steps(self, br_a, br_b, br_a)
 
115
 
 
116
    def test_fetch_self(self):
 
117
        wt = self.make_branch_and_tree('br')
 
118
        self.assertEqual(wt.branch.fetch(wt.branch), (0, []))
 
119
 
 
120
    def test_fetch_root_knit(self):
 
121
        """Ensure that knit2.fetch() updates the root knit
 
122
        
 
123
        This tests the case where the root has a new revision, but there are no
 
124
        corresponding filename, parent, contents or other changes.
 
125
        """
 
126
        knit1_format = bzrdir.BzrDirMetaFormat1()
 
127
        knit1_format.repository_format = repository.RepositoryFormatKnit1()
 
128
        knit2_format = bzrdir.BzrDirMetaFormat1()
 
129
        knit2_format.repository_format = knitrepo.RepositoryFormatKnit2()
 
130
        # we start with a knit1 repository because that causes the
 
131
        # root revision to change for each commit, even though the content,
 
132
        # parent, name, and other attributes are unchanged.
 
133
        tree = self.make_branch_and_tree('tree', knit1_format)
 
134
        tree.set_root_id('tree-root')
 
135
        tree.commit('rev1', rev_id='rev1')
 
136
        tree.commit('rev2', rev_id='rev2')
 
137
 
 
138
        # Now we convert it to a knit2 repository so that it has a root knit
 
139
        Convert(tree.basedir, knit2_format)
 
140
        tree = WorkingTree.open(tree.basedir)
 
141
        branch = self.make_branch('branch', format=knit2_format)
 
142
        branch.pull(tree.branch, stop_revision='rev1')
 
143
        repo = branch.repository
 
144
        root_knit = repo.weave_store.get_weave('tree-root',
 
145
                                                repo.get_transaction())
 
146
        # Make sure fetch retrieved only what we requested
 
147
        self.assertTrue('rev1' in root_knit)
 
148
        self.assertTrue('rev2' not in root_knit)
 
149
        branch.pull(tree.branch)
 
150
        root_knit = repo.weave_store.get_weave('tree-root',
 
151
                                                repo.get_transaction())
 
152
        # Make sure that the next revision in the root knit was retrieved,
 
153
        # even though the text, name, parent_id, etc., were unchanged.
 
154
        self.assertTrue('rev2' in root_knit)
 
155
 
 
156
 
 
157
class TestMergeFetch(TestCaseWithTransport):
 
158
 
 
159
    def test_merge_fetches_unrelated(self):
 
160
        """Merge brings across history from unrelated source"""
 
161
        wt1 = self.make_branch_and_tree('br1')
 
162
        br1 = wt1.branch
 
163
        wt1.commit(message='rev 1-1', rev_id='1-1')
 
164
        wt1.commit(message='rev 1-2', rev_id='1-2')
 
165
        wt2 = self.make_branch_and_tree('br2')
 
166
        br2 = wt2.branch
 
167
        wt2.commit(message='rev 2-1', rev_id='2-1')
 
168
        merge(other_revision=['br1', -1], base_revision=['br1', 0],
 
169
              this_dir='br2')
 
170
        self._check_revs_present(br2)
 
171
 
 
172
    def test_merge_fetches(self):
 
173
        """Merge brings across history from source"""
 
174
        wt1 = self.make_branch_and_tree('br1')
 
175
        br1 = wt1.branch
 
176
        wt1.commit(message='rev 1-1', rev_id='1-1')
 
177
        dir_2 = br1.bzrdir.sprout('br2')
 
178
        br2 = dir_2.open_branch()
 
179
        wt1.commit(message='rev 1-2', rev_id='1-2')
 
180
        dir_2.open_workingtree().commit(message='rev 2-1', rev_id='2-1')
 
181
        merge(other_revision=['br1', -1], base_revision=[None, None], 
 
182
              this_dir='br2')
 
183
        self._check_revs_present(br2)
 
184
 
 
185
    def _check_revs_present(self, br2):
 
186
        for rev_id in '1-1', '1-2', '2-1':
 
187
            self.assertTrue(br2.repository.has_revision(rev_id))
 
188
            rev = br2.repository.get_revision(rev_id)
 
189
            self.assertEqual(rev.revision_id, rev_id)
 
190
            self.assertTrue(br2.repository.get_inventory(rev_id))
 
191
 
 
192
 
 
193
class TestMergeFileHistory(TestCaseWithTransport):
 
194
 
 
195
    def setUp(self):
 
196
        super(TestMergeFileHistory, self).setUp()
 
197
        wt1 = self.make_branch_and_tree('br1')
 
198
        br1 = wt1.branch
 
199
        self.build_tree_contents([('br1/file', 'original contents\n')])
 
200
        wt1.add('file', 'this-file-id')
 
201
        wt1.commit(message='rev 1-1', rev_id='1-1')
 
202
        dir_2 = br1.bzrdir.sprout('br2')
 
203
        br2 = dir_2.open_branch()
 
204
        wt2 = dir_2.open_workingtree()
 
205
        self.build_tree_contents([('br1/file', 'original from 1\n')])
 
206
        wt1.commit(message='rev 1-2', rev_id='1-2')
 
207
        self.build_tree_contents([('br1/file', 'agreement\n')])
 
208
        wt1.commit(message='rev 1-3', rev_id='1-3')
 
209
        self.build_tree_contents([('br2/file', 'contents in 2\n')])
 
210
        wt2.commit(message='rev 2-1', rev_id='2-1')
 
211
        self.build_tree_contents([('br2/file', 'agreement\n')])
 
212
        wt2.commit(message='rev 2-2', rev_id='2-2')
 
213
 
 
214
    def test_merge_fetches_file_history(self):
 
215
        """Merge brings across file histories"""
 
216
        br2 = Branch.open('br2')
 
217
        merge(other_revision=['br1', -1], base_revision=[None, None], 
 
218
              this_dir='br2')
 
219
        for rev_id, text in [('1-2', 'original from 1\n'),
 
220
                             ('1-3', 'agreement\n'),
 
221
                             ('2-1', 'contents in 2\n'),
 
222
                             ('2-2', 'agreement\n')]:
 
223
            self.assertEqualDiff(
 
224
                br2.repository.revision_tree(
 
225
                    rev_id).get_file_text('this-file-id'), text)
 
226
 
 
227
 
 
228
class TestHttpFetch(TestCaseWithWebserver):
 
229
    # FIXME RBC 20060124 this really isn't web specific, perhaps an
 
230
    # instrumented readonly transport? Can we do an instrumented
 
231
    # adapter and use self.get_readonly_url ?
 
232
 
 
233
    def test_fetch(self):
 
234
        #highest indices a: 5, b: 7
 
235
        br_a, br_b = make_branches(self)
 
236
        br_rem_a = Branch.open(self.get_readonly_url('branch1'))
 
237
        fetch_steps(self, br_rem_a, br_b, br_a)
 
238
 
 
239
    def _count_log_matches(self, target, logs):
 
240
        """Count the number of times the target file pattern was fetched in an http log"""
 
241
        get_succeeds_re = re.compile(
 
242
            '.*"GET .*%s HTTP/1.1" 20[06] - "-" "bzr/%s' %
 
243
            (     target,                    bzrlib.__version__))
 
244
        c = 0
 
245
        for line in logs:
 
246
            if get_succeeds_re.match(line):
 
247
                c += 1
 
248
        return c
 
249
 
 
250
    def test_weaves_are_retrieved_once(self):
 
251
        self.build_tree(("source/", "source/file", "target/"))
 
252
        wt = self.make_branch_and_tree('source')
 
253
        branch = wt.branch
 
254
        wt.add(["file"], ["id"])
 
255
        wt.commit("added file")
 
256
        print >>open("source/file", 'w'), "blah"
 
257
        wt.commit("changed file")
 
258
        target = BzrDir.create_branch_and_repo("target/")
 
259
        source = Branch.open(self.get_readonly_url("source/"))
 
260
        self.assertEqual(target.fetch(source), (2, []))
 
261
        # this is the path to the literal file. As format changes 
 
262
        # occur it needs to be updated. FIXME: ask the store for the
 
263
        # path.
 
264
        self.log("web server logs are:")
 
265
        http_logs = self.get_readonly_server().logs
 
266
        self.log('\n'.join(http_logs))
 
267
        # unfortunately this log entry is branch format specific. We could 
 
268
        # factor out the 'what files does this format use' to a method on the 
 
269
        # repository, which would let us to this generically. RBC 20060419
 
270
        self.assertEqual(1, self._count_log_matches('/ce/id.kndx', http_logs))
 
271
        self.assertEqual(1, self._count_log_matches('/ce/id.knit', http_logs))
 
272
        self.assertEqual(1, self._count_log_matches('inventory.kndx', http_logs))
 
273
        # this r-h check test will prevent regressions, but it currently already 
 
274
        # passes, before the patch to cache-rh is applied :[
 
275
        self.assertEqual(1, self._count_log_matches('revision-history', http_logs))
 
276
        # FIXME naughty poking in there.
 
277
        self.get_readonly_server().logs = []
 
278
        # check there is nothing more to fetch
 
279
        source = Branch.open(self.get_readonly_url("source/"))
 
280
        self.assertEqual(target.fetch(source), (0, []))
 
281
        # should make just two requests
 
282
        http_logs = self.get_readonly_server().logs
 
283
        self.log("web server logs are:")
 
284
        self.log('\n'.join(http_logs))
 
285
        self.assertEqual(1, self._count_log_matches('branch-format', http_logs))
 
286
        self.assertEqual(1, self._count_log_matches('branch/format', http_logs))
 
287
        self.assertEqual(1, self._count_log_matches('repository/format', http_logs))
 
288
        self.assertEqual(1, self._count_log_matches('revision-history', http_logs))
 
289
        self.assertEqual(4, len(http_logs))