~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

Add Transport.supports_unix_modebits, so tests can 
avoid testing them where they won't work.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
import os
19
19
 
20
20
import bzrlib
21
 
from bzrlib.tests import TestCaseInTempDir
 
21
from bzrlib.tests import TestCaseWithTransport
22
22
from bzrlib.branch import Branch
 
23
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
23
24
from bzrlib.workingtree import WorkingTree
24
25
from bzrlib.commit import Commit
25
26
from bzrlib.config import BranchConfig
26
 
from bzrlib.errors import PointlessCommit, BzrError, SigningFailed
 
27
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
 
28
                           LockContention)
27
29
 
28
30
 
29
31
# TODO: Test commit with some added, and added-but-missing files
43
45
        return "bzrlib.ahook bzrlib.ahook"
44
46
 
45
47
 
46
 
class TestCommit(TestCaseInTempDir):
 
48
class TestCommit(TestCaseWithTransport):
47
49
 
48
50
    def test_simple_commit(self):
49
51
        """Commit and check two versions of a single file."""
50
 
        b = Branch.initialize(u'.')
 
52
        wt = self.make_branch_and_tree('.')
 
53
        b = wt.branch
51
54
        file('hello', 'w').write('hello world')
52
 
        b.working_tree().add('hello')
53
 
        b.working_tree().commit(message='add hello')
54
 
        file_id = b.working_tree().path2id('hello')
 
55
        wt.add('hello')
 
56
        wt.commit(message='add hello')
 
57
        file_id = wt.path2id('hello')
55
58
 
56
59
        file('hello', 'w').write('version 2')
57
 
        b.working_tree().commit(message='commit 2')
 
60
        wt.commit(message='commit 2')
58
61
 
59
62
        eq = self.assertEquals
60
63
        eq(b.revno(), 2)
71
74
 
72
75
    def test_delete_commit(self):
73
76
        """Test a commit with a deleted file"""
74
 
        b = Branch.initialize(u'.')
 
77
        wt = self.make_branch_and_tree('.')
 
78
        b = wt.branch
75
79
        file('hello', 'w').write('hello world')
76
 
        b.working_tree().add(['hello'], ['hello-id'])
77
 
        b.working_tree().commit(message='add hello')
 
80
        wt.add(['hello'], ['hello-id'])
 
81
        wt.commit(message='add hello')
78
82
 
79
83
        os.remove('hello')
80
 
        b.working_tree().commit('removed hello', rev_id='rev2')
 
84
        wt.commit('removed hello', rev_id='rev2')
81
85
 
82
86
        tree = b.repository.revision_tree('rev2')
83
87
        self.assertFalse(tree.has_id('hello-id'))
84
88
 
85
89
    def test_pointless_commit(self):
86
90
        """Commit refuses unless there are changes or it's forced."""
87
 
        b = Branch.initialize(u'.')
 
91
        wt = self.make_branch_and_tree('.')
 
92
        b = wt.branch
88
93
        file('hello', 'w').write('hello')
89
 
        b.working_tree().add(['hello'])
90
 
        b.working_tree().commit(message='add hello')
 
94
        wt.add(['hello'])
 
95
        wt.commit(message='add hello')
91
96
        self.assertEquals(b.revno(), 1)
92
97
        self.assertRaises(PointlessCommit,
93
 
                          b.working_tree().commit,
 
98
                          wt.commit,
94
99
                          message='fails',
95
100
                          allow_pointless=False)
96
101
        self.assertEquals(b.revno(), 1)
97
102
        
98
103
    def test_commit_empty(self):
99
104
        """Commiting an empty tree works."""
100
 
        b = Branch.initialize(u'.')
101
 
        b.working_tree().commit(message='empty tree', allow_pointless=True)
 
105
        wt = self.make_branch_and_tree('.')
 
106
        b = wt.branch
 
107
        wt.commit(message='empty tree', allow_pointless=True)
