/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
1
# Copyright (C) 2006-2012, 2016 Canonical Ltd
1740.3.1 by Jelmer Vernooij
Introduce and use CommitBuilder objects.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1740.3.1 by Jelmer Vernooij
Introduce and use CommitBuilder objects.
16
17
"""Tests for repository commit builder."""
18
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
19
import os
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
20
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
21
from breezy import (
5609.31.2 by mbp at sourcefrog
Also turn off whoami inference in per_repository tests
22
    config,
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
23
    errors,
24
    osutils,
25
    repository,
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
26
    revision as _mod_revision,
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
27
    tests,
28
    )
6670.4.3 by Jelmer Vernooij
Fix more imports.
29
from breezy.bzr import (
30
    inventory,
31
    )
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
32
from breezy.tests import per_repository
33
from breezy.tests import (
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
34
    features,
35
    )
5010.2.24 by Vincent Ladeuil
Fix imports in per_repository/test_commit_builder.py.
36
37
38
class TestCommitBuilder(per_repository.TestCaseWithRepository):
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
39
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
40
    def test_get_commit_builder(self):
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
41
        branch = self.make_branch('.')
42
        branch.repository.lock_write()
43
        builder = branch.repository.get_commit_builder(
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
44
            branch, [], branch.get_config_stack())
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
45
        self.assertIsInstance(builder, repository.CommitBuilder)
2805.6.1 by Robert Collins
Set random_revid on CommitBuilder when a commit generated its own revision id.
46
        self.assertTrue(builder.random_revid)
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
47
        branch.repository.commit_write_group()
48
        branch.repository.unlock()
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
49
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
50
    def test_finish_inventory_record_iter_changes(self):
51
        tree = self.make_branch_and_tree(".")
52
        tree.lock_write()
53
        try:
54
            builder = tree.branch.get_commit_builder([])
55
            try:
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
56
                list(builder.record_iter_changes(tree, tree.last_revision(),
57
                    tree.iter_changes(tree.basis_tree())))
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
58
                builder.finish_inventory()
59
            except:
60
                builder.abort()
61
                raise
62
            repo = tree.branch.repository
63
            repo.commit_write_group()
2617.6.8 by Robert Collins
Review feedback and documentation.
64
        finally:
65
            tree.unlock()
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
66
3775.2.5 by Robert Collins
CommitBuilder.abort() is callable after record_iter_changes.
67
    def test_abort_record_iter_changes(self):
68
        tree = self.make_branch_and_tree(".")
69
        tree.lock_write()
70
        try:
71
            builder = tree.branch.get_commit_builder([])
72
            try:
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
73
                basis = tree.basis_tree()
74
                last_rev = tree.last_revision()
75
                changes = tree.iter_changes(basis)
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
76
                list(builder.record_iter_changes(tree, last_rev, changes))
3775.2.5 by Robert Collins
CommitBuilder.abort() is callable after record_iter_changes.
77
                builder.finish_inventory()
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
78
            finally:
3775.2.5 by Robert Collins
CommitBuilder.abort() is callable after record_iter_changes.
79
                builder.abort()
80
        finally:
81
            tree.unlock()
82
5777.6.8 by Jelmer Vernooij
Add test for get_commit_builder(lossy=True).
83
    def test_commit_lossy(self):
84
        tree = self.make_branch_and_tree(".")
85
        tree.lock_write()
86
        try:
87
            builder = tree.branch.get_commit_builder([], lossy=True)
88
            list(builder.record_iter_changes(tree, tree.last_revision(),
89
                tree.iter_changes(tree.basis_tree())))
90
            builder.finish_inventory()
91
            rev_id = builder.commit('foo bar blah')
92
        finally:
93
            tree.unlock()
94
        rev = tree.branch.repository.get_revision(rev_id)
95
        self.assertEqual('foo bar blah', rev.message)
96
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
97
    def test_commit_message(self):
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
98
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
99
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
100
        try:
101
            builder = tree.branch.get_commit_builder([])
5718.4.6 by Jelmer Vernooij
inline function only used once.
102
            list(builder.record_iter_changes(tree, tree.last_revision(),
103
                tree.iter_changes(tree.basis_tree())))
104
            builder.finish_inventory()
2617.6.8 by Robert Collins
Review feedback and documentation.
105
            rev_id = builder.commit('foo bar blah')
106
        finally:
107
            tree.unlock()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
108
        rev = tree.branch.repository.get_revision(rev_id)
109
        self.assertEqual('foo bar blah', rev.message)
110
6217.5.1 by Jelmer Vernooij
Add CommitBuilder.updates_branch.
111
    def test_updates_branch(self):
112
        tree = self.make_branch_and_tree(".")
113
        tree.lock_write()
114
        try:
115
            builder = tree.branch.get_commit_builder([])
116
            list(builder.record_iter_changes(tree, tree.last_revision(),
117
                tree.iter_changes(tree.basis_tree())))
118
            builder.finish_inventory()
119
            will_update_branch = builder.updates_branch
120
            rev_id = builder.commit('might update the branch')
121
        finally:
122
            tree.unlock()
123
        actually_updated_branch = (tree.branch.last_revision() == rev_id)
6614.1.3 by Vincent Ladeuil
Fix assertEquals being deprecated by using assertEqual.
124
        self.assertEqual(actually_updated_branch, will_update_branch)
6217.5.1 by Jelmer Vernooij
Add CommitBuilder.updates_branch.
125
3775.2.6 by Robert Collins
CommitBuilder can specify a revision_id with record_iter_changes.
126
    def test_commit_with_revision_id_record_iter_changes(self):
127
        tree = self.make_branch_and_tree(".")
128
        tree.lock_write()
129
        try:
130
            # use a unicode revision id to test more corner cases.
131
            # The repository layer is meant to handle this.
132
            revision_id = u'\xc8abc'.encode('utf8')
133
            try:
134
                try:
