~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_fetch.py

  • Committer: John Arbash Meinel
  • Date: 2008-05-28 23:20:33 UTC
  • mto: This revision was merged to the branch mainline in revision 3458.
  • Revision ID: john@arbash-meinel.com-20080528232033-cx3l3yg845udklps
Bring back always in the form of 'override'.
Change the functions so that they are compatible with the released
definition, and just allow callers to supply override=False
if they want the new behavior.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2007 Canonical Ltd
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
import os
 
18
import re
18
19
import sys
19
20
 
 
21
import bzrlib
 
22
from bzrlib import (
 
23
    bzrdir,
 
24
    errors,
 
25
    merge,
 
26
    repository,
 
27
    )
20
28
from bzrlib.branch import Branch
21
29
from bzrlib.bzrdir import BzrDir
22
 
from bzrlib.builtins import merge
23
 
import bzrlib.errors
 
30
from bzrlib.repofmt import knitrepo
24
31
from bzrlib.tests import TestCaseWithTransport
25
 
from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver
 
32
from bzrlib.tests.http_utils import TestCaseWithWebserver
26
33
from bzrlib.tests.test_revision import make_branches
27
34
from bzrlib.trace import mutter
 
35
from bzrlib.upgrade import Convert
28
36
from bzrlib.workingtree import WorkingTree
29
37
 
 
38
# These tests are a bit old; please instead add new tests into
 
39
# interrepository_implementations/ so they'll run on all relevant
 
40
# combinations.
 
41
 
30
42
 
31
43
def has_revision(branch, revision_id):
32
44
    return branch.repository.has_revision(revision_id)
86
98
    self.assertEquals(fetched, 3, "fetched %d instead of 3" % fetched)
87
99
    # InstallFailed should be raised if the branch is missing the revision
88
100
    # 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)
 
101
    self.assertRaises(errors.InstallFailed, br_a3.fetch, br_a2, 'pizza')
94
102
 
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
 
103
    # TODO: Test trying to fetch from a branch that points to a revision not
 
104
    # actually present in its repository.  Not every branch format allows you
 
105
    # to directly point to such revisions, so it's a bit complicated to
 
106
    # construct.  One way would be to uncommit and gc the revision, but not
 
107
    # every branch supports that.  -- mbp 20070814
99
108
 
100
109
    #TODO: test that fetch correctly does reweaving when needed. RBC 20051008
101
110
    # Note that this means - updating the weave when ghosts are filled in to 
106
115
 
107
116
    def test_fetch(self):
108
117
        #highest indices a: 5, b: 7
109
 
        br_a, br_b = make_branches(self)
 
118
        br_a, br_b = make_branches(self, format='dirstate-tags')
110
119
        fetch_steps(self, br_a, br_b, br_a)
111
120
 
112
121
    def test_fetch_self(self):
113
122
        wt = self.make_branch_and_tree('br')
114
123
        self.assertEqual(wt.branch.fetch(wt.branch), (0, []))
115
124
 
 
125
    def test_fetch_root_knit(self):
 
126
        """Ensure that knit2.fetch() updates the root knit
 
127
        
 
128
        This tests the case where the root has a new revision, but there are no
 
129
        corresponding filename, parent, contents or other changes.
 
130
        """
 
131
        knit1_format = bzrdir.BzrDirMetaFormat1()
 
132
        knit1_format.repository_format = knitrepo.RepositoryFormatKnit1()
 
133
        knit2_format = bzrdir.BzrDirMetaFormat1()
 
134
        knit2_format.repository_format = knitrepo.RepositoryFormatKnit3()
 
135
        # we start with a knit1 repository because that causes the
 
136
        # root revision to change for each commit, even though the content,
 
137
        # parent, name, and other attributes are unchanged.
 
138
        tree = self.make_branch_and_tree('tree', knit1_format)
 
139
        tree.set_root_id('tree-root')
 
140
        tree.commit('rev1', rev_id='rev1')
 
141
        tree.commit('rev2', rev_id='rev2')
 
142
 
 
143
        # Now we convert it to a knit2 repository so that it has a root knit
 
144
        Convert(tree.basedir, knit2_format)
 
145
        tree = WorkingTree.open(tree.basedir)
 
146
        branch = self.make_branch('branch', format=knit2_format)
 
147
        branch.pull(tree.branch, stop_revision='rev1')
 
148
        repo = branch.repository
 
149
        root_knit = repo.weave_store.get_weave('tree-root',
 
150
                                                repo.get_transaction())
 
151
        # Make sure fetch retrieved only what we requested
 
152
        self.assertTrue('rev1' in root_knit)
 
153
        self.assertTrue('rev2' not in root_knit)
 
154
        branch.pull(tree.branch)
 
155
        root_knit = repo.weave_store.get_weave('tree-root',
 
156
                                                repo.get_transaction())
 
157
        # Make sure that the next revision in the root knit was retrieved,
 
158
        # even though the text, name, parent_id, etc., were unchanged.
 
159
        self.assertTrue('rev2' in root_knit)
 
