~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_fetch.py

  • Committer: Aaron Bentley
  • Date: 2007-02-06 14:52:16 UTC
  • mfrom: (2266 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2268.
  • Revision ID: abentley@panoramicfeedback.com-20070206145216-fcpi8o3ufvuzwbp9
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007 Canonical Ltd
 
1
# Copyright (C) 2005 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
18
18
import re
19
19
import sys
20
20
 
21
 
import bzrlib
22
 
from bzrlib import (
23
 
    bzrdir,
24
 
    errors,
25
 
    merge,
26
 
    repository,
27
 
    )
 
21
from bzrlib import bzrdir, repository
28
22
from bzrlib.branch import Branch
29
23
from bzrlib.bzrdir import BzrDir
30
 
from bzrlib.repofmt import knitrepo
 
24
from bzrlib.builtins import merge
 
25
import bzrlib.errors
31
26
from bzrlib.tests import TestCaseWithTransport
32
 
from bzrlib.tests.http_utils import TestCaseWithWebserver
 
27
from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver
33
28
from bzrlib.tests.test_revision import make_branches
34
29
from bzrlib.trace import mutter
35
30
from bzrlib.upgrade import Convert
36
31
from bzrlib.workingtree import WorkingTree
37
32
 
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
 
 
42
33
 
43
34
def has_revision(branch, revision_id):
44
35
    return branch.repository.has_revision(revision_id)
98
89
    self.assertEquals(fetched, 3, "fetched %d instead of 3" % fetched)
99
90
    # InstallFailed should be raised if the branch is missing the revision
100
91
    # that was requested.
101
 
    self.assertRaises(errors.InstallFailed, br_a3.fetch, br_a2, 'pizza')
 
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)
102
97
 
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
 
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
108
102
 
109
103
    #TODO: test that fetch correctly does reweaving when needed. RBC 20051008
110
104
    # Note that this means - updating the weave when ghosts are filled in to 
115
109
 
116
110
    def test_fetch(self):
117
111
        #highest indices a: 5, b: 7
118
 
        br_a, br_b = make_branches(self, format='dirstate-tags')
 
112
        br_a, br_b = make_branches(self)
119
113
        fetch_steps(self, br_a, br_b, br_a)
120
114
 
121
115
    def test_fetch_self(self):
129
123
        corresponding filename, parent, contents or other changes.
130
124
        """
131
125
        knit1_format = bzrdir.BzrDirMetaFormat1()
132
 
        knit1_format.repository_format = knitrepo.RepositoryFormatKnit1()
 
126
        knit1_format.repository_format = repository.RepositoryFormatKnit1()
133
127
        knit2_format = bzrdir.BzrDirMetaFormat1()
134
 
        knit2_format.repository_format = knitrepo.RepositoryFormatKnit3()
 
128
        knit2_format.repository_format = repository.RepositoryFormatKnit2()
135
129
        # we start with a knit1 repository because that causes the
136
130
        # root revision to change for each commit, even though the content,
137
131
        # parent, name, and other attributes are unchanged.
146
140
        branch = self.make_branch('branch', format=knit2_format)
147
141
        branch.pull(tree.branch, stop_revision='rev1')
148
142
        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()
 
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)
157
148
        branch.pull(tree.branch)
 
149
        root_knit = repo.weave_store.get_weave('tree-root',
 
150
                                                repo.get_transaction())
158
151
        # Make sure that the next revision in the root knit was retrieved,
159
152
        # 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")
 
153
        self.assertTrue('rev2' in root_knit)
178
154
 
179
155
 
180
156
class TestMergeFetch(TestCaseWithTransport):
188
164
        wt2 = self.make_branch_and_tree('br2')
189
165
        br2 = wt2.branch
190
166
        wt2.commit(message='rev 2-1', rev_id='2-1')
191
 
        wt2.merge_from_branch(br1, from_revision='null:')
 
167
        merge(other_revision=['br1', -1], base_revision=['br1', 0],
 
168
              this_dir='br2')
192
169
        self._check_revs_present(br2)
193
170
 
194
171
    def test_merge_fetches(self):
199
176
        dir_2 = br1.bzrdir.sprout('br2')
200
177
        br2 = dir_2.open_branch()
201
178
        wt1.commit(message='rev 1-2', rev_id='1-2')
202
 
        wt2 = dir_2.open_workingtree()
203
 
        wt2.commit(message='rev 2-1', rev_id='2-1')
204
 
        wt2.merge_from_branch(br1)
 
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')
205
182
        self._check_revs_present(br2)
206
183
 
207
184
    def _check_revs_present(self, br2):
236
213
    def test_merge_fetches_file_history(self):
237
214
        """Merge brings across file histories"""
238
215
        br2 = Branch.open('br2')
239
 
        br1 = Branch.open('br1')
240
 
        wt2 = WorkingTree.open('br2').merge_from_branch(br1)
241
 
        br2.lock_read()
242
 
        self.addCleanup(br2.unlock)
 
216
        merge(other_revision=['br1', -1], base_revision=[None, None], 
 
217
              this_dir='br2')
243
218
        for rev_id, text in [('1-2', 'original from 1\n'),
244
219
                             ('1-3', 'agreement\n'),
245
220
                             ('2-1', 'contents in 2\n'),
273
248
 
274
249
    def test_weaves_are_retrieved_once(self):
275
250
        self.build_tree(("source/", "source/file", "target/"))
276
 
        # This test depends on knit dasta storage.
277
 
        wt = self.make_branch_and_tree('source', format='dirstate-tags')
 
251
        wt = self.make_branch_and_tree('source')
278
252
        branch = wt.branch
279
253
        wt.add(["file"], ["id"])
280
254
        wt.commit("added file")
281
 
        open("source/file", 'w').write("blah\n")
 
255
        print >>open("source/file", 'w'), "blah"
282
256
        wt.commit("changed file")
283
257
        target = BzrDir.create_branch_and_repo("target/")
284
258
        source = Branch.open(self.get_readonly_url("source/"))
292
266
        # unfortunately this log entry is branch format specific. We could 
293
267
        # factor out the 'what files does this format use' to a method on the 
294
268
        # 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?
297
269
        self.assertEqual(1, self._count_log_matches('/ce/id.kndx', http_logs))
298
270
        self.assertEqual(1, self._count_log_matches('/ce/id.knit', http_logs))
299
271
        self.assertEqual(1, self._count_log_matches('inventory.kndx', http_logs))
300
272
        # this r-h check test will prevent regressions, but it currently already 
301
273
        # passes, before the patch to cache-rh is applied :[
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))
 
274
        self.assertEqual(1, self._count_log_matches('revision-history', http_logs))
306
275
        # FIXME naughty poking in there.
307
276
        self.get_readonly_server().logs = []
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])
 
277
        # check there is nothing more to fetch
 
278
        source = Branch.open(self.get_readonly_url("source/"))
316
279
        self.assertEqual(target.fetch(source), (0, []))
317
280
        # should make just two requests
318
281
        http_logs = self.get_readonly_server().logs
320
283
        self.log('\n'.join(http_logs))
321
284
        self.assertEqual(1, self._count_log_matches('branch-format', http_logs))
322
285
        self.assertEqual(1, self._count_log_matches('branch/format', 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))
 
286
        self.assertEqual(1, self._count_log_matches('repository/format', http_logs))
 
287
        self.assertEqual(1, self._count_log_matches('revision-history', http_logs))
329
288
        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'))