~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/per_bzrdir/test_bzrdir.py

  • Committer: Jelmer Vernooij
  • Date: 2010-08-29 14:37:51 UTC
  • mto: This revision was merged to the branch mainline in revision 5418.
  • Revision ID: jelmer@samba.org-20100829143751-9ry91e6u887gswiz
Move some bzrdir-specific tests to bzrlib.tests.per_bzrdir.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006-2010 Canonical Ltd
 
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
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for bzrdir implementations - tests a bzrdir format."""
 
18
 
 
19
import errno
 
20
from stat import S_ISDIR
 
21
 
 
22
import bzrlib.branch
 
23
from bzrlib import (
 
24
    errors,
 
25
    revision as _mod_revision,
 
26
    )
 
27
 
 
28
from bzrlib.tests.per_bzrdir import TestCaseWithBzrDir
 
29
 
 
30
 
 
31
class TestBzrDir(TestCaseWithBzrDir):
 
32
 
 
33
    # Many of these tests test for disk equality rather than checking
 
34
    # for semantic equivalence. This works well for some tests but
 
35
    # is not good at handling changes in representation or the addition
 
36
    # or removal of control data. It would be nice to for instance:
 
37
    # sprout a new branch, check that the nickname has been reset by hand
 
38
    # and then set the nickname to match the source branch, at which point
 
39
    # a semantic equivalence should pass
 
40
 
 
41
    def assertDirectoriesEqual(self, source, target, ignore_list=[]):
 
42
        """Assert that the content of source and target are identical.
 
43
 
 
44
        paths in ignore list will be completely ignored.
 
45
 
 
46
        We ignore paths that represent data which is allowed to change during
 
47
        a clone or sprout: for instance, inventory.knit contains gzip fragements
 
48
        which have timestamps in them, and as we have read the inventory from
 
49
        the source knit, the already-read data is recompressed rather than
 
50
        reading it again, which leads to changed timestamps. This is ok though,
 
51
        because the inventory.kndx file is not ignored, and the integrity of
 
52
        knit joins is tested by test_knit and test_versionedfile.
 
53
 
 
54
        :seealso: Additionally, assertRepositoryHasSameItems provides value
 
55
            rather than representation checking of repositories for
 
56
            equivalence.
 