160
 
 
161
    def test_fetch_incompatible(self):
 
162
        knit_tree = self.make_branch_and_tree('knit', format='knit')
 
163
        knit3_tree = self.make_branch_and_tree('knit3',
 
164
            format='dirstate-with-subtree')
 
165
        knit3_tree.commit('blah')
 
166
        self.assertRaises(errors.IncompatibleRepositories,
 
167
                          knit_tree.branch.fetch, knit3_tree.branch)
 
168
 
116
169
 
117
170
class TestMergeFetch(TestCaseWithTransport):
118
171
 
125
178
        wt2 = self.make_branch_and_tree('br2')
126
179
        br2 = wt2.branch
127
180
        wt2.commit(message='rev 2-1', rev_id='2-1')
128
 
        merge(other_revision=['br1', -1], base_revision=['br1', 0],
129
 
              this_dir='br2')
 
181
        wt2.merge_from_branch(br1, from_revision='null:')
130
182
        self._check_revs_present(br2)
131
183
 
132
184
    def test_merge_fetches(self):
137
189
        dir_2 = br1.bzrdir.sprout('br2')
138
190
        br2 = dir_2.open_branch()
139
191
        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')
 
192
        wt2 = dir_2.open_workingtree()
 
193
        wt2.commit(message='rev 2-1', rev_id='2-1')
 
194
        wt2.merge_from_branch(br1)
143
195
        self._check_revs_present(br2)
144
196
 
145
197
    def _check_revs_present(self, br2):
174
226
    def test_merge_fetches_file_history(self):
175
227
        """Merge brings across file histories"""
176
228
        br2 = Branch.open('br2')
177
 
        merge(other_revision=['br1', -1], base_revision=[None, None], 
178
 
              this_dir='br2')
 
229
        br1 = Branch.open('br1')
 
230
        wt2 = WorkingTree.open('br2').merge_from_branch(br1)
 
231
        br2.lock_read()
 
232
        self.addCleanup(br2.unlock)
