~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_fetch.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

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