~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_fetch.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-06-21 12:55:50 UTC
  • mfrom: (1800.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060621125550-9c0676b834e80815
(robertc)Merge Branch.generate_revision_history() helper routine to create new revision histories.

Show diffs side-by-side

added added

removed removed

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