1
# Copyright (C) 2005 by Canonical Ltd
2
# -*- coding: utf-8 -*-
1
# Copyright (C) 2005, 2006 Canonical Ltd
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
6
5
# the Free Software Foundation; either version 2 of the License, or
7
6
# (at your option) any later version.
9
8
# This program is distributed in the hope that it will be useful,
10
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
11
# GNU General Public License for more details.
14
13
# You should have received a copy of the GNU General Public License
15
14
# along with this program; if not, write to the Free Software
16
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
"""Black-box tests for bzr pull.
18
"""Black-box tests for bzr pull."""
25
23
from bzrlib.branch import Branch
26
from bzrlib.osutils import abspath
24
from bzrlib.osutils import pathjoin
27
25
from bzrlib.tests.blackbox import ExternalBase
28
26
from bzrlib.uncommit import uncommit
27
from bzrlib.workingtree import WorkingTree
28
from bzrlib import urlutils
31
31
class TestPull(ExternalBase):
33
def example_branch(test):
35
file('hello', 'wt').write('foo')
36
test.runbzr('add hello')
37
test.runbzr('commit -m setup hello')
38
file('goodbye', 'wt').write('baz')
39
test.runbzr('add goodbye')
40
test.runbzr('commit -m setup goodbye')
33
def example_branch(self, path='.'):
34
tree = self.make_branch_and_tree(path)
35
self.build_tree_contents([
36
(pathjoin(path, 'hello'), 'foo'),
37
(pathjoin(path, 'goodbye'), 'baz')])
39
tree.commit(message='setup')
41
tree.commit(message='setup')
42
44
def test_pull(self):
43
45
"""Pull changes from one branch to another."""
46
a_tree = self.example_branch('a')
48
self.runbzr('pull', retcode=3)
49
self.runbzr('missing', retcode=3)
50
self.runbzr('missing .')
51
self.runbzr('missing')
52
if sys.platform not in ('win32', 'cygwin'):
53
# This is equivalent to doing "bzr pull ."
54
# Which means that bzr creates 2 branches grabbing
55
# the same location, and tries to pull.
56
# However, 2 branches mean 2 locks on the same file
57
# which ultimately implies a deadlock.
58
# (non windows platforms allow multiple locks on the
59
# same file by the same calling process)
61
self.runbzr('pull /', retcode=3)
62
if sys.platform not in ('win32', 'cygwin'):
48
self.run_bzr('pull', retcode=3)
49
self.run_bzr('missing', retcode=3)
50
self.run_bzr('missing .')
51
self.run_bzr('missing')
52
# this will work on windows because we check for the same branch
53
# in pull - if it fails, it is a regression
55
self.run_bzr('pull /', retcode=3)
56
if sys.platform not in ('win32', 'cygwin'):
66
self.runbzr('branch a b')
60
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
70
self.runbzr('add subdir')
71
self.runbzr('commit -m blah --unchanged')
74
b = Branch.open('../b')
75
self.assertEquals(a.revision_history(), b.revision_history()[:-1])
76
self.runbzr('pull ../b')
77
self.assertEquals(a.revision_history(), b.revision_history())
78
self.runbzr('commit -m blah2 --unchanged')
80
self.runbzr('commit -m blah3 --unchanged')
65
b_tree.commit(message='blah', allow_pointless=True)
70
self.assertEqual(a.revision_history(), b.revision_history()[:-1])
73
self.run_bzr('pull ../b')
74
self.assertEqual(a.revision_history(), b.revision_history())
75
a_tree.commit(message='blah2', allow_pointless=True)
76
b_tree.commit(message='blah3', allow_pointless=True)
82
self.runbzr('pull ../a', retcode=3)
79
self.run_bzr('pull ../a', retcode=3)
84
self.runbzr('branch b overwriteme')
81
b_tree.bzrdir.sprout('overwriteme')
85
82
os.chdir('overwriteme')
86
self.runbzr('pull --overwrite ../a')
83
self.run_bzr('pull --overwrite ../a')
87
84
overwritten = Branch.open('.')
88
85
self.assertEqual(overwritten.revision_history(),
89
86
a.revision_history())
91
self.runbzr('merge ../b')
92
self.runbzr('commit -m blah4 --unchanged')
87
a_tree.merge_from_branch(b_tree.branch)
88
a_tree.commit(message="blah4", allow_pointless=True)
93
89
os.chdir('../b/subdir')
94
self.runbzr('pull ../../a')
95
self.assertEquals(a.revision_history()[-1], b.revision_history()[-1])
96
self.runbzr('commit -m blah5 --unchanged')
97
self.runbzr('commit -m blah6 --unchanged')
90
self.run_bzr('pull ../../a')
91
self.assertEqual(a.revision_history()[-1], b.revision_history()[-1])
92
sub_tree = WorkingTree.open_containing('.')[0]
93
sub_tree.commit(message="blah5", allow_pointless=True)
94
sub_tree.commit(message="blah6", allow_pointless=True)
99
self.runbzr('pull ../a')
96
self.run_bzr('pull ../a')
101
self.runbzr('commit -m blah7 --unchanged')
102
self.runbzr('merge ../b')
103
self.runbzr('commit -m blah8 --unchanged')
104
self.runbzr('pull ../b')
105
self.runbzr('pull ../b')
98
a_tree.commit(message="blah7", allow_pointless=True)
99
a_tree.merge_from_branch(b_tree.branch)
100
a_tree.commit(message="blah8", allow_pointless=True)
101
self.run_bzr('pull ../b')
102
self.run_bzr('pull ../b')
104
def test_pull_dash_d(self):
105
self.example_branch('a')
106
self.make_branch_and_tree('b')
107
self.make_branch_and_tree('c')
108
# pull into that branch
109
self.run_bzr('pull -d b a')
110
# pull into a branch specified by a url
111
c_url = urlutils.local_path_to_url('c')
112
self.assertStartsWith(c_url, 'file://')
113
self.run_bzr(['pull', '-d', c_url, 'a'])
107
115
def test_pull_revision(self):
108
116
"""Pull some changes from one branch to another."""
112
self.example_branch()
113
file('hello2', 'wt').write('foo')
114
self.runbzr('add hello2')
115
self.runbzr('commit -m setup hello2')
116
file('goodbye2', 'wt').write('baz')
117
self.runbzr('add goodbye2')
118
self.runbzr('commit -m setup goodbye2')
121
self.runbzr('branch -r 1 a b')
117
a_tree = self.example_branch('a')
118
self.build_tree_contents([
120
('a/goodbye2', 'baz')])
122
a_tree.commit(message="setup")
123
a_tree.add('goodbye2')
124
a_tree.commit(message="setup")
126
b_tree = a_tree.bzrdir.sprout('b',
127
revision_id=a_tree.branch.get_rev_id(1)).open_workingtree()
123
self.runbzr('pull -r 2')
129
self.run_bzr('pull -r 2')
124
130
a = Branch.open('../a')
125
131
b = Branch.open('.')
126
self.assertEquals(a.revno(),4)
127
self.assertEquals(b.revno(),2)
128
self.runbzr('pull -r 3')
129
self.assertEquals(b.revno(),3)
130
self.runbzr('pull -r 4')
131
self.assertEquals(a.revision_history(), b.revision_history())
132
self.assertEqual(a.revno(),4)
133
self.assertEqual(b.revno(),2)
134
self.run_bzr('pull -r 3')
135
self.assertEqual(b.revno(),3)
136
self.run_bzr('pull -r 4')
137
self.assertEqual(a.revision_history(), b.revision_history())
134
140
def test_overwrite_uptodate(self):
135
141
# Make sure pull --overwrite overwrites
136
142
# even if the target branch has merged
137
143
# everything already.
140
def get_rh(expected_len):
141
rh = self.capture('revision-history')
142
# Make sure we don't have trailing empty revisions
143
rh = rh.strip().split('\n')
144
self.assertEqual(len(rh), expected_len)
150
open('foo', 'wb').write('original\n')
152
bzr('commit', '-m', 'initial commit')
155
bzr('branch', 'a', 'b')
158
open('foo', 'wb').write('changed\n')
159
bzr('commit', '-m', 'later change')
161
open('foo', 'wb').write('another\n')
162
bzr('commit', '-m', 'a third change')
164
rev_history_a = get_rh(3)
168
bzr('commit', '-m', 'merge')
170
rev_history_b = get_rh(2)
172
bzr('pull', '--overwrite', '../a')
173
rev_history_b = get_rh(3)
144
a_tree = self.make_branch_and_tree('a')
145
self.build_tree_contents([('a/foo', 'original\n')])
147
a_tree.commit(message='initial commit')
149
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
151
self.build_tree_contents([('a/foo', 'changed\n')])
152
a_tree.commit(message='later change')
154
self.build_tree_contents([('a/foo', 'a third change')])
155
a_tree.commit(message='a third change')
157
rev_history_a = a_tree.branch.revision_history()
158
self.assertEqual(len(rev_history_a), 3)
160
b_tree.merge_from_branch(a_tree.branch)
161
b_tree.commit(message='merge')
163
self.assertEqual(len(b_tree.branch.revision_history()), 2)
166
self.run_bzr('pull --overwrite ../a')
167
rev_history_b = b_tree.branch.revision_history()
168
self.assertEqual(len(rev_history_b), 3)
175
170
self.assertEqual(rev_history_b, rev_history_a)
177
172
def test_overwrite_children(self):
178
173
# Make sure pull --overwrite sets the revision-history
179
174
# to be identical to the pull source, even if we have convergence
182
def get_rh(expected_len):
183
rh = self.capture('revision-history')
184
# Make sure we don't have trailing empty revisions
185
rh = rh.strip().split('\n')
186
self.assertEqual(len(rh), expected_len)
192
open('foo', 'wb').write('original\n')
194
bzr('commit', '-m', 'initial commit')
197
bzr('branch', 'a', 'b')
200
open('foo', 'wb').write('changed\n')
201
bzr('commit', '-m', 'later change')
203
open('foo', 'wb').write('another\n')
204
bzr('commit', '-m', 'a third change')
206
rev_history_a = get_rh(3)
210
bzr('commit', '-m', 'merge')
212
rev_history_b = get_rh(2)
215
open('foo', 'wb').write('a fourth change\n')
216
bzr('commit', '-m', 'a fourth change')
218
rev_history_a = get_rh(4)
175
a_tree = self.make_branch_and_tree('a')
176
self.build_tree_contents([('a/foo', 'original\n')])
178
a_tree.commit(message='initial commit')
180
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
182
self.build_tree_contents([('a/foo', 'changed\n')])
183
a_tree.commit(message='later change')
185
self.build_tree_contents([('a/foo', 'a third change')])
186
a_tree.commit(message='a third change')
188
self.assertEqual(len(a_tree.branch.revision_history()), 3)
190
b_tree.merge_from_branch(a_tree.branch)
191
b_tree.commit(message='merge')
193
self.assertEqual(len(b_tree.branch.revision_history()), 2)
195
self.build_tree_contents([('a/foo', 'a fourth change\n')])
196
a_tree.commit(message='a fourth change')
198
rev_history_a = a_tree.branch.revision_history()
199
self.assertEqual(len(rev_history_a), 4)
220
201
# With convergence, we could just pull over the
221
202
# new change, but with --overwrite, we want to switch our history
223
bzr('pull', '--overwrite', '../a')
224
rev_history_b = get_rh(4)
204
self.run_bzr('pull --overwrite ../a')
205
rev_history_b = b_tree.branch.revision_history()
206
self.assertEqual(len(rev_history_b), 4)
226
208
self.assertEqual(rev_history_b, rev_history_a)
246
228
self.assertEqual(None, branch_b.get_parent())
247
229
# test pull for failure without parent set
248
230
os.chdir('branch_b')
249
out = self.runbzr('pull', retcode=3)
250
self.assertEquals(out,
231
out = self.run_bzr('pull', retcode=3)
232
self.assertEqual(out,
251
233
('','bzr: ERROR: No pull location known or specified.\n'))
252
234
# test implicit --remember when no parent set, this pull conflicts
253
235
self.build_tree(['d'])
255
237
tree_b.commit('commit d')
256
out = self.runbzr('pull ../branch_a', retcode=3)
257
self.assertEquals(out,
258
('','bzr: ERROR: These branches have diverged. Try merge.\n'))
259
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
238
out = self.run_bzr('pull ../branch_a', retcode=3)
239
self.assertEqual(out,
240
('','bzr: ERROR: These branches have diverged.'
241
' Use the merge command to reconcile them.\n'))
242
self.assertEqual(branch_b.get_parent(), parent)
260
243
# test implicit --remember after resolving previous failure
261
244
uncommit(branch=branch_b, tree=tree_b)
262
245
transport.delete('branch_b/d')
264
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
247
self.assertEqual(branch_b.get_parent(), parent)
265
248
# test explicit --remember
266
self.runbzr('pull ../branch_c --remember')
267
self.assertEquals(abspath(branch_b.get_parent()),
268
abspath(branch_c.bzrdir.root_transport.base))
249
self.run_bzr('pull ../branch_c --remember')
250
self.assertEqual(branch_b.get_parent(),
251
branch_c.bzrdir.root_transport.base)
253
def test_pull_bundle(self):
254
from bzrlib.testament import Testament
255
# Build up 2 trees and prepare for a pull
256
tree_a = self.make_branch_and_tree('branch_a')
257
f = open('branch_a/a', 'wb')
261
tree_a.commit('message')
263
tree_b = tree_a.bzrdir.sprout('branch_b').open_workingtree()
265
# Make a change to 'a' that 'b' can pull
266
f = open('branch_a/a', 'wb')
269
tree_a.commit('message')
271
# Create the bundle for 'b' to pull
273
self.run_bzr('bundle ../branch_b -o ../bundle')
275
os.chdir('../branch_b')
276
out, err = self.run_bzr('pull ../bundle')
277
self.assertEqual(out,
278
'Now on revision 2.\n')
279
self.assertEqual(err,
280
' M a\nAll changes applied successfully.\n')
282
self.assertEqualDiff(tree_a.branch.revision_history(),
283
tree_b.branch.revision_history())
285
testament_a = Testament.from_revision(tree_a.branch.repository,
286
tree_a.get_parent_ids()[0])
287
testament_b = Testament.from_revision(tree_b.branch.repository,
288
tree_b.get_parent_ids()[0])
289
self.assertEqualDiff(testament_a.as_text(),
290
testament_b.as_text())
292
# it is legal to attempt to pull an already-merged bundle
293
out, err = self.run_bzr('pull ../bundle')
294
self.assertEqual(err, '')
295
self.assertEqual(out, 'No revisions to pull.\n')
297
def test_pull_verbose_no_files(self):
298
"""Pull --verbose should not list modified files"""
299
tree_a = self.make_branch_and_tree('tree_a')
300
self.build_tree(['tree_a/foo'])
303
tree_b = self.make_branch_and_tree('tree_b')
304
out = self.run_bzr('pull --verbose -d tree_b tree_a')[0]
305
self.assertContainsRe(out, 'bar')
306
self.assertNotContainsRe(out, 'added:')
307
self.assertNotContainsRe(out, 'foo')
309
def test_pull_quiet(self):
310
"""Check that bzr pull --quiet does not print anything"""
311
tree_a = self.make_branch_and_tree('tree_a')
312
self.build_tree(['tree_a/foo'])
314
revision_id = tree_a.commit('bar')
315
tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
316
out, err = self.run_bzr('pull --quiet -d tree_b')
317
self.assertEqual(out, '')
318
self.assertEqual(err, '')
319
self.assertEqual(tree_b.last_revision(), revision_id)
320
self.build_tree(['tree_a/moo'])
322
revision_id = tree_a.commit('quack')
323
out, err = self.run_bzr('pull --quiet -d tree_b')
324
self.assertEqual(out, '')
325
self.assertEqual(err, '')
326
self.assertEqual(tree_b.last_revision(), revision_id)