135
                    builder = tree.branch.get_commit_builder([],
136
                        revision_id=revision_id)
137
                except errors.NonAsciiRevisionId:
138
                    revision_id = 'abc'
139
                    builder = tree.branch.get_commit_builder([],
140
                        revision_id=revision_id)
6747.1.1 by Jelmer Vernooij
Remove unnecessary ExcludesUnsupported exception.
141
            except repository.CannotSetRevisionId:
3775.2.6 by Robert Collins
CommitBuilder can specify a revision_id with record_iter_changes.
142
                # This format doesn't support supplied revision ids
143
                return
144
            self.assertFalse(builder.random_revid)
145
            try:
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
146
                list(builder.record_iter_changes(tree, tree.last_revision(),
147
                    tree.iter_changes(tree.basis_tree())))
3775.2.6 by Robert Collins
CommitBuilder can specify a revision_id with record_iter_changes.
148
                builder.finish_inventory()
149
            except:
150
                builder.abort()
151
                raise
152
            self.assertEqual(revision_id, builder.commit('foo bar'))
153
        finally:
154
            tree.unlock()
155
        self.assertTrue(tree.branch.repository.has_revision(revision_id))
156
        # the revision id must be set on the inventory when saving it. This
157
        # does not precisely test that - a repository that wants to can add it
158
        # on deserialisation, but thats all the current contract guarantees
159
        # anyway.
160
        self.assertEqual(revision_id,
6113.1.4 by Jelmer Vernooij
Use revision_tree for testing, it's always present.
161
            tree.branch.repository.revision_tree(revision_id).get_revision_id())
3775.2.6 by Robert Collins
CommitBuilder can specify a revision_id with record_iter_changes.
162
5222.1.1 by Aaron Bentley
Refuse to commit trees with no root.
163
    def test_commit_without_root_errors(self):
164
        tree = self.make_branch_and_tree(".")
165
        tree.lock_write()
166
        try:
167
            builder = tree.branch.get_commit_builder([])
168
            def do_commit():
169
                try:
170
                    list(builder.record_iter_changes(
171
                        tree, tree.last_revision(), []))
172
                    builder.finish_inventory()
173
                except:
174
                    builder.abort()
175
                    raise
6202.2.1 by Jelmer Vernooij
Commit in commit builder test to prevent masking errors.
176
                else:
177
                    builder.commit("msg")
5222.1.1 by Aaron Bentley
Refuse to commit trees with no root.
178
            self.assertRaises(errors.RootMissing, do_commit)
179
        finally:
180
            tree.unlock()
181
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
182
    def test_commit_unchanged_root_record_iter_changes(self):
183
        tree = self.make_branch_and_tree(".")
184
        old_revision_id = tree.commit('')
185
        tree.lock_write()
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
186
        builder = tree.branch.get_commit_builder([old_revision_id])
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
187
        try:
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
188
            list(builder.record_iter_changes(tree, old_revision_id, []))
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
189
            # Regardless of repository root behaviour we should consider this a
190
            # pointless commit.
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
191
            self.assertFalse(builder.any_changes())
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
192
            builder.finish_inventory()
6362.5.5 by Jelmer Vernooij
Don't access revision tree before commit.
193
            builder.commit('')
5878.1.1 by Jelmer Vernooij
Avoid inventory usage in a commit builder test.
194
            builder_tree = builder.revision_tree()
195
            new_root_id = builder_tree.get_root_id()
196
            new_root_revision = builder_tree.get_file_revision(new_root_id)
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
197
            if tree.branch.repository.supports_rich_root():
198
                # We should not have seen a new root revision
5878.1.1 by Jelmer Vernooij
Avoid inventory usage in a commit builder test.
199
                self.assertEqual(old_revision_id, new_root_revision)
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
200
            else:
201
                # We should see a new root revision
5878.1.1 by Jelmer Vernooij
Avoid inventory usage in a commit builder test.
202
                self.assertNotEqual(old_revision_id, new_root_revision)
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
203
        finally:
204
            tree.unlock()
205
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
206
    def test_record_delete_record_iter_changes(self):
207
        tree = self.make_branch_and_tree(".")
208
        self.build_tree(["foo"])
6770.2.2 by Jelmer Vernooij
Avoid file ids.
209
        tree.add(["foo"])
210
        foo_id = tree.path2id('foo')
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
211
        rev_id = tree.commit("added foo")
212
        tree.lock_write()
213
        try:
214
            builder = tree.branch.get_commit_builder([rev_id])
215
            try:
6770.2.2 by Jelmer Vernooij
Avoid file ids.
216
                delete_change = (foo_id, ('foo', None), True, (True, False),
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
217
                    (tree.path2id(''), None), ('foo', None), ('file', None),
218
                    (False, None))
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
219
                list(builder.record_iter_changes(tree, rev_id,
220
                    [delete_change]))
6770.2.2 by Jelmer Vernooij
Avoid file ids.
221
                self.assertEqual(("foo", None, foo_id, None),
6437.12.2 by Jelmer Vernooij
Remove more uses of CommitBuilder._basis_delta.
222
                    builder.get_basis_delta()[0])
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
223
                self.assertTrue(builder.any_changes())
224
                builder.finish_inventory()
225
                rev_id2 = builder.commit('delete foo')
226
            except:
227
                builder.abort()
228
                raise
229
        finally:
230
            tree.unlock()
231
        rev_tree = builder.revision_tree()
232
        rev_tree.lock_read()
233
        self.addCleanup(rev_tree.unlock)
234
        self.assertFalse(rev_tree.path2id('foo'))
235
3775.2.10 by Robert Collins
CommitBuilder gives a revision tree when used with record_iter_contents.
236
    def test_revision_tree_record_iter_changes(self):
237
        tree = self.make_branch_and_tree(".")
238
        tree.lock_write()
239
        try:
240
            builder = tree.branch.get_commit_builder([])