102
108
        self.assertRaises(PointlessCommit,
103
 
                          b.working_tree().commit,
 
109
                          wt.commit,
104
110
                          message='empty tree',
105
111
                          allow_pointless=False)
106
 
        b.working_tree().commit(message='empty tree', allow_pointless=True)
 
112
        wt.commit(message='empty tree', allow_pointless=True)
107
113
        self.assertEquals(b.revno(), 2)
108
114
 
109
 
 
110
115
    def test_selective_delete(self):
111
116
        """Selective commit in tree with deletions"""
112
 
        b = Branch.initialize(u'.')
 
117
        wt = self.make_branch_and_tree('.')
 
118
        b = wt.branch
113
119
        file('hello', 'w').write('hello')
114
120
        file('buongia', 'w').write('buongia')
115
 
        b.working_tree().add(['hello', 'buongia'],
 
121
        wt.add(['hello', 'buongia'],
116
122
              ['hello-id', 'buongia-id'])
117
 
        b.working_tree().commit(message='add files',
 
123
        wt.commit(message='add files',
118
124
                 rev_id='test@rev-1')
119
125
        
120
126
        os.remove('hello')
121
127
        file('buongia', 'w').write('new text')
122
 
        b.working_tree().commit(message='update text',
 
128
        wt.commit(message='update text',
123
129
                 specific_files=['buongia'],
124
130
                 allow_pointless=False,
125
131
                 rev_id='test@rev-2')
126
132
 
127
 
        b.working_tree().commit(message='remove hello',
 
133
        wt.commit(message='remove hello',
128
134
                 specific_files=['hello'],
129
135
                 allow_pointless=False,
130
136
                 rev_id='test@rev-3')
141
147
        self.assertFalse(tree3.has_filename('hello'))
142
148
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
143
149
 
144
 
 
145
150
    def test_commit_rename(self):
146
151
        """Test commit of a revision where a file is renamed."""
147
 
        b = Branch.initialize(u'.')
148
 
        tree = WorkingTree(u'.', b)
 
152
        tree = self.make_branch_and_tree('.')
 
153
        b = tree.branch
149
154
        self.build_tree(['hello'], line_endings='binary')
150
155
        tree.add(['hello'], ['hello-id'])
151
156
        tree.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
171
176
 
172
177
    def test_reused_rev_id(self):
173
178
        """Test that a revision id cannot be reused in a branch"""
174
 
        b = Branch.initialize(u'.')
175
 
        b.working_tree().commit('initial', rev_id='test@rev-1', allow_pointless=True)
 
179
        wt = self.make_branch_and_tree('.')
 
180
        b = wt.branch
 
181
        wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
176
182
        self.assertRaises(Exception,
177
 
                          b.working_tree().commit,
 
183
                          wt.commit,
178
184
                          message='reused id',
179
185
                          rev_id='test@rev-1',
180
186
                          allow_pointless=True)
182
188
    def test_commit_move(self):
183
189
        """Test commit of revisions with moved files and directories"""
184
190
        eq = self.assertEquals
185
 
        b = Branch.initialize(u'.')
 
191
        wt = self.make_branch_and_tree('.')
 
192
        b = wt.branch
186
193
        r1 = 'test@rev-1'
187
194
        self.build_tree(['hello', 'a/', 'b/'])
188
 
        b.working_tree().add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
189
 
        b.working_tree().commit('initial', rev_id=r1, allow_pointless=False)
190
 
        b.working_tree().move(['hello'], 'a')
 
195
        wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
 
196
        wt.commit('initial', rev_id=r1, allow_pointless=False)
 
197
        wt.move(['hello'], 'a')
191
198
        r2 = 'test@rev-2'
192
 
        b.working_tree().commit('two', rev_id=r2, allow_pointless=False)
193
 
        self.check_inventory_shape(b.working_tree().read_working_inventory(),
 
199
        wt.commit('two', rev_id=r2, allow_pointless=False)
 
200
        self.check_inventory_shape(wt.read_working_inventory(),
194
201
                                   ['a', 'a/hello', 'b'])
195
202
 
196
 
        b.working_tree().move(['b'], 'a')
 
203
        wt.move(['b'], 'a')
197
204
        r3 = 'test@rev-3'
198
 
        b.working_tree().commit('three', rev_id=r3, allow_pointless=False)
199
 
        self.check_inventory_shape(b.working_tree().read_working_inventory(),
 
205
        wt.commit('three', rev_id=r3, allow_pointless=False)
 
206
        self.check_inventory_shape(wt.read_working_inventory(),
200
207
                                   ['a', 'a/hello', 'a/b'])
201
208
        self.check_inventory_shape(b.repository.get_revision_inventory(r3),
202
209
                                   ['a', 'a/hello', 'a/b'])
203
210
 
204
 
        b.working_tree().move(['a/hello'], 'a/b')
 
211
        wt.move(['a/hello'], 'a/b')
205
212
        r4 = 'test@rev-4'
206
 
        b.working_tree().commit('four', rev_id=r4, allow_pointless=False)
207
 
        self.check_inventory_shape(b.working_tree().read_working_inventory(),
 
213
        wt.commit('four', rev_id=r4, allow_pointless=False)
 
214
        self.check_inventory_shape(wt.read_working_inventory(),
208
215
                                   ['a', 'a/b/hello', 'a/b'])
209
216
 
210
217
        inv = b.repository.get_revision_inventory(r4)
214
221
        
215
222
    def test_removed_commit(self):
216
223
        """Commit with a removed file"""
217
 
        b = Branch.initialize(u'.')
218
 
        wt = b.working_tree()
 
224
        wt = self.make_branch_and_tree('.')
 
225
        b = wt.branch
219
226
        file('hello', 'w').write('hello world')
220
 
        b.working_tree().add(['hello'], ['hello-id'])
221
 
        b.working_tree().commit(message='add hello')
222
 
 
223
 
        wt = b.working_tree()  # FIXME: kludge for aliasing of working inventory
 
227
        wt.add(['hello'], ['hello-id'])
 
228
        wt.commit(message='add hello')
224
229
        wt.remove('hello')
225
 
        b.working_tree().commit('removed hello', rev_id='rev2')
 
230
        wt.commit('removed hello', rev_id='rev2')
226
231
 
227
232
        tree = b.repository.revision_tree('rev2')
228
233
        self.assertFalse(tree.has_id('hello-id'))
229
234
 
230
 
 
231
235
    def test_committed_ancestry(self):
232
236
        """Test commit appends revisions to ancestry."""
233
 
        b = Branch.initialize(u'.')
 
237
        wt = self.make_branch_and_tree('.')
 
238
        b = wt.branch
234
239
        rev_ids = []
235
240
        for i in range(4):
236
241
            file('hello', 'w').write((str(i) * 4) + '\n')
237
242
            if i == 0:
238
 
                b.working_tree().add(['hello'], ['hello-id'])
 
243
                wt.add(['hello'], ['hello-id'])
239
244
            rev_id = 'test@rev-%d' % (i+1)
240
245
            rev_ids.append(rev_id)
241
 
            b.working_tree().commit(message='rev %d' % (i+1),
 
246
            wt.commit(message='rev %d' % (i+1),
242
247
                     rev_id=rev_id)
243
248
        eq = self.assertEquals
244
249
        eq(b.revision_history(), rev_ids)
247
252
            eq(anc, [None] + rev_ids[:i+1])
248
253
 
249
254
    def test_commit_new_subdir_child_selective(self):
250
 
        b = Branch.initialize(u'.')
 
255
        wt = self.make_branch_and_tree('.')
 
256
        b = wt.branch
251
257
        self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
252
 
        b.working_tree().add(['dir', 'dir/file1', 'dir/file2'],
 
258
        wt.add(['dir', 'dir/file1', 'dir/file2'],
253
259
              ['dirid', 'file1id', 'file2id'])
254
 
        b.working_tree().commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
 
260
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
255
261
        inv = b.repository.get_inventory('1')
256
262
        self.assertEqual('1', inv['dirid'].revision)
257
263
        self.assertEqual('1', inv['file1id'].revision)
261
267
    def test_strict_commit(self):
262
268
        """Try and commit with unknown files and strict = True, should fail."""
263
269
        from bzrlib.errors import StrictCommitFailed
264
 
        b = Branch.initialize(u'.')
 
270
        wt = self.make_branch_and_tree('.')
 
271
        b = wt.branch
265
272
        file('hello', 'w').write('hello world')
266
 
        b.working_tree().add('hello')
 
273
        wt.add('hello')
267
274
        file('goodbye', 'w').write('goodbye cruel world!')
268
 
        self.assertRaises(StrictCommitFailed, b.working_tree().commit,
 
275
        self.assertRaises(StrictCommitFailed, wt.commit,
269
276
            message='add hello but not goodbye', strict=True)
270
277
 
271
278
    def test_strict_commit_without_unknowns(self):
272
279
        """Try and commit with no unknown files and strict = True,
273
280
        should work."""
274
281
        from bzrlib.errors import StrictCommitFailed
275
 
        b = Branch.initialize(u'.')
 
282
        wt = self.make_branch_and_tree('.')
 
283
        b = wt.branch
276
284
        file('hello', 'w').write('hello world')
277
 
        b.working_tree().add('hello')
278
 
        b.working_tree().commit(message='add hello', strict=True)
 
285
        wt.add('hello')
 
286
        wt.commit(message='add hello', strict=True)
279
287
 
280
288
    def test_nonstrict_commit(self):
281
289
        """Try and commit with unknown files and strict = False, should work."""
282
 
        b = Branch.initialize(u'.')
 
290
        wt = self.make_branch_and_tree('.')
 
291
        b = wt.branch
283
292
        file('hello', 'w').write('hello world')
284
 
        b.working_tree().add('hello')
 
293
        wt.add('hello')
285
294
        file('goodbye', 'w').write('goodbye cruel world!')
286
 
        b.working_tree().commit(message='add hello but not goodbye', strict=False)
 
295
        wt.commit(message='add hello but not goodbye', strict=False)
287
296
 
288
297
    def test_nonstrict_commit_without_unknowns(self):
289
298
        """Try and commit with no unknown files and strict = False,
290
299
        should work."""
291
 
        b = Branch.initialize(u'.')
 
300
        wt = self.make_branch_and_tree('.')
 
301
        b = wt.branch
292
302
        file('hello', 'w').write('hello world')
293
 
        b.working_tree().add('hello')
294
 
        b.working_tree().commit(message='add hello', strict=False)
 
303
        wt.add('hello')
 
304
        wt.commit(message='add hello', strict=False)
295
305
 
296
306
    def test_signed_commit(self):
297
307
        import bzrlib.gpg
298
308
        import bzrlib.commit as commit
299
309
        oldstrategy = bzrlib.gpg.GPGStrategy
300
 
        branch = Branch.initialize(u'.')
301
 
        branch.working_tree().commit("base", allow_pointless=True, rev_id='A')
302
 
        self.failIf(branch.repository.revision_store.has_id('A', 'sig'))
 
310
        wt = self.make_branch_and_tree('.')
 
311
        branch = wt.branch
 
312
        wt.commit("base", allow_pointless=True, rev_id='A')
 
313
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
303
314
        try:
304
315
            from bzrlib.testament import Testament
305
316
            # monkey patch gpg signing mechanism
306
317
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
307
 
            commit.Commit(config=MustSignConfig(branch)).commit(branch, "base",
 
318
            commit.Commit(config=MustSignConfig(branch)).commit(message="base",
308
319
                                                      allow_pointless=True,
309
 
                                                      rev_id='B')
 
320
                                                      rev_id='B',
 
321
                                                      working_tree=wt)
310
322
            self.assertEqual(Testament.from_revision(branch.repository,
311
323
                             'B').as_short_text(),
312
 
                             branch.repository.revision_store.get('B', 
313
 
                                                               'sig').read())
 
324
                             branch.repository.get_signature_text('B'))
314
325
        finally:
315
326
            bzrlib.gpg.GPGStrategy = oldstrategy
316
327
 
318
329
        import bzrlib.gpg
319
330
        import bzrlib.commit as commit
320
331
        oldstrategy = bzrlib.gpg.GPGStrategy
321
 
        branch = Branch.initialize(u'.')
322
 
        branch.working_tree().commit("base", allow_pointless=True, rev_id='A')
323
 
        self.failIf(branch.repository.revision_store.has_id('A', 'sig'))
 
332
        wt = self.make_branch_and_tree('.')
 
333
        branch = wt.branch
 
334
        wt.commit("base", allow_pointless=True, rev_id='A')
 
335
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
324
336
        try:
325
337
            from bzrlib.testament import Testament
326
338
            # monkey patch gpg signing mechanism
328
340
            config = MustSignConfig(branch)
329
341
            self.assertRaises(SigningFailed,
330
342
                              commit.Commit(config=config).commit,
331
 
                              branch, "base",
 
343
                              message="base",
332
344
                              allow_pointless=True,
333
 
                              rev_id='B')
334
 
            branch = Branch.open(u'.')
 
345
                              rev_id='B',
 
346
                              working_tree=wt)
 
347
            branch = Branch.open(self.get_url('.'))
335
348
            self.assertEqual(branch.revision_history(), ['A'])
336
 
            self.failIf(branch.repository.revision_store.has_id('B'))
 
349
            self.failIf(branch.repository.has_revision('B'))
337
350
        finally:
338
351
            bzrlib.gpg.GPGStrategy = oldstrategy
339
352
 
340
353
    def test_commit_invokes_hooks(self):
341
354
        import bzrlib.commit as commit
342
 
        branch = Branch.initialize(u'.')
 
355
        wt = self.make_branch_and_tree('.')
 
356
        branch = wt.branch
343
357
        calls = []
344
358
        def called(branch, rev_id):
345
359
            calls.append('called')
347
361
        try:
348
362
            config = BranchWithHooks(branch)
349
363
            commit.Commit(config=config).commit(
350
 
                            branch, "base",
 
364
                            message = "base",
351
365
                            allow_pointless=True,
352
 
                            rev_id='A')
 
366
                            rev_id='A', working_tree = wt)
353
367
            self.assertEqual(['called', 'called'], calls)
354
368
        finally:
355
369
            del bzrlib.ahook
 
370
 
 
371
    def test_commit_object_doesnt_set_nick(self):
 
372
        # using the Commit object directly does not set the branch nick.
 
373
        wt = self.make_branch_and_tree('.')
 
374
        c = Commit()
 
375
        c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
 
376
        self.assertEquals(wt.branch.revno(), 1)
 
377
        self.assertEqual({},
 
378
                         wt.branch.repository.get_revision(
 
379
                            wt.branch.last_revision()).properties)
 
380
 
 
381
    def test_safe_master_lock(self):
 
382
        os.mkdir('master')
 
383
        master = BzrDirMetaFormat1().initialize('master')
 
384
        master.create_repository()
 
385
        master_branch = master.create_branch()
 
386
        master.create_workingtree()
 
387
        bound = master.sprout('bound')
 
388
        wt = bound.open_workingtree()
 
389
        wt.branch.set_bound_location(os.path.realpath('master'))
 
390
        master_branch.lock_write()
 
391
        self.assertRaises(LockContention, wt.commit, 'silly')