~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transform.py

  • Committer: Martin
  • Date: 2011-04-15 21:22:57 UTC
  • mto: This revision was merged to the branch mainline in revision 5797.
  • Revision ID: gzlist@googlemail.com-20110415212257-jgtovwwp4be7egd9
Add release notes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
 
17
import errno
17
18
import os
18
19
from StringIO import StringIO
19
20
import sys
52
53
    ImmortalPendingDeletion,
53
54
    LockError,
54
55
    MalformedTransform,
55
 
    NoSuchFile,
56
56
    ReusingTransform,
57
57
)
58
58
from bzrlib.osutils import (
64
64
    features,
65
65
    HardlinkFeature,
66
66
    SymlinkFeature,
67
 
    TestCase,
68
67
    TestCaseInTempDir,
69
68
    TestSkipped,
70
69
)
74
73
    cook_conflicts,
75
74
    _FileMover,
76
75
    FinalPaths,
77
 
    get_backup_name,
78
76
    resolve_conflicts,
79
77
    resolve_checkout,
80
78
    ROOT_PARENT,
95
93
        self.addCleanup(transform.finalize)
96
94
        return transform, transform.root
97
95
 
 
96
    def get_transform_for_sha1_test(self):
 
97
        trans, root = self.get_transform()
 
98
        self.wt.lock_tree_write()
 
99
        self.addCleanup(self.wt.unlock)
 
100
        contents = ['just some content\n']
 
101
        sha1 = osutils.sha_strings(contents)
 
102
        # Roll back the clock
 
103
        trans._creation_mtime = time.time() - 20.0
 
104
        return trans, root, contents, sha1
 
105
 
98
106
    def test_existing_limbo(self):
99
107
        transform, root = self.get_transform()
100
108
        limbo_name = transform._limbodir
163
171
        transform.finalize()
164
172
        transform.finalize()
165
173
 
 
174
    def test_apply_informs_tree_of_observed_sha1(self):
 
175
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
 
176
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
 
177
                                  sha1=sha1)
 
178
        calls = []
 
179
        orig = self.wt._observed_sha1
 
180
        def _observed_sha1(*args):
 
181
            calls.append(args)
 
182
            orig(*args)
 
183
        self.wt._observed_sha1 = _observed_sha1
 
184
        trans.apply()
 
185
        self.assertEqual([(None, 'file1', trans._observed_sha1s[trans_id])],
 
186
                         calls)
 
187
 
 
188
    def test_create_file_caches_sha1(self):
 
189
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
 
190
        trans_id = trans.create_path('file1', root)
 
191
        trans.create_file(contents, trans_id, sha1=sha1)
 
192
        st_val = osutils.lstat(trans._limbo_name(trans_id))
 
193
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
 
194
        self.assertEqual(o_sha1, sha1)
 
195
        self.assertEqualStat(o_st_val, st_val)
 
196
 
 
197
    def test__apply_insertions_updates_sha1(self):
 
198
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
 
199
        trans_id = trans.create_path('file1', root)
 
200
        trans.create_file(contents, trans_id, sha1=sha1)
 
201
        st_val = osutils.lstat(trans._limbo_name(trans_id))
 
202
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
 
203
        self.assertEqual(o_sha1, sha1)
 
204
        self.assertEqualStat(o_st_val, st_val)
 
205
        creation_mtime = trans._creation_mtime + 10.0
 
206
        # We fake a time difference from when the file was created until now it
 
207
        # is being renamed by using os.utime. Note that the change we actually
 
208
        # want to see is the real ctime change from 'os.rename()', but as long
 
209
        # as we observe a new stat value, we should be fine.
 
210
        os.utime(trans._limbo_name(trans_id), (creation_mtime, creation_mtime))
 
211
        trans.apply()
 
212
        new_st_val = osutils.lstat(self.wt.abspath('file1'))
 
213
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
 
214
        self.assertEqual(o_sha1, sha1)
 
215
        self.assertEqualStat(o_st_val, new_st_val)
 
216
        self.assertNotEqual(st_val.st_mtime, new_st_val.st_mtime)
 
217
 
 
218
    def test_new_file_caches_sha1(self):
 
219
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
 
220
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
 
221
                                  sha1=sha1)
 
222
        st_val = osutils.lstat(trans._limbo_name(trans_id))
 