241
            try:
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
242
                list(builder.record_iter_changes(tree,
243
                    _mod_revision.NULL_REVISION,
244
                    tree.iter_changes(tree.basis_tree())))
3775.2.10 by Robert Collins
CommitBuilder gives a revision tree when used with record_iter_contents.
245
                builder.finish_inventory()
246
                rev_id = builder.commit('foo bar')
247
            except:
248
                builder.abort()
249
                raise
250
            rev_tree = builder.revision_tree()
251
            # Just a couple simple tests to ensure that it actually follows
252
            # the RevisionTree api.
253
            self.assertEqual(rev_id, rev_tree.get_revision_id())
6072.1.1 by Jelmer Vernooij
Various fixes for tests of foreign plugins.
254
            self.assertEqual((), tuple(rev_tree.get_parent_ids()))
3775.2.10 by Robert Collins
CommitBuilder gives a revision tree when used with record_iter_contents.
255
        finally:
256
            tree.unlock()
257
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
258
    def test_root_entry_has_revision(self):
259
        # test the root revision created and put in the basis
260
        # has the right rev id.
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
261
        # XXX: RBC 20081118 - this test is too big, it depends on the exact
262
        # behaviour of tree methods and so on; it should be written to the
263
        # commit builder interface directly.
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
264
        tree = self.make_branch_and_tree('.')
265
        rev_id = tree.commit('message')
266
        basis_tree = tree.basis_tree()
267
        basis_tree.lock_read()
268
        self.addCleanup(basis_tree.unlock)
5819.2.4 by Jelmer Vernooij
Avoid using inventory.
269
        self.assertEqual(rev_id,
270
            basis_tree.get_file_revision(basis_tree.get_root_id()))
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
271
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
272
    def _get_revtrees(self, tree, revision_ids):
2592.3.214 by Robert Collins
Merge bzr.dev.
273
        tree.lock_read()
274
        try:
275
            trees = list(tree.branch.repository.revision_trees(revision_ids))
276
            for _tree in trees:
277
                _tree.lock_read()
278
                self.addCleanup(_tree.unlock)
279
            return trees
280
        finally:
