~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/per_repository_reference/test_commit_with_stacking.py

  • Committer: Patch Queue Manager
  • Date: 2016-02-01 19:56:05 UTC
  • mfrom: (6615.1.1 trunk)
  • Revision ID: pqm@pqm.ubuntu.com-20160201195605-o7rl92wf6uyum3fk
(vila) Open trunk again as 2.8b1 (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2010, 2011 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
 
 
18
from bzrlib import (
 
19
    errors,
 
20
    remote,
 
21
    tests,
 
22
    urlutils,
 
23
    )
 
24
from bzrlib.tests.per_repository import TestCaseWithRepository
 
25
 
 
26
 
 
27
class TestCaseWithStackedTarget(TestCaseWithRepository):
 
28
 
 
29
    r1_key = ('rev1-id',)
 
30
    r2_key = ('rev2-id',)
 
31
 
 
32
    def make_stacked_target(self):
 
33
        base_tree = self.make_branch_and_tree('base')
 
34
        self.build_tree(['base/f1.txt'])
 
35
        base_tree.add(['f1.txt'], ['f1.txt-id'])
 
36
        base_tree.commit('initial', rev_id=self.r1_key[0])
 
37
        self.build_tree(['base/f2.txt'])
 
38
        base_tree.add(['f2.txt'], ['f2.txt-id'])
 
39
        base_tree.commit('base adds f2', rev_id=self.r2_key[0])
 
40
        stacked_url = urlutils.join(base_tree.branch.base, '../stacked')
 
41
        stacked_bzrdir = base_tree.bzrdir.sprout(stacked_url,
 
42
            stacked=True)
 
43
        if isinstance(stacked_bzrdir, remote.RemoteBzrDir):
 
44
            stacked_branch = stacked_bzrdir.open_branch()
 
45
            stacked_tree = stacked_branch.create_checkout('stacked',
 
46
                lightweight=True)
 
47
        else:
 
48
            stacked_tree = stacked_bzrdir.open_workingtree()
 
49
        return base_tree, stacked_tree
 
50
 
 
51
 
 
52
class TestCommitWithStacking(TestCaseWithStackedTarget):
 
53
 
 
54
    def setUp(self):
 
55
        super(TestCommitWithStacking, self).setUp()
 
56
        format = self.repository_format
 
57
        if (not (isinstance(format, remote.RemoteRepositoryFormat)
 
58
                 or format.supports_chks)):
 
59
            raise tests.TestNotApplicable('stacked commit only supported'
 
60
                ' for chk repositories')
 
61
 
 
62
    def get_only_repo(self, tree):
 
63
        """Open just the repository used by this tree.
 
64
 
 
65
        This returns a read locked Repository object without any stacking
 
66
        fallbacks.
 
67
        """
 
68
        repo = tree.branch.repository.bzrdir.open_repository()
 
69
        repo.lock_read()
 
70
        self.addCleanup(repo.unlock)
 
71
        return repo
 
72
 
 
73
    def assertPresent(self, expected, vf, keys):
 
74
        """Check which of the supplied keys are present."""
 
75
        parent_map = vf.get_parent_map(keys)
 
76
        self.assertEqual(sorted(expected), sorted(parent_map))
 
77
 
 
78
    def test_simple_commit(self):
 
79
        base_tree, stacked_tree = self.make_stacked_target()
 
80
        self.assertEqual(1,
 
81
                len(stacked_tree.branch.repository._fallback_repositories))
 
82
        self.build_tree_contents([('stacked/f1.txt', 'new content\n')])
 
83
        stacked_tree.commit('new content', rev_id='new-rev-id')
 
84
        # We open the repository without fallbacks to ensure the data is
 
85
        # locally true
 
86
        stacked_only_repo = self.get_only_repo(stacked_tree)
 
87
        # We should have the immediate parent inventory available, but not the
 
88
        # grandparent's
 
89
        self.assertPresent([self.r2_key],
 
90
            stacked_only_repo.inventories, [self.r1_key, self.r2_key])
 
91
        # And we should be able to pull this revision into another stacked
 
92
        # branch
 
93
        stacked2_branch = base_tree.bzrdir.sprout('stacked2',
 
94
                                                  stacked=True).open_branch()
 
95
        stacked2_branch.repository.fetch(stacked_only_repo,
 
96
                                         revision_id='new-rev-id')
 
97
 
 
98
    def test_merge_commit(self):
 
99
        base_tree, stacked_tree = self.make_stacked_target()
 
100
        self.build_tree_contents([('base/f1.txt', 'new content\n')])
 
101
        r3_key = ('rev3-id',)
 
102
        base_tree.commit('second base', rev_id=r3_key[0])
 
103
        to_be_merged_tree = base_tree.bzrdir.sprout('merged'
 
104
            ).open_workingtree()
 
105
        self.build_tree(['merged/f2.txt'])
 
106
        to_be_merged_tree.add(['f2.txt'], ['f2.txt-id'])
 
107
        to_merge_key = ('to-merge-rev-id',)
 
108
        to_be_merged_tree.commit('new-to-be-merged', rev_id=to_merge_key[0])
 
109
        stacked_tree.merge_from_branch(to_be_merged_tree.branch)
 
110
        merged_key = ('merged-rev-id',)
 
111
        stacked_tree.commit('merge', rev_id=merged_key[0])
 
112
        # to-merge isn't in base, so it should be in stacked.
 
113
        # rev3-id is a parent of a revision we have, so we should have the
 
114
        # inventory, but not the revision.
 
115
        # merged has a parent of r2, so we should also have r2's
 
116
        # inventory-but-not-revision.
 
117
        # Nothing has r1 directly, so we shouldn't have anything present for it
 
118
        stacked_only_repo = self.get_only_repo(stacked_tree)
 
119
        all_keys = [self.r1_key, self.r2_key, r3_key, to_merge_key, merged_key]
 
120
        self.assertPresent([to_merge_key, merged_key],
 
121
                           stacked_only_repo.revisions, all_keys)
 
122
        self.assertPresent([self.r2_key, r3_key, to_merge_key, merged_key],
 
123
                           stacked_only_repo.inventories, all_keys)
 
124
 
 
125
    def test_merge_from_master(self):
 
126
        base_tree, stacked_tree = self.make_stacked_target()
 
127
        self.build_tree_contents([('base/f1.txt', 'new content\n')])
 
128
        r3_key = ('rev3-id',)
 
129
        base_tree.commit('second base', rev_id=r3_key[0])
 
130
        stacked_tree.merge_from_branch(base_tree.branch)
 
131
        merged_key = ('merged-rev-id',)
 
132
        stacked_tree.commit('merge', rev_id=merged_key[0])
 
133
        all_keys = [self.r1_key, self.r2_key, r3_key, merged_key]
 
134
        # We shouldn't have any of the base revisions in the local repo, but we
 
135
        # should have both base inventories.
 
136
        stacked_only_repo = self.get_only_repo(stacked_tree)
 
137
        self.assertPresent([merged_key],
 
138
                           stacked_only_repo.revisions, all_keys)
 
139
        self.assertPresent([self.r2_key, r3_key, merged_key],
 
140
                           stacked_only_repo.inventories, all_keys)
 
141
 
 
142
    def test_multi_stack(self):
 
143
        """base + stacked + stacked-on-stacked"""
 
144
        base_tree, stacked_tree = self.make_stacked_target()
 
145
        self.build_tree(['stacked/f3.txt'])
 
146
        stacked_tree.add(['f3.txt'], ['f3.txt-id'])
 
147
        stacked_key = ('stacked-rev-id',)
 
148
        stacked_tree.commit('add f3', rev_id=stacked_key[0])
 
149
        stacked_only_repo = self.get_only_repo(stacked_tree)
 
150
        self.assertPresent([self.r2_key], stacked_only_repo.inventories,
 
151
                           [self.r1_key, self.r2_key])
 
152
        # This ensures we get a Remote URL, rather than a local one.
 
153
        stacked2_url = urlutils.join(base_tree.branch.base, '../stacked2')
 
154
        stacked2_bzrdir = stacked_tree.bzrdir.sprout(stacked2_url,
 
155
                            revision_id=self.r1_key[0],
 
156
                            stacked=True)
 
157
        if isinstance(stacked2_bzrdir, remote.RemoteBzrDir):
 
158
            stacked2_branch = stacked2_bzrdir.open_branch()
 
159
            stacked2_tree = stacked2_branch.create_checkout('stacked2',
 
160
                lightweight=True)
 
161
        else:
 
162
            stacked2_tree = stacked2_bzrdir.open_workingtree()
 
163
        # stacked2 is stacked on stacked, but its content is rev1, so
 
164
        # it needs to pull the basis information from a fallback-of-fallback.
 
165
        self.build_tree(['stacked2/f3.txt'])
 
166
        stacked2_only_repo = self.get_only_repo(stacked2_tree)
 
167
        self.assertPresent([], stacked2_only_repo.inventories,
 
168
                           [self.r1_key, self.r2_key])
 
169
        stacked2_tree.add(['f3.txt'], ['f3.txt-id'])
 
170
        stacked2_tree.commit('add f3', rev_id='stacked2-rev-id')
 
171
        # We added data to this read-locked repo, so refresh it
 
172
        stacked2_only_repo.refresh_data()
 
173
        self.assertPresent([self.r1_key], stacked2_only_repo.inventories,
 
174
                           [self.r1_key, self.r2_key])
 
175
 
 
176
    def test_commit_with_ghosts_fails(self):
 
177
        base_tree, stacked_tree = self.make_stacked_target()
 
178
        stacked_tree.set_parent_ids([stacked_tree.last_revision(),
 
179
                                     'ghost-rev-id'])
 
180
        self.assertRaises(errors.BzrError,
 
181
            stacked_tree.commit, 'failed_commit')
 
182
 
 
183
    def test_commit_with_ghost_in_ancestry(self):
 
184
        base_tree, stacked_tree = self.make_stacked_target()
 
185
        self.build_tree_contents([('base/f1.txt', 'new content\n')])
 
186
        r3_key = ('rev3-id',)
 
187
        base_tree.commit('second base', rev_id=r3_key[0])
 
188
        to_be_merged_tree = base_tree.bzrdir.sprout('merged'
 
189
            ).open_workingtree()
 
190
        self.build_tree(['merged/f2.txt'])
 
191
        to_be_merged_tree.add(['f2.txt'], ['f2.txt-id'])
 
192
        ghost_key = ('ghost-rev-id',)
 
193
        to_be_merged_tree.set_parent_ids([r3_key[0], ghost_key[0]])
 
194
        to_merge_key = ('to-merge-rev-id',)
 
195
        to_be_merged_tree.commit('new-to-be-merged', rev_id=to_merge_key[0])
 
196
        stacked_tree.merge_from_branch(to_be_merged_tree.branch)
 
197
        merged_key = ('merged-rev-id',)
 
198
        stacked_tree.commit('merge', rev_id=merged_key[0])
 
199
        # vs test_merge_commit, the fetch for 'merge_from_branch' should
 
200
        # already have handled that 'ghost-rev-id' is a ghost, and commit
 
201
        # should not try to fill it in at this point.
 
202
        stacked_only_repo = self.get_only_repo(stacked_tree)
 
203
        all_keys = [self.r1_key, self.r2_key, r3_key, to_merge_key, merged_key,
 
204
                    ghost_key]
 
205
        self.assertPresent([to_merge_key, merged_key],
 
206
                           stacked_only_repo.revisions, all_keys)
 
207
        self.assertPresent([self.r2_key, r3_key, to_merge_key, merged_key],
 
208
                           stacked_only_repo.inventories, all_keys)
 
209
 
 
210
 
 
211
class TestCommitStackedFailsAppropriately(TestCaseWithStackedTarget):
 
212
 
 
213
    def test_stacked_commit_fails_on_old_formats(self):
 
214
        base_tree, stacked_tree = self.make_stacked_target()
 
215
        format = stacked_tree.branch.repository._format
 
216
        if format.supports_chks:
 
217
            stacked_tree.commit('should succeed')
 
218
        else:
 
219
            self.assertRaises(errors.BzrError,
 
220
                stacked_tree.commit, 'unsupported format')