223
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
 
224
        self.assertEqual(o_sha1, sha1)
 
225
        self.assertEqualStat(o_st_val, st_val)
 
226
 
 
227
    def test_cancel_creation_removes_observed_sha1(self):
 
228
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
 
229
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
 
230
                                  sha1=sha1)
 
231
        self.assertTrue(trans_id in trans._observed_sha1s)
 
232
        trans.cancel_creation(trans_id)
 
233
        self.assertFalse(trans_id in trans._observed_sha1s)
 
234
 
166
235
    def test_create_files_same_timestamp(self):
167
236
        transform, root = self.get_transform()
168
237
        self.wt.lock_tree_write()
900
969
        # On windows looks like:
901
970
        # "Failed to rename .../work/myfile to 
902
971
        # .../work/.bzr/checkout/limbo/new-1: [Errno 13] Permission denied"
903
 
        # The strerror will vary per OS and language so it's not checked here
904
 
        self.assertContainsRe(str(e),
905
 
            "Failed to rename .*(first-dir.newname:|myfile)")
 
972
        # This test isn't concerned with exactly what the error looks like,
 
973
        # and the strerror will vary across OS and locales, but the assert
 
974
        # that the exeception attributes are what we expect
 
975
        self.assertEqual(e.errno, errno.EACCES)
 
976
        if os.name == "posix":
 
977
            self.assertEndsWith(e.to_path, "/first-dir/newname")
 
978
        else:
 
979
            self.assertEqual(os.path.basename(e.from_path), "myfile")
906
980
 
907
981
    def test_set_executability_order(self):