57
        """
 
58
        files = []
 
59
        directories = ['.']
 
60
        while directories:
 
61
            dir = directories.pop()
 
62
            for path in set(source.list_dir(dir) + target.list_dir(dir)):
 
63
                path = dir + '/' + path
 
64
                if path in ignore_list:
 
65
                    continue
 
66
                try:
 
67
                    stat = source.stat(path)
 
68
                except errors.NoSuchFile:
 
69
                    self.fail('%s not in source' % path)
 
70
                if S_ISDIR(stat.st_mode):
 
71
                    self.assertTrue(S_ISDIR(target.stat(path).st_mode))
 
72
                    directories.append(path)
 
73
                else:
 
74
                    self.assertEqualDiff(source.get(path).read(),
 
75
                                         target.get(path).read(),
 
76
                                         "text for file %r differs:\n" % path)
 
77
 
 
78
    def assertRepositoryHasSameItems(self, left_repo, right_repo):
 
79
        """require left_repo and right_repo to contain the same data."""
 
80
        # XXX: TODO: Doesn't work yet, because we need to be able to compare
 
81
        # local repositories to remote ones...  but this is an as-yet unsolved
 
82
        # aspect of format management and the Remote protocols...
 
83
        # self.assertEqual(left_repo._format.__class__,
 
84
        #     right_repo._format.__class__)
 
85
        left_repo.lock_read()
 
86
        try:
 
87
            right_repo.lock_read()
 
88
            try:
 
89
                # revs
 
90
                all_revs = left_repo.all_revision_ids()
 
91
                self.assertEqual(left_repo.all_revision_ids(),
 
92
                    right_repo.all_revision_ids())
 
93
                for rev_id in left_repo.all_revision_ids():
 
94
                    self.assertEqual(left_repo.get_revision(rev_id),
 
95
                        right_repo.get_revision(rev_id))
 
96
                # Assert the revision trees (and thus the inventories) are equal
 
97
                sort_key = lambda rev_tree: rev_tree.get_revision_id()
 
98
                rev_trees_a = sorted(
 
99
                    left_repo.revision_trees(all_revs), key=sort_key)
 
100
                rev_trees_b = sorted(
 
101
                    right_repo.revision_trees(all_revs), key=sort_key)
 
102
                for tree_a, tree_b in zip(rev_trees_a, rev_trees_b):
 
103
                    self.assertEqual([], list(tree_a.iter_changes(tree_b)))
 
104
                # texts
 
105
                text_index = left_repo._generate_text_key_index()
 
106
                self.assertEqual(text_index,
 
107
                    right_repo._generate_text_key_index())
 
108
                desired_files = []
 
109
                for file_id, revision_id in text_index.iterkeys():
 
110
                    desired_files.append(
 
111
                        (file_id, revision_id, (file_id, revision_id)))
 
112
                left_texts = list(left_repo.iter_files_bytes(desired_files))
 
113
                right_texts = list(right_repo.iter_files_bytes(desired_files))
 
114
                left_texts.sort()
 
115
                right_texts.sort()
 
116
                self.assertEqual(left_texts, right_texts)
 
117
                # signatures
 
118
                for rev_id in all_revs:
 
119
                    try:
 
120
                        left_text = left_repo.get_signature_text(rev_id)
 
121
                    except errors.NoSuchRevision:
 
122
                        continue
 
123
                    right_text = right_repo.get_signature_text(rev_id)
 
124
                    self.assertEqual(left_text, right_text)
 
125
            finally:
 
126
                right_repo.unlock()
 
127
        finally:
 
128
            left_repo.unlock()
 
129
 
 
130
    def test_clone_bzrdir_repository_under_shared_force_new_repo(self):
 
131
        tree = self.make_branch_and_tree('commit_tree')
 
132
        self.build_tree(['commit_tree/foo'])
 
133
        tree.add('foo')
 
134
        tree.commit('revision 1', rev_id='1')
 
135
        dir = self.make_bzrdir('source')
 
136
        repo = dir.create_repository()
 
137
        repo.fetch(tree.branch.repository)
 
138
        self.assertTrue(repo.has_revision('1'))
 
139
        try:
 
140
            self.make_repository('target', shared=True)
 
141
        except errors.IncompatibleFormat:
 
142
            return
 
143
        target = dir.clone(self.get_url('target/child'), force_new_repo=True)
 
144
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
145
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
146
                                    ['./.bzr/repository',
 
147
                                     ])
 
148
        self.assertRepositoryHasSameItems(tree.branch.repository, repo)
 
149
 
 
150
    def test_clone_bzrdir_branch_and_repo(self):
 
151
        tree = self.make_branch_and_tree('commit_tree')
 
152
        self.build_tree(['commit_tree/foo'])
 
153
        tree.add('foo')
 
154
        tree.commit('revision 1')
 
155
        source = self.make_branch('source')
 
156
        tree.branch.repository.copy_content_into(source.repository)
 
157
        tree.branch.copy_content_into(source)
 
158
        dir = source.bzrdir
 
159
        target = dir.clone(self.get_url('target'))
 
160
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
161
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
162
                                    [
 
163
                                     './.bzr/basis-inventory-cache',
 
164
                                     './.bzr/checkout/stat-cache',
 
165
                                     './.bzr/merge-hashes',
 
166
                                     './.bzr/repository',
 
167
                                     './.bzr/stat-cache',
 
168
                                    ])
 
169
        self.assertRepositoryHasSameItems(
 
170
            tree.branch.repository, target.open_repository())
 
171
 
 
172
    def test_clone_on_transport(self):
 
173
        a_dir = self.make_bzrdir('source')
 
174
        target_transport = a_dir.root_transport.clone('..').clone('target')
 
175
        target = a_dir.clone_on_transport(target_transport)
 
176
        self.assertNotEqual(a_dir.transport.base, target.transport.base)
 
177
        self.assertDirectoriesEqual(a_dir.root_transport, target.root_transport,
 
178
                                    ['./.bzr/merge-hashes'])
 
179
 
 
180
    def test_clone_bzrdir_empty(self):
 
181
        dir = self.make_bzrdir('source')
 
182
        target = dir.clone(self.get_url('target'))
 
183
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
184
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
185
                                    ['./.bzr/merge-hashes'])
 
186
 
 
187
    def test_clone_bzrdir_empty_force_new_ignored(self):
 
188
        # the force_new_repo parameter should have no effect on an empty
 
189
        # bzrdir's clone logic
 
190
        dir = self.make_bzrdir('source')
 
191
        target = dir.clone(self.get_url('target'), force_new_repo=True)
 
192
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
193
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
194
                                    ['./.bzr/merge-hashes'])
 
195
 
 
196
    def test_clone_bzrdir_repository(self):
 
197
        tree = self.make_branch_and_tree('commit_tree')
 
198
        self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
 
199
        tree.add('foo')
 
200
        tree.commit('revision 1', rev_id='1')
 
201
        dir = self.make_bzrdir('source')
 
202
        repo = dir.create_repository()
 
203
        repo.fetch(tree.branch.repository)
 
204
        self.assertTrue(repo.has_revision('1'))
 
205
        target = dir.clone(self.get_url('target'))
 
206
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
207
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
208
                                    [
 
209
                                     './.bzr/merge-hashes',
 
210
                                     './.bzr/repository',
 
211
                                     ])
 
212
        self.assertRepositoryHasSameItems(tree.branch.repository,
 
213
            target.open_repository())
 
214
 
 
215
    def test_clone_bzrdir_tree_branch_repo(self):
 
216
        tree = self.make_branch_and_tree('source')
 
217
        self.build_tree(['source/foo'])
 
218
        tree.add('foo')
 
219
        tree.commit('revision 1')
 
220
        dir = tree.bzrdir
 
221
        target = dir.clone(self.get_url('target'))
 
222
        self.skipIfNoWorkingTree(target)
 
223
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
224
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
225
                                    ['./.bzr/stat-cache',
 
226
                                     './.bzr/checkout/dirstate',
 
227
                                     './.bzr/checkout/stat-cache',
 
228
                                     './.bzr/checkout/merge-hashes',
 
229
                                     './.bzr/merge-hashes',
 
230
                                     './.bzr/repository',
 
231
                                     ])
 
232
        self.assertRepositoryHasSameItems(tree.branch.repository,
 
233
            target.open_repository())
 
234
        target.open_workingtree().revert()
 
235
 
 
236
    def test_revert_inventory(self):
 
237
        tree = self.make_branch_and_tree('source')
 
238
        self.build_tree(['source/foo'])
 
239
        tree.add('foo')
 
240
        tree.commit('revision 1')
 
241
        dir = tree.bzrdir
 
242
        target = dir.clone(self.get_url('target'))
 
243
        self.skipIfNoWorkingTree(target)
 
244
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
245
                                    ['./.bzr/stat-cache',
 
246
                                     './.bzr/checkout/dirstate',
 
247
                                     './.bzr/checkout/stat-cache',
 
248
                                     './.bzr/checkout/merge-hashes',
 
249
                                     './.bzr/merge-hashes',
 
250
                                     './.bzr/repository',
 
251
                                     ])
 
252
        self.assertRepositoryHasSameItems(tree.branch.repository,
 
253
            target.open_repository())
 
254
 
 
255
        target.open_workingtree().revert()
 
256
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
257
                                    ['./.bzr/stat-cache',
 
258
                                     './.bzr/checkout/dirstate',
 
259
                                     './.bzr/checkout/stat-cache',
 
260
                                     './.bzr/checkout/merge-hashes',
 
261
                                     './.bzr/merge-hashes',
 
262
                                     './.bzr/repository',
 
263
                                     ])
 
264
        self.assertRepositoryHasSameItems(tree.branch.repository,
 
265
            target.open_repository())
 
266
 
 
267
    def test_clone_bzrdir_tree_branch_reference(self):
 
268
        # a tree with a branch reference (aka a checkout)
 
269
        # should stay a checkout on clone.
 
270
        referenced_branch = self.make_branch('referencced')
 
271
        dir = self.make_bzrdir('source')
 
272
        try:
 
273
            reference = bzrlib.branch.BranchReferenceFormat().initialize(dir,
 
274
                target_branch=referenced_branch)
 
275
        except errors.IncompatibleFormat:
 
276
            # this is ok too, not all formats have to support references.
 
277
            return
 
278
        self.createWorkingTreeOrSkip(dir)
 
279
        target = dir.clone(self.get_url('target'))
 
280
        self.skipIfNoWorkingTree(target)
 
281
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
282
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
283
                                    ['./.bzr/stat-cache',
 
284
                                     './.bzr/checkout/stat-cache',
 
285
                                     './.bzr/checkout/merge-hashes',
 
286
                                     './.bzr/merge-hashes',
 
287
                                     './.bzr/repository/inventory.knit',
 
288
                                     ])
 
289
 
 
290
    def test_clone_bzrdir_branch_and_repo_into_shared_repo_force_new_repo(self):
 
291
        # by default cloning into a shared repo uses the shared repo.
 
292
        tree = self.make_branch_and_tree('commit_tree')
 
293
        self.build_tree(['commit_tree/foo'])
 
294
        tree.add('foo')
 
295
        tree.commit('revision 1')
 
296
        source = self.make_branch('source')
 
297
        tree.branch.repository.copy_content_into(source.repository)
 
298
        tree.branch.copy_content_into(source)
 
299
        try:
 
300
            self.make_repository('target', shared=True)
 
301
        except errors.IncompatibleFormat:
 
302
            return
 
303
        dir = source.bzrdir
 
304
        target = dir.clone(self.get_url('target/child'), force_new_repo=True)
 
305
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
306
        repo = target.open_repository()
 
307
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
308
                                    ['./.bzr/repository',
 
309
                                     ])
 
310
        self.assertRepositoryHasSameItems(tree.branch.repository, repo)
 
311
 
 
312
    def test_clone_bzrdir_branch_reference(self):
 
313
        # cloning should preserve the reference status of the branch in a bzrdir
 
314
        referenced_branch = self.make_branch('referencced')
 
315
        dir = self.make_bzrdir('source')
 
316
        try:
 
317
            reference = bzrlib.branch.BranchReferenceFormat().initialize(dir,
 
318
                target_branch=referenced_branch)
 
319
        except errors.IncompatibleFormat:
 
320
            # this is ok too, not all formats have to support references.
 
321
            return
 
322
        target = dir.clone(self.get_url('target'))
 
323
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
324
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport)
 
325
 
 
326
    def test_sprout_bzrdir_repository(self):
 
327
        tree = self.make_branch_and_tree('commit_tree')
 
328
        self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
 
329
        tree.add('foo')
 
330
        tree.commit('revision 1', rev_id='1')
 
331
        dir = self.make_bzrdir('source')
 
332
        repo = dir.create_repository()
 
333
        repo.fetch(tree.branch.repository)
 
334
        self.assertTrue(repo.has_revision('1'))
 
335
        try:
 
336
            self.assertTrue(
 
337
                _mod_revision.is_null(_mod_revision.ensure_null(
 
338
                dir.open_branch().last_revision())))
 
339
        except errors.NotBranchError:
 
340
            pass
 
341
        target = dir.sprout(self.get_url('target'))
 
342
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
343
        # testing inventory isn't reasonable for repositories
 
344
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
345
                                    [
 
346
                                     './.bzr/branch',
 
347
                                     './.bzr/checkout',
 
348
                                     './.bzr/inventory',
 
349
                                     './.bzr/parent',
 
350
                                     './.bzr/repository/inventory.knit',
 
351
                                     ])
 
352
        try:
 
353
            local_inventory = dir.transport.local_abspath('inventory')
 
354
        except errors.NotLocalUrl:
 
355
            return
 
356
        try:
 
357
            # If we happen to have a tree, we'll guarantee everything
 
358
            # except for the tree root is the same.
 
359
            inventory_f = file(local_inventory, 'rb')
 
360
            self.addCleanup(inventory_f.close)
 
361
            self.assertContainsRe(inventory_f.read(),
 
362
                                  '<inventory format="5">\n</inventory>\n')
 
363
        except IOError, e:
 
364
            if e.errno != errno.ENOENT:
 
365
                raise
 
366
 
 
367
    def test_sprout_bzrdir_branch_and_repo(self):
 
368
        tree = self.make_branch_and_tree('commit_tree')
 
369
        self.build_tree(['commit_tree/foo'])
 
370
        tree.add('foo')
 
371
        tree.commit('revision 1')
 
372
        source = self.make_branch('source')
 
373
        tree.branch.repository.copy_content_into(source.repository)
 
374
        tree.bzrdir.open_branch().copy_content_into(source)
 
375
        dir = source.bzrdir
 
376
        target = dir.sprout(self.get_url('target'))
 
377
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
378
        target_repo = target.open_repository()
 
379
        self.assertRepositoryHasSameItems(source.repository, target_repo)
 
380
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
381
                                    [
 
382
                                     './.bzr/basis-inventory-cache',
 
383
                                     './.bzr/branch/branch.conf',
 
384
                                     './.bzr/branch/parent',
 
385
                                     './.bzr/checkout',
 
386
                                     './.bzr/checkout/inventory',
 
387
                                     './.bzr/checkout/stat-cache',
 
388
                                     './.bzr/inventory',
 
389
                                     './.bzr/parent',
 
390
                                     './.bzr/repository',
 
391
                                     './.bzr/stat-cache',
 
392
                                     './foo',
 
393
                                     ])
 
394
 
 
395
    def test_sprout_bzrdir_tree_branch_repo(self):
 
396
        tree = self.make_branch_and_tree('source')
 
397
        self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
 
398
        tree.add('foo')
 
399
        tree.commit('revision 1')
 
400
        dir = tree.bzrdir
 
401
        target = self.sproutOrSkip(dir, self.get_url('target'))
 
402
        self.assertNotEqual(dir.transport.base, target.transport.base)
 
403
        self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
 
404
                                    [
 
405
                                     './.bzr/branch/branch.conf',
 
406
                                     './.bzr/branch/parent',
 
407
                                     './.bzr/checkout/dirstate',
 
408
                                     './.bzr/checkout/stat-cache',
 
409
                                     './.bzr/checkout/inventory',
 
410
                                     './.bzr/inventory',
 
411
                                     './.bzr/parent',
 
412
                                     './.bzr/repository',
 
413
                                     './.bzr/stat-cache',
 
414
                                     ])
 
415
        self.assertRepositoryHasSameItems(
 
416
            tree.branch.repository, target.open_repository())
 
417
 
 
418
 
 
419
    def test_retire_bzrdir(self):
 
420
        bd = self.make_bzrdir('.')
 
421
        transport = bd.root_transport
 
422
        # must not overwrite existing directories
 
423
        self.build_tree(['.bzr.retired.0/', '.bzr.retired.0/junk',],
 
424
            transport=transport)
 
425
        self.failUnless(transport.has('.bzr'))
 
426
        bd.retire_bzrdir()
 
427
        self.failIf(transport.has('.bzr'))
 
428
        self.failUnless(transport.has('.bzr.retired.1'))
 
429
 
 
430
    def test_retire_bzrdir_limited(self):
 
431
        bd = self.make_bzrdir('.')
 
432
        transport = bd.root_transport
 
433
        # must not overwrite existing directories
 
434
        self.build_tree(['.bzr.retired.0/', '.bzr.retired.0/junk',],
 
435
            transport=transport)
 
436
        self.failUnless(transport.has('.bzr'))
 
437
        self.assertRaises((errors.FileExists, errors.DirectoryNotEmpty),
 
438
            bd.retire_bzrdir, limit=0)