/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

First attempt to merge .dev and resolve the conflicts (but tests are 
failing)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
 
1
# Copyright (C) 2005, 2007 Canonical Ltd
2
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
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
        repo.lock_read()
 
150
        try:
 
151
            # Make sure fetch retrieved only what we requested
 
152
            self.assertEqual({('tree-root', 'rev1'):()},
 
153
                repo.texts.get_parent_map(
 
154
                    [('tree-root', 'rev1'), ('tree-root', 'rev2')]))
 
155
        finally:
 
156
            repo.unlock()
 
157
        branch.pull(tree.branch)
 
158
        # Make sure that the next revision in the root knit was retrieved,
 
159
        # even though the text, name, parent_id, etc., were unchanged.
 
160
        repo.lock_read()
 
161
        try:
 
162
            # Make sure fetch retrieved only what we requested
 
163
            self.assertEqual({('tree-root', 'rev2'):(('tree-root', 'rev1'),)},
 
164
                repo.texts.get_parent_map([('tree-root', 'rev2')]))
 
165
        finally:
 
166
            repo.unlock()
 
167
 
 
168
    def test_fetch_incompatible(self):
 
169
        knit_tree = self.make_branch_and_tree('knit', format='knit')
 
170
        knit3_tree = self.make_branch_and_tree('knit3',
 
171
            format='dirstate-with-subtree')
 
172
        knit3_tree.commit('blah')
 
173
        e = self.assertRaises(errors.IncompatibleRepositories,
 
174
                              knit_tree.branch.fetch, knit3_tree.branch)
 
175
        self.assertContainsRe(str(e),
 
176
            r"(?m).*/knit.*\nis not compatible with\n.*/knit3/.*\n"
 
177
            r"different rich-root support")
 
178
 
116
179
 
117
180
class TestMergeFetch(TestCaseWithTransport):
118
181
 
125
188
        wt2 = self.make_branch_and_tree('br2')
126
189
        br2 = wt2.branch
127
190
        wt2.commit(message='rev 2-1', rev_id='2-1')
128
 
        merge(other_revision=['br1', -1], base_revision=['br1', 0],
129
 
              this_dir='br2')
 
191
        wt2.merge_from_branch(br1, from_revision='null:')
130
192
        self._check_revs_present(br2)
131
193
 
132
194
    def test_merge_fetches(self):
137
199
        dir_2 = br1.bzrdir.sprout('br2')
138
200
        br2 = dir_2.open_branch()
139
201
        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')
 
202
        wt2 = dir_2.open_workingtree()
 
203
        wt2.commit(message='rev 2-1', rev_id='2-1')
 
204
        wt2.merge_from_branch(br1)
143
205
        self._check_revs_present(br2)
144
206
 
145
207
    def _check_revs_present(self, br2):
174
236
    def test_merge_fetches_file_history(self):
175
237
        """Merge brings across file histories"""
176
238
        br2 = Branch.open('br2')
177
 
        merge(other_revision=['br1', -1], base_revision=[None, None], 
178
 
              this_dir='br2')
 
239
        br1 = Branch.open('br1')
 
240
        wt2 = WorkingTree.open('br2').merge_from_branch(br1)
 
241
        br2.lock_read()
 
242
        self.addCleanup(br2.unlock)
