~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_fetch.py

  • Committer: Martin Pool
  • Date: 2005-06-27 08:18:07 UTC
  • mto: This revision was merged to the branch mainline in revision 852.
  • Revision ID: mbp@sourcefrog.net-20050627081807-dc3ff5726c88b247
More tests for insertion of lines in new versions.

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