908
982
        """Ensure that executability behaves the same, no matter what order.
1896
1970
        self.addCleanup(target.unlock)
1897
1971
        self.assertEqual([], list(target.iter_changes(revision_tree)))
1898
1972
 
 
1973
    def test_build_tree_accelerator_tree_observes_sha1(self):
 
1974
        source = self.create_ab_tree()
 
1975
        sha1 = osutils.sha_string('A')
 
1976
        target = self.make_branch_and_tree('target')
 
1977
        target.lock_write()
 
1978
        self.addCleanup(target.unlock)
 
1979
        state = target.current_dirstate()
 
1980
        state._cutoff_time = time.time() + 60
 
1981
        build_tree(source.basis_tree(), target, source)
 
1982
        entry = state._get_entry(0, path_utf8='file1')
 
1983
        self.assertEqual(sha1, entry[1][0][1])
 
1984
 
1899
1985
    def test_build_tree_accelerator_tree_missing_file(self):
1900
1986
        source = self.create_ab_tree()
1901
1987
        os.unlink('source/file1')
2059
2145
        self.assertEqual('file.moved', target.id2path('lower-id'))
2060
2146
        self.assertEqual('FILE', target.id2path('upper-id'))
2061
2147
 
 
2148
    def test_build_tree_observes_sha(self):
 
2149
        source = self.make_branch_and_tree('source')
 
2150
        self.build_tree(['source/file1', 'source/dir/', 'source/dir/file2'])
 
2151
        source.add(['file1', 'dir', 'dir/file2'],
 
2152
                   ['file1-id', 'dir-id', 'file2-id'])
 
2153
        source.commit('new files')
 
2154
        target = self.make_branch_and_tree('target')
 
2155
        target.lock_write()
 
2156
        self.addCleanup(target.unlock)
 
2157
        # We make use of the fact that DirState caches its cutoff time. So we
 
2158
        # set the 'safe' time to one minute in the future.
 
2159
        state = target.current_dirstate()
 
2160
        state._cutoff_time = time.time() + 60
 
2161
        build_tree(source.basis_tree(), target)
 
2162
        entry1_sha = osutils.sha_file_by_name('source/file1')
 
2163
        entry2_sha = osutils.sha_file_by_name('source/dir/file2')
 
2164
        # entry[1] is the state information, entry[1][0] is the state of the
 
2165
        # working tree, entry[1][0][1] is the sha value for the current working
 
2166
        # tree
 
2167
        entry1 = state._get_entry(0, path_utf8='file1')
 
2168
        self.assertEqual(entry1_sha, entry1[1][0][1])
 
2169
        # The 'size' field must also be set.
 
2170
        self.assertEqual(25, entry1[1][0][2])
 
2171
        entry1_state = entry1[1][0]
 
2172
        entry2 = state._get_entry(0, path_utf8='dir/file2')
 
2173
        self.assertEqual(entry2_sha, entry2[1][0][1])
 
2174
        self.assertEqual(29, entry2[1][0][2])
 
2175
        entry2_state = entry2[1][0]
 
2176
        # Now, make sure that we don't have to re-read the content. The
 
2177
        # packed_stat should match exactly.
 
2178
        self.assertEqual(entry1_sha, target.get_file_sha1('file1-id', 'file1'))
 
2179
        self.assertEqual(entry2_sha,
 
2180
                         target.get_file_sha1('file2-id', 'dir/file2'))
 
2181
        self.assertEqual(entry1_state, entry1[1][0])
 
2182
        self.assertEqual(entry2_state, entry2[1][0])
 
2183
 
2062
2184
 
2063
2185
class TestCommitTransform(tests.TestCaseWithTransport):
2064
2186
 
2381
2503
                  ('TREE_ROOT', 'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2382
2504
                  (False, False))
2383
2505
ROOT_ENTRY = ('TREE_ROOT', ('', ''), False, (True, True), (None, None),
2384
 
              ('', ''), ('directory', 'directory'), (False, None))
 
2506
              ('', ''), ('directory', 'directory'), (False, False))
2385
2507
 
2386
2508
 
2387
2509
class TestTransformPreview(tests.TestCaseWithTransport):
2474
2596
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2475
2597
        changes = preview_tree.iter_changes(revision_tree,
2476
2598
                                            specific_files=[''])
2477
 
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
 
2599
        self.assertEqual([A_ENTRY], list(changes))
2478
2600
 
2479
2601
    def test_want_unversioned(self):
2480
2602
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2481
2603
        changes = preview_tree.iter_changes(revision_tree,
2482
2604
                                            want_unversioned=True)
2483
 
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
 
2605
        self.assertEqual([A_ENTRY], list(changes))
2484
2606
 
2485
2607
    def test_ignore_extra_trees_no_specific_files(self):
2486
2608
        # extra_trees is harmless without specific_files, so we'll silently
3272
3394
                                               policy)
3273
3395
 
3274
3396
    def _prepare_orphan(self, wt):
3275
 
        self.build_tree(['dir/', 'dir/foo'])
3276
 
        wt.add(['dir'], ['dir-id'])
3277
 
        wt.commit('add dir')
 
3397
        self.build_tree(['dir/', 'dir/file', 'dir/foo'])
 
3398
        wt.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
 
3399
        wt.commit('add dir and file ignoring foo')
3278
3400
        tt = transform.TreeTransform(wt)
3279
3401
        self.addCleanup(tt.finalize)
 
3402
        # dir and bar are deleted
3280
3403
        dir_tid = tt.trans_id_tree_path('dir')
 
3404
        file_tid = tt.trans_id_tree_path('dir/file')
3281
3405
        orphan_tid = tt.trans_id_tree_path('dir/foo')
 
3406
        tt.delete_contents(file_tid)
 
3407
        tt.unversion_file(file_tid)
3282
3408
        tt.delete_contents(dir_tid)
3283
3409
        tt.unversion_file(dir_tid)
 
3410
        # There should be a conflict because dir still contain foo
3284
3411
        raw_conflicts = tt.find_conflicts()
3285
3412
        self.assertLength(1, raw_conflicts)
3286
3413
        self.assertEqual(('missing parent', 'new-1'), raw_conflicts[0])
3290
3417
        wt = self.make_branch_and_tree('.')
3291
3418
        self._set_orphan_policy(wt, 'move')
3292
3419
        tt, orphan_tid = self._prepare_orphan(wt)
 
3420
        warnings = []
 
3421
        def warning(*args):
 
3422
            warnings.append(args[0] % args[1:])
 
3423
        self.overrideAttr(trace, 'warning', warning)
3293
3424
        remaining_conflicts = resolve_conflicts(tt)
 
3425
        self.assertEquals(['dir/foo has been orphaned in bzr-orphans'],
 
3426
                          warnings)
3294
3427
        # Yeah for resolved conflicts !
3295
3428
        self.assertLength(0, remaining_conflicts)
3296
3429
        # We have a new orphan