179
233
        for rev_id, text in [('1-2', 'original from 1\n'),
180
234
                             ('1-3', 'agreement\n'),
181
235
                             ('2-1', 'contents in 2\n'),
198
252
 
199
253
    def _count_log_matches(self, target, logs):
200
254
        """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__)
 
255
        get_succeeds_re = re.compile(
 
256
            '.*"GET .*%s HTTP/1.1" 20[06] - "-" "bzr/%s' %
 
257
            (     target,                    bzrlib.__version__))
203
258
        c = 0
204
259
        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:
 
260
            if get_succeeds_re.match(line):
208
261
                c += 1
209
262
        return c
210
263
 
211
264
    def test_weaves_are_retrieved_once(self):
212
265
        self.build_tree(("source/", "source/file", "target/"))
213
 
        wt = self.make_branch_and_tree('source')
 
266
        # This test depends on knit dasta storage.
 
267
        wt = self.make_branch_and_tree('source', format='dirstate-tags')
214
268
        branch = wt.branch
215
269
        wt.add(["file"], ["id"])
216
270
        wt.commit("added file")
217
 
        print >>open("source/file", 'w'), "blah"
 
271
        open("source/file", 'w').write("blah\n")
218
272
        wt.commit("changed file")
219
273
        target = BzrDir.create_branch_and_repo("target/")
220
274
        source = Branch.open(self.get_readonly_url("source/"))
221
275
        self.assertEqual(target.fetch(source), (2, []))
222
 
        log_pattern = '%%s HTTP/1.1" 200 - "-" "bzr/%s' % bzrlib.__version__
223
276
        # this is the path to the literal file. As format changes 
224
277
        # occur it needs to be updated. FIXME: ask the store for the
225
278
        # path.
229
282
        # unfortunately this log entry is branch format specific. We could 
230
283
        # factor out the 'what files does this format use' to a method on the 
231
284
        # repository, which would let us to this generically. RBC 20060419
 
285
        # RBC 20080408: Or perhaps we can assert that no files are fully read
 
286
        # twice?
232
287
        self.assertEqual(1, self._count_log_matches('/ce/id.kndx', http_logs))
233
288
        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))
 
289
        # XXX: This *should* be '1', but more intrusive fetch changes are
 
290
        # needed to drop this back to 1.
 
291
        self.assertEqual(2, self._count_log_matches('inventory.kndx', http_logs))
236
292
        # this r-h check test will prevent regressions, but it currently already 
237
293
        # passes, before the patch to cache-rh is applied :[
238
 
        self.assertEqual(1, self._count_log_matches('revision-history', http_logs))
 
294
        self.assertTrue(1 >= self._count_log_matches('revision-history',
 
295
                                                     http_logs))
 
296
        self.assertTrue(1 >= self._count_log_matches('last-revision',
 
297
                                                     http_logs))
239
298
        # FIXME naughty poking in there.
240
299
        self.get_readonly_server().logs = []
241
 
        # check there is nothing more to fetch
242
 
        source = Branch.open(self.get_readonly_url("source/"))
 
300
        # check there is nothing more to fetch.  We take care to re-use the
 
301
        # existing transport so that the request logs we're about to examine
 
302
        # aren't cluttered with redundant probes for a smart server.
 
303
        # XXX: Perhaps this further parameterisation: test http with smart
 
304
        # server, and test http without smart server?
 
305
        source = Branch.open(
 
306
            self.get_readonly_url("source/"),
 
307
            possible_transports=[source.bzrdir.root_transport])
243
308
        self.assertEqual(target.fetch(source), (0, []))
244
309
        # should make just two requests
245
310
        http_logs = self.get_readonly_server().logs
247
312
        self.log('\n'.join(http_logs))
248
313
        self.assertEqual(1, self._count_log_matches('branch-format', http_logs))
249
314
        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))
 
315
        self.assertEqual(1, self._count_log_matches('repository/format',
 
316
            http_logs))
 
317
        self.assertTrue(1 >= self._count_log_matches('revision-history',
 
318
                                                     http_logs))
 
319
        self.assertTrue(1 >= self._count_log_matches('last-revision',
 
320
                                                     http_logs))
252
321
        self.assertEqual(4, len(http_logs))
 
322
 
 
323
 
 
324
class Test1To2Fetch(TestCaseWithTransport):
 
325
    """Tests for Model1To2 failure modes"""
 
326
 
 
327
    def make_tree_and_repo(self):
 
328
        self.tree = self.make_branch_and_tree('tree', format='pack-0.92')
 
329
        self.repo = self.make_repository('rich-repo', format='rich-root-pack')
 
330
        self.repo.lock_write()
 
331
        self.addCleanup(self.repo.unlock)
 
332
 
 
333
    def do_fetch_order_test(self, first, second):
 
334
        """Test that fetch works no matter what the set order of revision is.
 
335
 
 
336
        This test depends on the order of items in a set, which is
 
337
        implementation-dependant, so we test A, B and then B, A.
 
338
        """
 
339
        self.make_tree_and_repo()
 
340
        self.tree.commit('Commit 1', rev_id=first)
 
341
        self.tree.commit('Commit 2', rev_id=second)
 
342
        self.repo.fetch(self.tree.branch.repository, second)
 
343
 
 
344
    def test_fetch_order_AB(self):
 
345
        """See do_fetch_order_test"""
 
346
        self.do_fetch_order_test('A', 'B')
 
347
 
 
348
    def test_fetch_order_BA(self):
 
349
        """See do_fetch_order_test"""
 
350
        self.do_fetch_order_test('B', 'A')
 
351
 
 
352
    def get_parents(self, file_id, revision_id):
 
353
        transaction = self.repo.get_transaction()
 
354
        vf = self.repo.weave_store.get_weave(file_id, transaction)
 
355
        return vf.get_parents_with_ghosts(revision_id)
 
356
 
 
357
    def test_fetch_ghosts(self):
 
358
        self.make_tree_and_repo()
 
359
        self.tree.commit('first commit', rev_id='left-parent')
 
360
        self.tree.add_parent_tree_id('ghost-parent')
 
361
        fork = self.tree.bzrdir.sprout('fork', 'null:').open_workingtree()
 
362
        fork.commit('not a ghost', rev_id='not-ghost-parent')
 
363
        self.tree.branch.repository.fetch(fork.branch.repository,
 
364
                                     'not-ghost-parent')
 
365
        self.tree.add_parent_tree_id('not-ghost-parent')
 
366
        self.tree.commit('second commit', rev_id='second-id')
 
367
        self.repo.fetch(self.tree.branch.repository, 'second-id')
 
368
        root_id = self.tree.get_root_id()
 
369
        self.assertEqual(['left-parent', 'ghost-parent', 'not-ghost-parent'],
 
370
                         self.get_parents(root_id, 'second-id'))
 
371
 
 
372
    def make_two_commits(self, change_root, fetch_twice):
 
373
        self.make_tree_and_repo()
 
374
        self.tree.commit('first commit', rev_id='first-id')
 
375
        if change_root:
 
376
            self.tree.set_root_id('unique-id')
 
377
        self.tree.commit('second commit', rev_id='second-id')
 
378
        if fetch_twice:
 
379
            self.repo.fetch(self.tree.branch.repository, 'first-id')
 
380
        self.repo.fetch(self.tree.branch.repository, 'second-id')
 
381
 
 
382
    def test_fetch_changed_root(self):
 
383
        self.make_two_commits(change_root=True, fetch_twice=False)
 
384
        self.assertEqual([], self.get_parents('unique-id', 'second-id'))
 
385
 
 
386
    def test_two_fetch_changed_root(self):
 
387
        self.make_two_commits(change_root=True, fetch_twice=True)
 
388
        self.assertEqual([], self.get_parents('unique-id', 'second-id'))
 
389
 
 
390
    def test_two_fetches(self):
 
391
        self.make_two_commits(change_root=False, fetch_twice=True)
 
392
        self.assertEqual(['first-id'],
 
393
                         self.get_parents('TREE_ROOT', 'second-id'))