281
            tree.unlock()
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
282
283
    def test_last_modified_revision_after_commit_root_unchanged(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
284
        # commiting without changing the root does not change the
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
285
        # last modified except on non-rich-root-repositories.
286
        tree = self.make_branch_and_tree('.')
287
        rev1 = tree.commit('')
288
        rev2 = tree.commit('')
289
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
5819.2.4 by Jelmer Vernooij
Avoid using inventory.
290
        self.assertEqual(rev1, tree1.get_file_revision(tree1.get_root_id()))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
291
        if tree.branch.repository.supports_rich_root():
5819.2.4 by Jelmer Vernooij
Avoid using inventory.
292
            self.assertEqual(rev1,
293
                tree2.get_file_revision(tree2.get_root_id()))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
294
        else:
5819.2.4 by Jelmer Vernooij
Avoid using inventory.
295
            self.assertEqual(rev2,
296
                tree2.get_file_revision(tree2.get_root_id()))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
297
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
298
    def _add_commit_check_unchanged(self, tree, name, mini_commit=None):
6770.2.3 by Jelmer Vernooij
Fix file ids.
299
        tree.add([name])
300
        self._commit_check_unchanged(tree, name, tree.path2id(name),
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
301
            mini_commit=mini_commit)
302
303
    def _commit_check_unchanged(self, tree, name, file_id, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
304
        rev1 = tree.commit('')
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
305
        rev2 = mini_commit(tree, name, name, False, False)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
306
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
5793.2.3 by Jelmer Vernooij
Add a RevisionTree.get_file_revision() method.
307
        self.assertEqual(rev1, tree1.get_file_revision(file_id))
308
        self.assertEqual(rev1, tree2.get_file_revision(file_id))
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
309
        expected_graph = {}
310
        expected_graph[(file_id, rev1)] = ()
311
        self.assertFileGraph(expected_graph, tree, (file_id, rev1))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
312
313
    def test_last_modified_revision_after_commit_dir_unchanged(self):
314
        # committing without changing a dir does not change the last modified.
315
        tree = self.make_branch_and_tree('.')
316
        self.build_tree(['dir/'])
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
317
        self._add_commit_check_unchanged(tree, 'dir',
318
            mini_commit=self.mini_commit_record_iter_changes)
319
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
320
    def test_last_modified_revision_after_commit_dir_contents_unchanged(self):
321
        # committing without changing a dir does not change the last modified
322
        # of the dir even the dirs contents are changed.
323
        tree = self.make_branch_and_tree('.')
324
        self.build_tree(['dir/'])
6770.2.4 by Jelmer Vernooij
Fix remaining test.
325
        tree.add(['dir'])
326
        dir_id = tree.path2id('dir')
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
327
        rev1 = tree.commit('')
328
        self.build_tree(['dir/content'])
6770.2.4 by Jelmer Vernooij
Fix remaining test.
329
        tree.add(['dir/content'])
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
330
        rev2 = tree.commit('')
331
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
6770.2.4 by Jelmer Vernooij
Fix remaining test.
332
        self.assertEqual(rev1, tree1.get_file_revision(dir_id))
333
        self.assertEqual(rev1, tree2.get_file_revision(dir_id))
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
334
        expected_graph = {}
6770.2.4 by Jelmer Vernooij
Fix remaining test.
335
        expected_graph[(dir_id, rev1)] = ()
336
        self.assertFileGraph(expected_graph, tree, (dir_id, rev1))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
337
338
    def test_last_modified_revision_after_commit_file_unchanged(self):
339
        # committing without changing a file does not change the last modified.
340
        tree = self.make_branch_and_tree('.')
341
        self.build_tree(['file'])
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
342
        self._add_commit_check_unchanged(tree, 'file',
343
            mini_commit=self.mini_commit_record_iter_changes)
344
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
345
    def test_last_modified_revision_after_commit_link_unchanged(self):
346
        # committing without changing a link does not change the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
347
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
348
        tree = self.make_branch_and_tree('.')
349
        os.symlink('target', 'link')
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
350
        self._add_commit_check_unchanged(tree, 'link',
351
            mini_commit=self.mini_commit_record_iter_changes)
352
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
353
    def test_last_modified_revision_after_commit_reference_unchanged(self):
354
        # committing without changing a subtree does not change the last
355
        # modified.
356
        tree = self.make_branch_and_tree('.')
357
        subtree = self.make_reference('reference')
358
        try:
359
            tree.add_reference(subtree)
360
            self._commit_check_unchanged(tree, 'reference',
361
                subtree.get_root_id(),
362
                mini_commit=self.mini_commit_record_iter_changes)
363
        except errors.UnsupportedOperation:
364
            return
365
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
366
    def _add_commit_renamed_check_changed(self, tree, name,
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
367
        expect_fs_hash=False, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
368
        def rename():
369
            tree.rename_one(name, 'new_' + name)
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
370
        self._add_commit_change_check_changed(tree, name, rename,
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
371
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
372
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
373
    def _commit_renamed_check_changed(self, tree, name, file_id,
374
        expect_fs_hash=False, mini_commit=None):
375
        def rename():
376
            tree.rename_one(name, 'new_' + name)
377
        self._commit_change_check_changed(tree, name, file_id, rename,
378
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
379
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
380
    def test_last_modified_revision_after_rename_dir_changes(self):
381
        # renaming a dir changes the last modified.
382
        tree = self.make_branch_and_tree('.')
383
        self.build_tree(['dir/'])
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
384
        self._add_commit_renamed_check_changed(tree, 'dir',
385
            mini_commit=self.mini_commit_record_iter_changes)
386
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
387
    def test_last_modified_revision_after_rename_file_changes(self):
388
        # renaming a file changes the last modified.
389
        tree = self.make_branch_and_tree('.')
390
        self.build_tree(['file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
391
        self._add_commit_renamed_check_changed(tree, 'file',
3775.2.12 by Robert Collins
CommitBuilder.record_iter_changes handles renamed files.
392
            expect_fs_hash=True,
393
            mini_commit=self.mini_commit_record_iter_changes)
394
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
395
    def test_last_modified_revision_after_rename_link_changes(self):
396
        # renaming a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
397
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
398
        tree = self.make_branch_and_tree('.')
399
        os.symlink('target', 'link')
3775.2.13 by Robert Collins
CommitBuilder.record_iter_changes handles renamed symlinks.
400
        self._add_commit_renamed_check_changed(tree, 'link',
401
            mini_commit=self.mini_commit_record_iter_changes)
402
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
403
    def test_last_modified_revision_after_rename_ref_changes(self):
404
        # renaming a reference changes the last modified.
405
        tree = self.make_branch_and_tree('.')
406
        subtree = self.make_reference('reference')
407
        try:
408
            tree.add_reference(subtree)
409
            self._commit_renamed_check_changed(tree, 'reference',
410
                subtree.get_root_id(),
411
                mini_commit=self.mini_commit_record_iter_changes)
412
        except errors.UnsupportedOperation:
413
            return
414
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
415
    def _add_commit_reparent_check_changed(self, tree, name,
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
416
        expect_fs_hash=False, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
417
        self.build_tree(['newparent/'])
418
        tree.add(['newparent'])
419
        def reparent():
420
            tree.rename_one(name, 'newparent/new_' + name)
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
421
        self._add_commit_change_check_changed(tree, name, reparent,
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
422
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
423
424
    def test_last_modified_revision_after_reparent_dir_changes(self):
425
        # reparenting a dir changes the last modified.
426
        tree = self.make_branch_and_tree('.')
427
        self.build_tree(['dir/'])
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
428
        self._add_commit_reparent_check_changed(tree, 'dir',
429
            mini_commit=self.mini_commit_record_iter_changes)
430
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
431
    def test_last_modified_revision_after_reparent_file_changes(self):
432
        # reparenting a file changes the last modified.
433
        tree = self.make_branch_and_tree('.')
434
        self.build_tree(['file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
435
        self._add_commit_reparent_check_changed(tree, 'file',
3775.2.17 by Robert Collins
CommitBuilder.record_iter_changes handles changed files.
436
            expect_fs_hash=True,
437
            mini_commit=self.mini_commit_record_iter_changes)
3775.2.15 by Robert Collins
CommitBuilder.record_iter_changes handles reparented files.
438
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
439
    def test_last_modified_revision_after_reparent_link_changes(self):
440
        # reparenting a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
441
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
442
        tree = self.make_branch_and_tree('.')
443
        os.symlink('target', 'link')
3775.2.16 by Robert Collins
CommitBuilder.record_iter_changes handles reparented symlinks.
444
        self._add_commit_reparent_check_changed(tree, 'link',
445
            mini_commit=self.mini_commit_record_iter_changes)
446
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
447
    def _add_commit_change_check_changed(self, tree, name, changer,
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
448
            expect_fs_hash=False, mini_commit=None):
449
        tree.add([name])
450
        file_id = tree.path2id(name)
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
451
        self._commit_change_check_changed(
452
            tree, name, file_id,
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
453
            changer, expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
454
4183.5.3 by Robert Collins
Fix typo.
455
    def _commit_change_check_changed(self, tree, name, file_id, changer,
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
456
        expect_fs_hash=False, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
457
        rev1 = tree.commit('')
458
        changer()
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
459
        rev2 = mini_commit(tree, name, tree.id2path(file_id),
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
460
            expect_fs_hash=expect_fs_hash)
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
461
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
5793.2.3 by Jelmer Vernooij
Add a RevisionTree.get_file_revision() method.
462
        self.assertEqual(rev1, tree1.get_file_revision(file_id))
463
        self.assertEqual(rev2, tree2.get_file_revision(file_id))
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
464
        expected_graph = {}
465
        expected_graph[(file_id, rev1)] = ()
466
        expected_graph[(file_id, rev2)] = ((file_id, rev1),)
467
        self.assertFileGraph(expected_graph, tree, (file_id, rev2))
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
468
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
469
    def mini_commit_record_iter_changes(self, tree, name, new_name,
470
        records_version=True, delta_against_basis=True, expect_fs_hash=False):
471
        """Perform a miniature commit looking for record entry results.
472
473
        This version uses the record_iter_changes interface.
474
        
475
        :param tree: The tree to commit.
476
        :param name: The path in the basis tree of the tree being committed.
477
        :param new_name: The path in the tree being committed.
478
        :param records_version: True if the commit of new_name is expected to
479
            record a new version.
480
        :param delta_against_basis: True of the commit of new_name is expected
481
            to have a delta against the basis.
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
482
        :param expect_fs_hash: If true, looks for a fs hash output from
483
            record_iter_changes.
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
484
        """
485
        tree.lock_write()
486
        try:
487
            # mini manual commit here so we can check the return of
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
488
            # record_iter_changes
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
489
            parent_ids = tree.get_parent_ids()
490
            builder = tree.branch.get_commit_builder(parent_ids)
491
            parent_tree = tree.basis_tree()
492
            parent_tree.lock_read()
493
            self.addCleanup(parent_tree.unlock)
5856.1.2 by Jelmer Vernooij
Delay accessing inventory in tests until necessary.
494
            parent_trees = [parent_tree]
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
495
            for parent_id in parent_ids[1:]:
5856.1.2 by Jelmer Vernooij
Delay accessing inventory in tests until necessary.
496
                parent_trees.append(tree.branch.repository.revision_tree(
497
                    parent_id))
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
498
            changes = list(tree.iter_changes(parent_tree))
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
499
            result = list(builder.record_iter_changes(tree, parent_ids[0],
500
                changes))
501
            file_id = tree.path2id(new_name)
502
            if expect_fs_hash:
503
                tree_file_stat = tree.get_file_with_stat(file_id)
504
                tree_file_stat[0].close()
505
                self.assertLength(1, result)
506
                result = result[0]
507
                self.assertEqual(result[:2], (file_id, new_name))
508
                self.assertEqual(result[2][0], tree.get_file_sha1(file_id))
509
                self.assertEqualStat(result[2][1], tree_file_stat[1])
510
            else:
511
                self.assertEqual([], result)
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
512
            builder.finish_inventory()
5718.4.4 by Jelmer Vernooij
Only check .inventories if present.
513
            if tree.branch.repository._format.supports_full_versioned_files:
514
                inv_key = (builder._new_revision_id,)
515
                inv_sha1 = tree.branch.repository.inventories.get_sha1s(
516
                                [inv_key])[inv_key]
517
                self.assertEqual(inv_sha1, builder.inv_sha1)
6362.5.5 by Jelmer Vernooij
Don't access revision tree before commit.
518
            rev2 = builder.commit('')
6437.12.1 by Jelmer Vernooij
Use CommitBuilder.get_basis_delta rather than private CommitBuilder._basis_delta.
519
            delta = builder.get_basis_delta()
520
            delta_dict = dict((change[2], change) for change in delta)
521
            version_recorded = (file_id in delta_dict and
522
                delta_dict[file_id][3] is not None and
523
                delta_dict[file_id][3].revision == rev2)
524
            if records_version:
525
                self.assertTrue(version_recorded)
526
            else:
527
                self.assertFalse(version_recorded)
528
6405.2.6 by Jelmer Vernooij
Lots of test fixes.
529
            new_inventory = builder.revision_tree().root_inventory
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
530
            new_entry = new_inventory[file_id]
531
            if delta_against_basis:
532
                expected_delta = (name, new_name, file_id, new_entry)
533
                self.assertEqual(expected_delta, delta_dict[file_id])
534
            else:
535
                expected_delta = None
536
                self.assertFalse(version_recorded)
537
            tree.set_parent_ids([rev2])
538
        except:
539
            builder.abort()
540
            tree.unlock()
541
            raise
542
        else:
543
            tree.unlock()
544
        return rev2
545
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
546
    def assertFileGraph(self, expected_graph, tree, tip):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
547
        # all the changes that have occured should be in the ancestry
548
        # (closest to a public per-file graph API we have today)
549
        tree.lock_read()
550
        self.addCleanup(tree.unlock)
5815.5.9 by Jelmer Vernooij
Remove dependencies on texts.
551
        g = dict(tree.branch.repository.get_file_graph().iter_ancestry([tip]))
5010.2.24 by Vincent Ladeuil
Fix imports in per_repository/test_commit_builder.py.
552
        self.assertEqual(expected_graph, g)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
553
554
    def test_last_modified_revision_after_content_file_changes(self):
555
        # altering a file changes the last modified.
556
        tree = self.make_branch_and_tree('.')
557
        self.build_tree(['file'])
558
        def change_file():
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
559
            tree.put_file_bytes_non_atomic(tree.path2id('file'), 'new content')
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
560
        self._add_commit_change_check_changed(tree, 'file', change_file,
3775.2.17 by Robert Collins
CommitBuilder.record_iter_changes handles changed files.
561
            expect_fs_hash=True,
562
            mini_commit=self.mini_commit_record_iter_changes)
563
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
564
    def _test_last_mod_rev_after_content_link_changes(
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
565
        self, link, target, newtarget):
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
566
        # changing a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
567
        self.requireFeature(features.SymlinkFeature)
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
568
        tree = self.make_branch_and_tree('.')
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
569
        os.symlink(target, link)
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
570
        def change_link():
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
571
            os.unlink(link)
572
            os.symlink(newtarget, link)
573
        self._add_commit_change_check_changed(
574
            tree, link, change_link,
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
575
            mini_commit=self.mini_commit_record_iter_changes)
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
576
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
577
    def test_last_modified_rev_after_content_link_changes(self):
578
        self._test_last_mod_rev_after_content_link_changes(
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
579
            'link', 'target', 'newtarget')
580
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
581
    def test_last_modified_rev_after_content_unicode_link_changes(self):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
582
        self.requireFeature(features.UnicodeFilenameFeature)
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
583
        self._test_last_mod_rev_after_content_link_changes(
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
584
            u'li\u1234nk', u'targ\N{Euro Sign}t', u'n\N{Euro Sign}wtarget')
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
585
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
586
    def _commit_sprout(self, tree, name):
6770.2.3 by Jelmer Vernooij
Fix file ids.
587
        tree.add([name])
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
588
        rev_id = tree.commit('')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
589
        return rev_id, tree.controldir.sprout('t2').open_workingtree()
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
590
591
    def _rename_in_tree(self, tree, name):
592
        tree.rename_one(name, 'new_' + name)
593
        return tree.commit('')
594
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
595
    def _commit_sprout_rename_merge(self, tree1, name, expect_fs_hash=False,
596
        mini_commit=None):
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
597
        """Do a rename in both trees."""
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
598
        rev1, tree2 = self._commit_sprout(tree1, name)
6770.2.3 by Jelmer Vernooij
Fix file ids.
599
        file_id = tree2.path2id(name)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
600
        # change both sides equally
601
        rev2 = self._rename_in_tree(tree1, name)
602
        rev3 = self._rename_in_tree(tree2, name)
603
        tree1.merge_from_branch(tree2.branch)
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
604
        rev4 = mini_commit(tree1, 'new_' + name, 'new_' + name,
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
605
            expect_fs_hash=expect_fs_hash)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
606
        tree3, = self._get_revtrees(tree1, [rev4])
6770.2.3 by Jelmer Vernooij
Fix file ids.
607
        self.assertEqual(rev4, tree3.get_file_revision(file_id))
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
608
        expected_graph = {}
609
        expected_graph[(file_id, rev1)] = ()
610
        expected_graph[(file_id, rev2)] = ((file_id, rev1),)
611
        expected_graph[(file_id, rev3)] = ((file_id, rev1),)
612
        expected_graph[(file_id, rev4)] = ((file_id, rev2), (file_id, rev3),)
613
        self.assertFileGraph(expected_graph, tree1, (file_id, rev4))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
614
615
    def test_last_modified_revision_after_merge_dir_changes(self):
616
        # merge a dir changes the last modified.
617
        tree1 = self.make_branch_and_tree('t1')
618
        self.build_tree(['t1/dir/'])
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
619
        self._commit_sprout_rename_merge(tree1, 'dir',
620
            mini_commit=self.mini_commit_record_iter_changes)
621
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
622
    def test_last_modified_revision_after_merge_file_changes(self):
623
        # merge a file changes the last modified.
624
        tree1 = self.make_branch_and_tree('t1')
625
        self.build_tree(['t1/file'])
3775.2.20 by Robert Collins
CommitBuilder.record_iter_changes handles merged files.
626
        self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True,
627
            mini_commit=self.mini_commit_record_iter_changes)
628
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
629
    def test_last_modified_revision_after_merge_link_changes(self):
630
        # merge a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
631
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
632
        tree1 = self.make_branch_and_tree('t1')
633
        os.symlink('target', 't1/link')
3775.2.21 by Robert Collins
CommitBuilder.record_iter_changes handles merged symlinks.
634
        self._commit_sprout_rename_merge(tree1, 'link',
635
            mini_commit=self.mini_commit_record_iter_changes)
636
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
637
    def _commit_sprout_rename_merge_converged(self, tree1, name,
638
        mini_commit=None):
639
        # Make a merge which just incorporates a change from a branch:
640
        # The per-file graph is straight line, and no alteration occurs
641
        # in the inventory.
4183.5.9 by Robert Collins
Fix creating new revisions of files when merging.
642
        # Part 1: change in the merged branch.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
643
        rev1, tree2 = self._commit_sprout(tree1, name)
6770.2.3 by Jelmer Vernooij
Fix file ids.
644
        file_id = tree2.path2id(name)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
645
        # change on the other side to merge back
646
        rev2 = self._rename_in_tree(tree2, name)
647
        tree1.merge_from_branch(tree2.branch)
4183.5.9 by Robert Collins
Fix creating new revisions of files when merging.
648
        def _check_graph(in_tree, changed_in_tree):
649
            rev3 = mini_commit(in_tree, name, 'new_' + name, False,
650
                delta_against_basis=changed_in_tree)
651
            tree3, = self._get_revtrees(in_tree, [rev2])
6770.2.3 by Jelmer Vernooij
Fix file ids.
652
            self.assertEqual(rev2, tree3.get_file_revision(file_id))
4183.5.9 by Robert Collins
Fix creating new revisions of files when merging.
653
            expected_graph = {}
654
            expected_graph[(file_id, rev1)] = ()
655
            expected_graph[(file_id, rev2)] = ((file_id, rev1),)
656
            self.assertFileGraph(expected_graph, in_tree, (file_id, rev2))
657
        _check_graph(tree1, True)
658
        # Part 2: change in the merged into branch - we use tree2 that has a
659
        # change to name, branch tree1 and give it an unrelated change, then
660
        # merge that to t2.
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
661
        other_tree = tree1.controldir.sprout('t3').open_workingtree()
4183.5.9 by Robert Collins
Fix creating new revisions of files when merging.
662
        other_rev = other_tree.commit('')
663
        tree2.merge_from_branch(other_tree.branch)
664
        _check_graph(tree2, False)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
665
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
666
    def _commit_sprout_make_merge(self, tree1, make, mini_commit=None):
667
        # Make a merge which incorporates the addition of a new object to
668
        # another branch. The per-file graph shows no additional change
669
        # in the merge because its a straight line.
670
        rev1 = tree1.commit('')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
671
        tree2 = tree1.controldir.sprout('t2').open_workingtree()
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
672
        # make and commit on the other side to merge back
673
        make('t2/name')
6770.2.2 by Jelmer Vernooij
Avoid file ids.
674
        tree2.add(['name'])
675
        file_id = tree2.path2id('name')
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
676
        rev2 = tree2.commit('')
677
        tree1.merge_from_branch(tree2.branch)
678
        rev3 = mini_commit(tree1, None, 'name', False)
679
        tree3, = self._get_revtrees(tree1, [rev2])
680
        # in rev2, name should be only changed in rev2
5793.2.3 by Jelmer Vernooij
Add a RevisionTree.get_file_revision() method.
681
        self.assertEqual(rev2, tree3.get_file_revision(file_id))
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
682
        expected_graph = {}
683
        expected_graph[(file_id, rev2)] = ()
684
        self.assertFileGraph(expected_graph, tree1, (file_id, rev2))
685
686
    def test_last_modified_revision_after_converged_merge_dir_unchanged(self):
687
        # merge a dir that changed preserves the last modified.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
688
        tree1 = self.make_branch_and_tree('t1')
689
        self.build_tree(['t1/dir/'])
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
690
        self._commit_sprout_rename_merge_converged(tree1, 'dir',
691
            mini_commit=self.mini_commit_record_iter_changes)
692
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
693
    def test_last_modified_revision_after_converged_merge_file_unchanged(self):
694
        # merge a file that changed preserves the last modified.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
695
        tree1 = self.make_branch_and_tree('t1')
696
        self.build_tree(['t1/file'])
3775.2.23 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch files.
697
        self._commit_sprout_rename_merge_converged(tree1, 'file',
698
            mini_commit=self.mini_commit_record_iter_changes)
699
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
700
    def test_last_modified_revision_after_converged_merge_link_unchanged(self):
701
        # merge a link that changed preserves the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
702
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
703
        tree1 = self.make_branch_and_tree('t1')
704
        os.symlink('target', 't1/link')
3775.2.24 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch symlinks.
705
        self._commit_sprout_rename_merge_converged(tree1, 'link',
706
            mini_commit=self.mini_commit_record_iter_changes)
707
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
708
    def test_last_modified_revision_after_merge_new_dir_unchanged(self):
709
        # merge a new dir does not change the last modified.
710
        tree1 = self.make_branch_and_tree('t1')
711
        self._commit_sprout_make_merge(tree1, self.make_dir,
712
            mini_commit=self.mini_commit_record_iter_changes)
713
714
    def test_last_modified_revision_after_merge_new_file_unchanged(self):
715
        # merge a new file does not change the last modified.
716
        tree1 = self.make_branch_and_tree('t1')
717
        self._commit_sprout_make_merge(tree1, self.make_file,
718
            mini_commit=self.mini_commit_record_iter_changes)
719
720
    def test_last_modified_revision_after_merge_new_link_unchanged(self):
721
        # merge a new link does not change the last modified.
722
        tree1 = self.make_branch_and_tree('t1')
723
        self._commit_sprout_make_merge(tree1, self.make_link,
724
            mini_commit=self.mini_commit_record_iter_changes)
725
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
726
    def make_dir(self, name):
727
        self.build_tree([name + '/'])
728
729
    def make_file(self, name):
730
        self.build_tree([name])
731
732
    def make_link(self, name):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
733
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
734
        os.symlink('target', name)
735
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
736
    def make_reference(self, name):
737
        tree = self.make_branch_and_tree(name, format='1.9-rich-root')
738
        tree.commit('foo')
739
        return tree
740
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
741
    def _check_kind_change(self, make_before, make_after, expect_fs_hash=False,
742
        mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
743
        tree = self.make_branch_and_tree('.')
744
        path = 'name'
745
        make_before(path)
2831.5.2 by Vincent Ladeuil
Review feedback.
746
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
747
        def change_kind():
6164.2.3 by Jelmer Vernooij
Use rmtree, since some vcses include control directories in every directory.
748
            if osutils.file_kind(path) == "directory":
749
                osutils.rmtree(path)
750
            else:
751
                osutils.delete_any(path)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
752
            make_after(path)
2831.5.2 by Vincent Ladeuil
Review feedback.
753
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
754
        self._add_commit_change_check_changed(tree, path, change_kind,
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
755
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
756
757
    def test_last_modified_dir_file(self):
6217.2.1 by Jelmer Vernooij
Allow tree implementations to not support kind changes.
758
        try:
759
            self._check_kind_change(self.make_dir, self.make_file,
760
                expect_fs_hash=True,
761
                mini_commit=self.mini_commit_record_iter_changes)
762
        except errors.UnsupportedKindChange:
763
            raise tests.TestSkipped(
764
                "tree does not support changing entry kind from "
765
                "directory to file")
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
766
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
767
    def test_last_modified_dir_link(self):
6217.2.1 by Jelmer Vernooij
Allow tree implementations to not support kind changes.
768
        try:
769
            self._check_kind_change(self.make_dir, self.make_link,
770
                mini_commit=self.mini_commit_record_iter_changes)
771
        except errors.UnsupportedKindChange:
772
            raise tests.TestSkipped(
773
                "tree does not support changing entry kind from "
774
                "directory to link")
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
775
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
776
    def test_last_modified_link_file(self):
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
777
        self._check_kind_change(self.make_link, self.make_file,
3775.2.26 by Robert Collins
CommitBuilder.record_iter_changes handles links becomes directories and files.
778
            expect_fs_hash=True,
779
            mini_commit=self.mini_commit_record_iter_changes)
780
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
781
    def test_last_modified_link_dir(self):
3775.2.26 by Robert Collins
CommitBuilder.record_iter_changes handles links becomes directories and files.
782
        self._check_kind_change(self.make_link, self.make_dir,
783
            mini_commit=self.mini_commit_record_iter_changes)
784
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
785
    def test_last_modified_file_dir(self):
3775.2.27 by Robert Collins
CommitBuilder.record_iter_changes handles files becoming directories and links.
786
        self._check_kind_change(self.make_file, self.make_dir,
787
            mini_commit=self.mini_commit_record_iter_changes)
788
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
789
    def test_last_modified_file_link(self):
3775.2.27 by Robert Collins
CommitBuilder.record_iter_changes handles files becoming directories and links.
790
        self._check_kind_change(self.make_file, self.make_link,
791
            mini_commit=self.mini_commit_record_iter_changes)
3775.2.28 by Robert Collins
Merge .dev.
792
3831.1.1 by John Arbash Meinel
Before allowing commit to succeed, verify the texts will be 'safe'.
793
    def test_get_commit_builder_with_invalid_revprops(self):
794
        branch = self.make_branch('.')
795
        branch.repository.lock_write()
796
        self.addCleanup(branch.repository.unlock)
797
        self.assertRaises(ValueError, branch.repository.get_commit_builder,
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
798
            branch, [], branch.get_config_stack(),
3831.1.1 by John Arbash Meinel
Before allowing commit to succeed, verify the texts will be 'safe'.
799
            revprops={'invalid': u'property\rwith\r\ninvalid chars'})
800
801
    def test_commit_builder_commit_with_invalid_message(self):
802
        branch = self.make_branch('.')
803
        branch.repository.lock_write()
804
        self.addCleanup(branch.repository.unlock)
805
        builder = branch.repository.get_commit_builder(branch, [],
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
806
            branch.get_config_stack())
3831.1.1 by John Arbash Meinel
Before allowing commit to succeed, verify the texts will be 'safe'.
807
        self.addCleanup(branch.repository.abort_write_group)
808
        self.assertRaises(ValueError, builder.commit,
809
            u'Invalid\r\ncommit message\r\n')
4595.4.2 by Robert Collins
Disable commit builders on stacked repositories.
810
5485.4.2 by Martin
Move guard to CommitBuilder.__init__ and test to bt.per_repository
811
    def test_non_ascii_str_committer_rejected(self):
812
        """Ensure an error is raised on a non-ascii byte string committer"""
813
        branch = self.make_branch('.')
814
        branch.repository.lock_write()
815
        self.addCleanup(branch.repository.unlock)
816
        self.assertRaises(UnicodeDecodeError,
817
            branch.repository.get_commit_builder,
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
818
            branch, [], branch.get_config_stack(),
5485.4.2 by Martin
Move guard to CommitBuilder.__init__ and test to bt.per_repository
819
            committer="Erik B\xe5gfors <erik@example.com>")
820
4595.4.2 by Robert Collins
Disable commit builders on stacked repositories.
821
    def test_stacked_repositories_reject_commit_builder(self):
822
        # As per bug 375013, committing to stacked repositories is currently
5557.1.17 by John Arbash Meinel
Fix the test case that was checking we refused to create a commit_builder
823
        # broken if we aren't in a chk repository. So old repositories with
824
        # fallbacks refuse to hand out a commit builder.
4595.4.2 by Robert Collins
Disable commit builders on stacked repositories.
825
        repo_basis = self.make_repository('basis')
826
        branch = self.make_branch('local')
827
        repo_local = branch.repository
828
        try:
829
            repo_local.add_fallback_repository(repo_basis)
830
        except errors.UnstackableRepositoryFormat:
831
            raise tests.TestNotApplicable("not a stackable format.")
5557.1.17 by John Arbash Meinel
Fix the test case that was checking we refused to create a commit_builder
832
        self.addCleanup(repo_local.lock_write().unlock)
833
        if not repo_local._format.supports_chks:
834
            self.assertRaises(errors.BzrError, repo_local.get_commit_builder,
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
835
                branch, [], branch.get_config_stack())
5557.1.17 by John Arbash Meinel
Fix the test case that was checking we refused to create a commit_builder
836
        else:
837
            builder = repo_local.get_commit_builder(branch, [],
6351.3.3 by Jelmer Vernooij
Convert more stuff to use config stacks.
838
                                                    branch.get_config_stack())
5557.1.17 by John Arbash Meinel
Fix the test case that was checking we refused to create a commit_builder
839
            builder.abort()
5050.18.1 by Aaron Bentley
CommitBuilder user committer, not username in revision-id.
840
841
    def test_committer_no_username(self):
842
        # Ensure that when no username is available but a committer is
843
        # supplied, commit works.
5570.3.9 by Vincent Ladeuil
More use cases for overrideEnv, _cleanEnvironment *may* contain too much variables now.
844
        self.overrideEnv('EMAIL', None)
6622.1.28 by Jelmer Vernooij
More renames; commands in output, environment variables.
845
        self.overrideEnv('BRZ_EMAIL', None)
5609.31.2 by mbp at sourcefrog
Also turn off whoami inference in per_repository tests
846
        # Also, make sure that it's not inferred from mailname.
847
        self.overrideAttr(config, '_auto_user_id',
848
            lambda: (None, None))
5050.18.1 by Aaron Bentley
CommitBuilder user committer, not username in revision-id.
849
        tree = self.make_branch_and_tree(".")
850
        tree.lock_write()
851
        try:
852
            # Make sure no username is available.
6737 by Jelmer Vernooij
Merge lp:~jelmer/brz/move-errors-config.
853
            self.assertRaises(config.NoWhoami, tree.branch.get_commit_builder,
5050.18.1 by Aaron Bentley
CommitBuilder user committer, not username in revision-id.
854
                              [])
855
            builder = tree.branch.get_commit_builder(
856
                [], committer='me@example.com')
857
            try:
858
                list(builder.record_iter_changes(tree, tree.last_revision(),
859
                    tree.iter_changes(tree.basis_tree())))
860
                builder.finish_inventory()
861
            except:
862
                builder.abort()
863
                raise
864
            repo = tree.branch.repository
865
            repo.commit_write_group()
866
        finally:
867
            tree.unlock()