179
243
        for rev_id, text in [('1-2', 'original from 1\n'),
180
244
                             ('1-3', 'agreement\n'),
181
245
                             ('2-1', 'contents in 2\n'),
198
262
 
199
263
    def _count_log_matches(self, target, logs):
200
264
        """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__)
 
265
        get_succeeds_re = re.compile(
 
266
            '.*"GET .*%s HTTP/1.1" 20[06] - "-" "bzr/%s' %
 
267
            (     target,                    bzrlib.__version__))
203
268
        c = 0
204
269
        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:
 
270
            if get_succeeds_re.match(line):
208
271
                c += 1
209
272
        return c
210
273
 
211
274
    def test_weaves_are_retrieved_once(self):
212
275
        self.build_tree(("source/", "source/file", "target/"))
213
 
        wt = self.make_branch_and_tree('source')
 
276
        # This test depends on knit dasta storage.
 
277
        wt = self.make_branch_and_tree('source', format='dirstate-tags')
214
278
        branch = wt.branch
215
279
        wt.add(["file"], ["id"])
216
280
        wt.commit("added file")
217
 
        print >>open("source/file", 'w'), "blah"
 
281
        open("source/file", 'w').write("blah\n")
218
282
        wt.commit("changed file")
219
283
        target = BzrDir.create_branch_and_repo("target/")
220
284
        source = Branch.open(self.get_readonly_url("source/"))
221
285
        self.assertEqual(target.fetch(source), (2, []))
222
 
        log_pattern = '%%s HTTP/1.1" 200 - "-" "bzr/%s' % bzrlib.__version__
223
286
        # this is the path to the literal file. As format changes 
224
287
        # occur it needs to be updated. FIXME: ask the store for the
225
288
        # path.
229
292
        # unfortunately this log entry is branch format specific. We could 
230
293
        # factor out the 'what files does this format use' to a method on the 
231
294
        # repository, which would let us to this generically. RBC 20060419
 
295
        # RBC 20080408: Or perhaps we can assert that no files are fully read
 
296
        # twice?
232
297
        self.assertEqual(1, self._count_log_matches('/ce/id.kndx', http_logs))
233
298
        self.assertEqual(1, self._count_log_matches('/ce/id.knit', http_logs))
234
299
        self.assertEqual(1, self._count_log_matches('inventory.kndx', http_logs))
235
300
        # this r-h check test will prevent regressions, but it currently already 
236
301
        # passes, before the patch to cache-rh is applied :[
237
 
        self.assertEqual(1, self._count_log_matches('revision-history', http_logs))
 
302
        self.assertTrue(1 >= self._count_log_matches('revision-history',
 
303
                                                     http_logs))
 
304
        self.assertTrue(1 >= self._count_log_matches('last-revision',
 
305
                                                     http_logs))
238
306
        # FIXME naughty poking in there.
239
307
        self.get_readonly_server().logs = []
240
 
        # check there is nothing more to fetch
241
 
        source = Branch.open(self.get_readonly_url("source/"))
 
308
        # check there is nothing more to fetch.  We take care to re-use the
 
309
        # existing transport so that the request logs we're about to examine
 
310
        # aren't cluttered with redundant probes for a smart server.
 
311
        # XXX: Perhaps this further parameterisation: test http with smart
 
312
        # server, and test http without smart server?
 
313
        source = Branch.open(
 
314
            self.get_readonly_url("source/"),
 
315
            possible_transports=[source.bzrdir.root_transport])
242
316
        self.assertEqual(target.fetch(source), (0, []))
243
317
        # should make just two requests
244
318
        http_logs = self.get_readonly_server().logs
246
320
        self.log('\n'.join(http_logs))
247
321
        self.assertEqual(1, self._count_log_matches('branch-format', http_logs))
248
322
        self.assertEqual(1, self._count_log_matches('branch/format', http_logs))
249
 
        self.assertEqual(1, self._count_log_matches('repository/format', http_logs))
250
 
        self.assertEqual(1, self._count_log_matches('revision-history', http_logs))
 
323
        self.assertEqual(1, self._count_log_matches('repository/format',
 
324
            http_logs))
 
325
        self.assertTrue(1 >= self._count_log_matches('revision-history',
 
326
                                                     http_logs))
 
327
        self.assertTrue(1 >= self._count_log_matches('last-revision',
 
328
                                                     http_logs))
251
329
        self.assertEqual(4, len(http_logs))
 
330
 
 
331
 
 
332
class Test1To2Fetch(TestCaseWithTransport):
 
333
    """Tests for Model1To2 failure modes"""
 
334
 
 
335
    def make_tree_and_repo(self):
 
336
        self.tree = self.make_branch_and_tree('tree', format='pack-0.92')
 
337
        self.repo = self.make_repository('rich-repo', format='rich-root-pack')
 
338
        self.repo.lock_write()
 
339
        self.addCleanup(self.repo.unlock)
 
340
 
 
341
    def do_fetch_order_test(self, first, second):
 
342
        """Test that fetch works no matter what the set order of revision is.
 
343
 
 
344
        This test depends on the order of items in a set, which is
 
345
        implementation-dependant, so we test A, B and then B, A.
 
346
        """
 
347
        self.make_tree_and_repo()
 
348
        self.tree.commit('Commit 1', rev_id=first)
 
349
        self.tree.commit('Commit 2', rev_id=second)
 
350
        self.repo.fetch(self.tree.branch.repository, second)
 
351
 
 
352
    def test_fetch_order_AB(self):
 
353
        """See do_fetch_order_test"""
 
354
        self.do_fetch_order_test('A', 'B')
 
355
 
 
356
    def test_fetch_order_BA(self):
 
357
        """See do_fetch_order_test"""
 
358
        self.do_fetch_order_test('B', 'A')
 
359
 
 
360
    def get_parents(self, file_id, revision_id):
 
361
        self.repo.lock_read()
 
362
        try:
 
363
            parent_map = self.repo.texts.get_parent_map([(file_id, revision_id)])
 
364
            return parent_map[(file_id, revision_id)]
 
365
        finally:
 
366
            self.repo.unlock()
 
367
 
 
368
    def test_fetch_ghosts(self):
 
369
        self.make_tree_and_repo()
 
370
        self.tree.commit('first commit', rev_id='left-parent')
 
371
        self.tree.add_parent_tree_id('ghost-parent')
 
372
        fork = self.tree.bzrdir.sprout('fork', 'null:').open_workingtree()
 
373
        fork.commit('not a ghost', rev_id='not-ghost-parent')
 
374
        self.tree.branch.repository.fetch(fork.branch.repository,
 
375
                                     'not-ghost-parent')
 
376
        self.tree.add_parent_tree_id('not-ghost-parent')
 
377
        self.tree.commit('second commit', rev_id='second-id')
 
378
        self.repo.fetch(self.tree.branch.repository, 'second-id')
 
379
        root_id = self.tree.get_root_id()
 
380
        self.assertEqual(
 
381
            ((root_id, 'left-parent'), (root_id, 'ghost-parent'),
 
382
             (root_id, 'not-ghost-parent')),
 
383
            self.get_parents(root_id, 'second-id'))
 
384
 
 
385
    def make_two_commits(self, change_root, fetch_twice):
 
386
        self.make_tree_and_repo()
 
387
        self.tree.commit('first commit', rev_id='first-id')
 
388
        if change_root:
 
389
            self.tree.set_root_id('unique-id')
 
390
        self.tree.commit('second commit', rev_id='second-id')
 
391
        if fetch_twice:
 
392
            self.repo.fetch(self.tree.branch.repository, 'first-id')
 
393
        self.repo.fetch(self.tree.branch.repository, 'second-id')
 
394
 
 
395
    def test_fetch_changed_root(self):
 
396
        self.make_two_commits(change_root=True, fetch_twice=False)
 
397
        self.assertEqual((), self.get_parents('unique-id', 'second-id'))
 
398
 
 
399
    def test_two_fetch_changed_root(self):
 
400
        self.make_two_commits(change_root=True, fetch_twice=True)
 
401
        self.assertEqual((), self.get_parents('unique-id', 'second-id'))
 
402
 
 
403
    def test_two_fetches(self):
 
404
        self.make_two_commits(change_root=False, fetch_twice=True)
 
405
        self.assertEqual((('TREE_ROOT', 'first-id'),),
 
406
            self.get_parents('TREE_ROOT', 'second-id'))