/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()
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
196
            new_root_revision = builder_tree.get_file_revision(u'')
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,
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
270
            basis_tree.get_file_revision(u'', 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])
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
290
        self.assertEqual(rev1, tree1.get_file_revision(u''))
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():
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
292
            self.assertEqual(rev1,tree2.get_file_revision(u''))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
293
        else:
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
294
            self.assertEqual(rev2, tree2.get_file_revision(u''))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
295
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
296
    def _add_commit_check_unchanged(self, tree, name, mini_commit=None):
6770.2.3 by Jelmer Vernooij
Fix file ids.
297
        tree.add([name])
298
        self._commit_check_unchanged(tree, name, tree.path2id(name),
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
299
            mini_commit=mini_commit)
300
301
    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.
302
        rev1 = tree.commit('')
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
303
        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.
304
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
305
        self.assertEqual(rev1, tree1.get_file_revision(tree1.id2path(file_id)))
306
        self.assertEqual(rev1, tree2.get_file_revision(tree2.id2path(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.
307
        expected_graph = {}
308
        expected_graph[(file_id, rev1)] = ()
309
        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.
310
311
    def test_last_modified_revision_after_commit_dir_unchanged(self):
312
        # committing without changing a dir does not change the last modified.
313
        tree = self.make_branch_and_tree('.')
314
        self.build_tree(['dir/'])
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
315
        self._add_commit_check_unchanged(tree, 'dir',
316
            mini_commit=self.mini_commit_record_iter_changes)
317
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
318
    def test_last_modified_revision_after_commit_dir_contents_unchanged(self):
319
        # committing without changing a dir does not change the last modified
320
        # of the dir even the dirs contents are changed.
321
        tree = self.make_branch_and_tree('.')
322
        self.build_tree(['dir/'])
6770.2.4 by Jelmer Vernooij
Fix remaining test.
323
        tree.add(['dir'])
324
        dir_id = tree.path2id('dir')
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
325
        rev1 = tree.commit('')
326
        self.build_tree(['dir/content'])
6770.2.4 by Jelmer Vernooij
Fix remaining test.
327
        tree.add(['dir/content'])
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
328
        rev2 = tree.commit('')
329
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
330
        self.assertEqual(rev1, tree1.get_file_revision('dir'))
331
        self.assertEqual(rev1, tree2.get_file_revision('dir'))
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.
332
        expected_graph = {}
6770.2.4 by Jelmer Vernooij
Fix remaining test.
333
        expected_graph[(dir_id, rev1)] = ()
334
        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.
335
336
    def test_last_modified_revision_after_commit_file_unchanged(self):
337
        # committing without changing a file does not change the last modified.
338
        tree = self.make_branch_and_tree('.')
339
        self.build_tree(['file'])
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
340
        self._add_commit_check_unchanged(tree, 'file',
341
            mini_commit=self.mini_commit_record_iter_changes)
342
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
343
    def test_last_modified_revision_after_commit_link_unchanged(self):
344
        # 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
345
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
346
        tree = self.make_branch_and_tree('.')
347
        os.symlink('target', 'link')
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
348
        self._add_commit_check_unchanged(tree, 'link',
349
            mini_commit=self.mini_commit_record_iter_changes)
350
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
351
    def test_last_modified_revision_after_commit_reference_unchanged(self):
352
        # committing without changing a subtree does not change the last
353
        # modified.
354
        tree = self.make_branch_and_tree('.')
355
        subtree = self.make_reference('reference')
356
        try:
357
            tree.add_reference(subtree)
358
            self._commit_check_unchanged(tree, 'reference',
359
                subtree.get_root_id(),
360
                mini_commit=self.mini_commit_record_iter_changes)
361
        except errors.UnsupportedOperation:
362
            return
363
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
364
    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.
365
        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.
366
        def rename():
367
            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.
368
        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.
369
            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.
370
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
371
    def _commit_renamed_check_changed(self, tree, name, file_id,
372
        expect_fs_hash=False, mini_commit=None):
373
        def rename():
374
            tree.rename_one(name, 'new_' + name)
375
        self._commit_change_check_changed(tree, name, file_id, rename,
376
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
377
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
378
    def test_last_modified_revision_after_rename_dir_changes(self):
379
        # renaming a dir changes the last modified.
380
        tree = self.make_branch_and_tree('.')
381
        self.build_tree(['dir/'])
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
382
        self._add_commit_renamed_check_changed(tree, 'dir',
383
            mini_commit=self.mini_commit_record_iter_changes)
384
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
385
    def test_last_modified_revision_after_rename_file_changes(self):
386
        # renaming a file changes the last modified.
387
        tree = self.make_branch_and_tree('.')
388
        self.build_tree(['file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
389
        self._add_commit_renamed_check_changed(tree, 'file',
3775.2.12 by Robert Collins
CommitBuilder.record_iter_changes handles renamed files.
390
            expect_fs_hash=True,
391
            mini_commit=self.mini_commit_record_iter_changes)
392
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
393
    def test_last_modified_revision_after_rename_link_changes(self):
394
        # renaming a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
395
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
396
        tree = self.make_branch_and_tree('.')
397
        os.symlink('target', 'link')
3775.2.13 by Robert Collins
CommitBuilder.record_iter_changes handles renamed symlinks.
398
        self._add_commit_renamed_check_changed(tree, 'link',
399
            mini_commit=self.mini_commit_record_iter_changes)
400
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
401
    def test_last_modified_revision_after_rename_ref_changes(self):
402
        # renaming a reference changes the last modified.
403
        tree = self.make_branch_and_tree('.')
404
        subtree = self.make_reference('reference')
405
        try:
406
            tree.add_reference(subtree)
407
            self._commit_renamed_check_changed(tree, 'reference',
408
                subtree.get_root_id(),
409
                mini_commit=self.mini_commit_record_iter_changes)
410
        except errors.UnsupportedOperation:
411
            return
412
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
413
    def _add_commit_reparent_check_changed(self, tree, name,
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
414
        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.
415
        self.build_tree(['newparent/'])
416
        tree.add(['newparent'])
417
        def reparent():
418
            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.
419
        self._add_commit_change_check_changed(tree, name, reparent,
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
420
            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.
421
422
    def test_last_modified_revision_after_reparent_dir_changes(self):
423
        # reparenting a dir changes the last modified.
424
        tree = self.make_branch_and_tree('.')
425
        self.build_tree(['dir/'])
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
426
        self._add_commit_reparent_check_changed(tree, 'dir',
427
            mini_commit=self.mini_commit_record_iter_changes)
428
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
429
    def test_last_modified_revision_after_reparent_file_changes(self):
430
        # reparenting a file changes the last modified.
431
        tree = self.make_branch_and_tree('.')
432
        self.build_tree(['file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
433
        self._add_commit_reparent_check_changed(tree, 'file',
3775.2.17 by Robert Collins
CommitBuilder.record_iter_changes handles changed files.
434
            expect_fs_hash=True,
435
            mini_commit=self.mini_commit_record_iter_changes)
3775.2.15 by Robert Collins
CommitBuilder.record_iter_changes handles reparented files.
436
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
437
    def test_last_modified_revision_after_reparent_link_changes(self):
438
        # reparenting a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
439
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
440
        tree = self.make_branch_and_tree('.')
441
        os.symlink('target', 'link')
3775.2.16 by Robert Collins
CommitBuilder.record_iter_changes handles reparented symlinks.
442
        self._add_commit_reparent_check_changed(tree, 'link',
443
            mini_commit=self.mini_commit_record_iter_changes)
444
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
445
    def _add_commit_change_check_changed(self, tree, name, changer,
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
446
            expect_fs_hash=False, mini_commit=None):
447
        tree.add([name])
448
        file_id = tree.path2id(name)
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
449
        self._commit_change_check_changed(
450
            tree, name, file_id,
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
451
            changer, expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
452
4183.5.3 by Robert Collins
Fix typo.
453
    def _commit_change_check_changed(self, tree, name, file_id, changer,
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
454
        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.
455
        rev1 = tree.commit('')
456
        changer()
4183.5.2 by Robert Collins
Support tree-reference in record_iter_changes.
457
        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.
458
            expect_fs_hash=expect_fs_hash)
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
459
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
460
        self.assertEqual(rev1, tree1.get_file_revision(tree1.id2path(file_id)))
461
        self.assertEqual(rev2, tree2.get_file_revision(tree2.id2path(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.
462
        expected_graph = {}
463
        expected_graph[(file_id, rev1)] = ()
464
        expected_graph[(file_id, rev2)] = ((file_id, rev1),)
465
        self.assertFileGraph(expected_graph, tree, (file_id, rev2))
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
466
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
467
    def mini_commit_record_iter_changes(self, tree, name, new_name,
468
        records_version=True, delta_against_basis=True, expect_fs_hash=False):
469
        """Perform a miniature commit looking for record entry results.
470
471
        This version uses the record_iter_changes interface.
472
        
473
        :param tree: The tree to commit.
474
        :param name: The path in the basis tree of the tree being committed.
475
        :param new_name: The path in the tree being committed.
476
        :param records_version: True if the commit of new_name is expected to
477
            record a new version.
478
        :param delta_against_basis: True of the commit of new_name is expected
479
            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.
480
        :param expect_fs_hash: If true, looks for a fs hash output from
481
            record_iter_changes.
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
482
        """
483
        tree.lock_write()
484
        try:
485
            # mini manual commit here so we can check the return of
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
486
            # record_iter_changes
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
487
            parent_ids = tree.get_parent_ids()
488
            builder = tree.branch.get_commit_builder(parent_ids)
489
            parent_tree = tree.basis_tree()
490
            parent_tree.lock_read()
491
            self.addCleanup(parent_tree.unlock)
5856.1.2 by Jelmer Vernooij
Delay accessing inventory in tests until necessary.
492
            parent_trees = [parent_tree]
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
493
            for parent_id in parent_ids[1:]:
5856.1.2 by Jelmer Vernooij
Delay accessing inventory in tests until necessary.
494
                parent_trees.append(tree.branch.repository.revision_tree(
495
                    parent_id))
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
496
            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.
497
            result = list(builder.record_iter_changes(tree, parent_ids[0],
498
                changes))
499
            file_id = tree.path2id(new_name)
500
            if expect_fs_hash:
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
501
                tree_file_stat = tree.get_file_with_stat(new_name)
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
502
                tree_file_stat[0].close()
503
                self.assertLength(1, result)
504
                result = result[0]
505
                self.assertEqual(result[:2], (file_id, new_name))
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
506
                self.assertEqual(result[2][0], tree.get_file_sha1(new_name))
4183.5.4 by Robert Collins
Turn record_iter_changes into a generator to emit file system hashes.
507
                self.assertEqualStat(result[2][1], tree_file_stat[1])
508
            else:
509
                self.assertEqual([], result)
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
510
            builder.finish_inventory()
5718.4.4 by Jelmer Vernooij
Only check .inventories if present.
511
            if tree.branch.repository._format.supports_full_versioned_files:
512
                inv_key = (builder._new_revision_id,)
513
                inv_sha1 = tree.branch.repository.inventories.get_sha1s(
514
                                [inv_key])[inv_key]
515
                self.assertEqual(inv_sha1, builder.inv_sha1)
6362.5.5 by Jelmer Vernooij
Don't access revision tree before commit.
516
            rev2 = builder.commit('')
6437.12.1 by Jelmer Vernooij
Use CommitBuilder.get_basis_delta rather than private CommitBuilder._basis_delta.
517
            delta = builder.get_basis_delta()
518
            delta_dict = dict((change[2], change) for change in delta)
519
            version_recorded = (file_id in delta_dict and
520
                delta_dict[file_id][3] is not None and
521
                delta_dict[file_id][3].revision == rev2)
522
            if records_version:
523
                self.assertTrue(version_recorded)
524
            else:
525
                self.assertFalse(version_recorded)
526
6405.2.6 by Jelmer Vernooij
Lots of test fixes.
527
            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.
528
            new_entry = new_inventory[file_id]
529
            if delta_against_basis:
530
                expected_delta = (name, new_name, file_id, new_entry)
531
                self.assertEqual(expected_delta, delta_dict[file_id])
532
            else:
533
                expected_delta = None
534
                self.assertFalse(version_recorded)
535
            tree.set_parent_ids([rev2])
536
        except:
537
            builder.abort()
538
            tree.unlock()
539
            raise
540
        else:
541
            tree.unlock()
542
        return rev2
543
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.
544
    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.
545
        # all the changes that have occured should be in the ancestry
546
        # (closest to a public per-file graph API we have today)
547
        tree.lock_read()
548
        self.addCleanup(tree.unlock)
5815.5.9 by Jelmer Vernooij
Remove dependencies on texts.
549
        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.
550
        self.assertEqual(expected_graph, g)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
551
552
    def test_last_modified_revision_after_content_file_changes(self):
553
        # altering a file changes the last modified.
554
        tree = self.make_branch_and_tree('.')
555
        self.build_tree(['file'])
556
        def change_file():
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
557
            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.
558
        self._add_commit_change_check_changed(tree, 'file', change_file,
3775.2.17 by Robert Collins
CommitBuilder.record_iter_changes handles changed files.
559
            expect_fs_hash=True,
560
            mini_commit=self.mini_commit_record_iter_changes)
561
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
562
    def _test_last_mod_rev_after_content_link_changes(
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
563
        self, link, target, newtarget):
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
564
        # changing a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
565
        self.requireFeature(features.SymlinkFeature)
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
566
        tree = self.make_branch_and_tree('.')
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
567
        os.symlink(target, link)
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
568
        def change_link():
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
569
            os.unlink(link)
570
            os.symlink(newtarget, link)
571
        self._add_commit_change_check_changed(
572
            tree, link, change_link,
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
573
            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.
574
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
575
    def test_last_modified_rev_after_content_link_changes(self):
576
        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.
577
            'link', 'target', 'newtarget')
578
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
579
    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
580
        self.requireFeature(features.UnicodeFilenameFeature)
6700.2.1 by Jelmer Vernooij
Remove record_entry_contents tests and infrastructure.
581
        self._test_last_mod_rev_after_content_link_changes(
6770.2.1 by Jelmer Vernooij
Avoid setting file ids.
582
            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.
583
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
584
    def _commit_sprout(self, tree, name):
6770.2.3 by Jelmer Vernooij
Fix file ids.
585
        tree.add([name])
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
586
        rev_id = tree.commit('')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
587
        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.
588
589
    def _rename_in_tree(self, tree, name):
590
        tree.rename_one(name, 'new_' + name)
591
        return tree.commit('')
592
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
593
    def _commit_sprout_rename_merge(self, tree1, name, expect_fs_hash=False,
594
        mini_commit=None):
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
595
        """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.
596
        rev1, tree2 = self._commit_sprout(tree1, name)
6770.2.3 by Jelmer Vernooij
Fix file ids.
597
        file_id = tree2.path2id(name)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
598
        # change both sides equally
599
        rev2 = self._rename_in_tree(tree1, name)
600
        rev3 = self._rename_in_tree(tree2, name)
601
        tree1.merge_from_branch(tree2.branch)
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
602
        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.
603
            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.
604
        tree3, = self._get_revtrees(tree1, [rev4])
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
605
        self.assertEqual(rev4, tree3.get_file_revision(tree3.id2path(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.
606
        expected_graph = {}
607
        expected_graph[(file_id, rev1)] = ()
608
        expected_graph[(file_id, rev2)] = ((file_id, rev1),)
609
        expected_graph[(file_id, rev3)] = ((file_id, rev1),)
610
        expected_graph[(file_id, rev4)] = ((file_id, rev2), (file_id, rev3),)
611
        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.
612
613
    def test_last_modified_revision_after_merge_dir_changes(self):
614
        # merge a dir changes the last modified.
615
        tree1 = self.make_branch_and_tree('t1')
616
        self.build_tree(['t1/dir/'])
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
617
        self._commit_sprout_rename_merge(tree1, 'dir',
618
            mini_commit=self.mini_commit_record_iter_changes)
619
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
620
    def test_last_modified_revision_after_merge_file_changes(self):
621
        # merge a file changes the last modified.
622
        tree1 = self.make_branch_and_tree('t1')
623
        self.build_tree(['t1/file'])
3775.2.20 by Robert Collins
CommitBuilder.record_iter_changes handles merged files.
624
        self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True,
625
            mini_commit=self.mini_commit_record_iter_changes)
626
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
627
    def test_last_modified_revision_after_merge_link_changes(self):
628
        # merge a link changes the last modified.
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
629
        self.requireFeature(features.SymlinkFeature)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
630
        tree1 = self.make_branch_and_tree('t1')
631
        os.symlink('target', 't1/link')
3775.2.21 by Robert Collins
CommitBuilder.record_iter_changes handles merged symlinks.
632
        self._commit_sprout_rename_merge(tree1, 'link',
633
            mini_commit=self.mini_commit_record_iter_changes)
634
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
635
    def _commit_sprout_rename_merge_converged(self, tree1, name,
636
        mini_commit=None):
637
        # Make a merge which just incorporates a change from a branch:
638
        # The per-file graph is straight line, and no alteration occurs
639
        # in the inventory.
4183.5.9 by Robert Collins
Fix creating new revisions of files when merging.
640
        # 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.
641
        rev1, tree2 = self._commit_sprout(tree1, name)
6770.2.3 by Jelmer Vernooij
Fix file ids.
642
        file_id = tree2.path2id(name)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
643
        # change on the other side to merge back
644
        rev2 = self._rename_in_tree(tree2, name)
645
        tree1.merge_from_branch(tree2.branch)
4183.5.9 by Robert Collins
Fix creating new revisions of files when merging.
646
        def _check_graph(in_tree, changed_in_tree):
647
            rev3 = mini_commit(in_tree, name, 'new_' + name, False,
648
                delta_against_basis=changed_in_tree)
649
            tree3, = self._get_revtrees(in_tree, [rev2])
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
650
            self.assertEqual(
651
                    rev2,
652
                    tree3.get_file_revision(tree3.id2path(file_id), 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
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
681
        self.assertEqual(rev2, tree3.get_file_revision(tree3.id2path(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()