1# Copyright (C) 2005-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"""Tests for upgrade of old trees.
18
19This file contains canned versions of some old trees, which are instantiated
20and then upgraded to the new format."""
21
22# TODO queue for upgrade:
23# test the error message when upgrading an unknown BzrDir format.
24
25from .. import (
26    branch,
27    controldir,
28    tests,
29    upgrade,
30    )
31from ..bzr import (
32    branch as bzrbranch,
33    workingtree,
34    workingtree_4,
35    )
36
37
38class TestUpgrade(tests.TestCaseWithTransport):
39
40    def test_upgrade_rich_root(self):
41        tree = self.make_branch_and_tree('tree', format='rich-root')
42        tree.commit('first post')
43        upgrade.upgrade('tree')
44
45    def test_convert_branch5_branch6(self):
46        b = self.make_branch('branch', format='knit')
47        b._set_revision_history([b'CD'])
48        b.set_parent('file:///EF')
49        b.set_bound_location('file:///GH')
50        b.set_push_location('file:///IJ')
51        target = controldir.format_registry.make_controldir(
52            'dirstate-with-subtree')
53        converter = b.controldir._format.get_converter(target)
54        converter.convert(b.controldir, None)
55        new_branch = branch.Branch.open(self.get_url('branch'))
56        self.assertIs(new_branch.__class__, bzrbranch.BzrBranch6)
57        self.assertEqual(b'CD', new_branch.last_revision())
58        self.assertEqual('file:///EF', new_branch.get_parent())
59        self.assertEqual('file:///GH', new_branch.get_bound_location())
60        branch_config = new_branch.get_config_stack()
61        self.assertEqual('file:///IJ', branch_config.get('push_location'))
62
63        b2 = self.make_branch('branch2', format='knit')
64        converter = b2.controldir._format.get_converter(target)
65        converter.convert(b2.controldir, None)
66        b2 = branch.Branch.open(self.get_url('branch'))
67        self.assertIs(b2.__class__, bzrbranch.BzrBranch6)
68
69    def test_convert_branch7_branch8(self):
70        b = self.make_branch('branch', format='1.9')
71        target = controldir.format_registry.make_controldir('1.9')
72        target.set_branch_format(bzrbranch.BzrBranchFormat8())
73        converter = b.controldir._format.get_converter(target)
74        converter.convert(b.controldir, None)
75        b = branch.Branch.open(self.get_url('branch'))
76        self.assertIs(b.__class__, bzrbranch.BzrBranch8)
77        self.assertEqual({}, b._get_all_reference_info())
78
79    def test_convert_knit_dirstate_empty(self):
80        # test that asking for an upgrade from knit to dirstate works.
81        tree = self.make_branch_and_tree('tree', format='knit')
82        target = controldir.format_registry.make_controldir('dirstate')
83        converter = tree.controldir._format.get_converter(target)
84        converter.convert(tree.controldir, None)
85        new_tree = workingtree.WorkingTree.open('tree')
86        self.assertIs(new_tree.__class__, workingtree_4.WorkingTree4)
87        self.assertEqual(b'null:', new_tree.last_revision())
88
89    def test_convert_knit_dirstate_content(self):
90        # smoke test for dirstate conversion: we call dirstate primitives,
91        # and its there that the core logic is tested.
92        tree = self.make_branch_and_tree('tree', format='knit')
93        self.build_tree(['tree/file'])
94        tree.add(['file'], [b'file-id'])
95        target = controldir.format_registry.make_controldir('dirstate')
96        converter = tree.controldir._format.get_converter(target)
97        converter.convert(tree.controldir, None)
98        new_tree = workingtree.WorkingTree.open('tree')
99        self.assertIs(new_tree.__class__, workingtree_4.WorkingTree4)
100        self.assertEqual(b'null:', new_tree.last_revision())
101
102    def test_convert_knit_one_parent_dirstate(self):
103        # test that asking for an upgrade from knit to dirstate works.
104        tree = self.make_branch_and_tree('tree', format='knit')
105        rev_id = tree.commit('first post')
106        target = controldir.format_registry.make_controldir('dirstate')
107        converter = tree.controldir._format.get_converter(target)
108        converter.convert(tree.controldir, None)
109        new_tree = workingtree.WorkingTree.open('tree')
110        self.assertIs(new_tree.__class__, workingtree_4.WorkingTree4)
111        self.assertEqual(rev_id, new_tree.last_revision())
112        for path in ['basis-inventory-cache', 'inventory', 'last-revision',
113                     'pending-merges', 'stat-cache']:
114            self.assertPathDoesNotExist('tree/.bzr/checkout/' + path)
115
116    def test_convert_knit_merges_dirstate(self):
117        tree = self.make_branch_and_tree('tree', format='knit')
118        tree.commit('first post')
119        merge_tree = tree.controldir.sprout('tree2').open_workingtree()
120        rev_id2 = tree.commit('second post')
121        rev_id3 = merge_tree.commit('second merge post')
122        tree.merge_from_branch(merge_tree.branch)
123        target = controldir.format_registry.make_controldir('dirstate')
124        converter = tree.controldir._format.get_converter(target)
125        converter.convert(tree.controldir, None)
126        new_tree = workingtree.WorkingTree.open('tree')
127        self.assertIs(new_tree.__class__, workingtree_4.WorkingTree4)
128        self.assertEqual(rev_id2, new_tree.last_revision())
129        self.assertEqual([rev_id2, rev_id3], new_tree.get_parent_ids())
130        for path in ['basis-inventory-cache', 'inventory', 'last-revision',
131                     'pending-merges', 'stat-cache']:
132            self.assertPathDoesNotExist('tree/.bzr/checkout/' + path)
133
134
135class TestSmartUpgrade(tests.TestCaseWithTransport):
136
137    from_format = controldir.format_registry.make_controldir("pack-0.92")
138    to_format = controldir.format_registry.make_controldir("2a")
139
140    def make_standalone_branch(self):
141        wt = self.make_branch_and_tree("branch1", format=self.from_format)
142        return wt.controldir
143
144    def test_upgrade_standalone_branch(self):
145        control = self.make_standalone_branch()
146        tried, worked, issues = upgrade.smart_upgrade(
147            [control], format=self.to_format)
148        self.assertLength(1, tried)
149        self.assertEqual(tried[0], control)
150        self.assertLength(1, worked)
151        self.assertEqual(worked[0], control)
152        self.assertLength(0, issues)
153        self.assertPathExists('branch1/backup.bzr.~1~')
154        self.assertEqual(control.open_repository()._format,
155                         self.to_format._repository_format)
156
157    def test_upgrade_standalone_branch_cleanup(self):
158        control = self.make_standalone_branch()
159        tried, worked, issues = upgrade.smart_upgrade(
160            [control], format=self.to_format, clean_up=True)
161        self.assertLength(1, tried)
162        self.assertEqual(tried[0], control)
163        self.assertLength(1, worked)
164        self.assertEqual(worked[0], control)
165        self.assertLength(0, issues)
166        self.assertPathExists('branch1')
167        self.assertPathExists('branch1/.bzr')
168        self.assertPathDoesNotExist('branch1/backup.bzr.~1~')
169        self.assertEqual(control.open_repository()._format,
170                         self.to_format._repository_format)
171
172    def make_repo_with_branches(self):
173        repo = self.make_repository('repo', shared=True,
174                                    format=self.from_format)
175        # Note: self.make_branch() always creates a new repo at the location
176        # so we need to avoid using that here ...
177        controldir.ControlDir.create_branch_convenience(
178            "repo/branch1", format=self.from_format)
179        b2 = controldir.ControlDir.create_branch_convenience(
180            "repo/branch2", format=self.from_format)
181        return repo.controldir
182
183    def test_upgrade_repo_with_branches(self):
184        control = self.make_repo_with_branches()
185        tried, worked, issues = upgrade.smart_upgrade(
186            [control], format=self.to_format)
187        self.assertLength(3, tried)
188        self.assertEqual(tried[0], control)
189        self.assertLength(3, worked)
190        self.assertEqual(worked[0], control)
191        self.assertLength(0, issues)
192        self.assertPathExists('repo/backup.bzr.~1~')
193        self.assertPathExists('repo/branch1/backup.bzr.~1~')
194        self.assertPathExists('repo/branch2/backup.bzr.~1~')
195        self.assertEqual(control.open_repository()._format,
196                         self.to_format._repository_format)
197        b1 = branch.Branch.open('repo/branch1')
198        self.assertEqual(b1._format, self.to_format._branch_format)
199
200    def test_upgrade_repo_with_branches_cleanup(self):
201        control = self.make_repo_with_branches()
202        tried, worked, issues = upgrade.smart_upgrade(
203            [control], format=self.to_format, clean_up=True)
204        self.assertLength(3, tried)
205        self.assertEqual(tried[0], control)
206        self.assertLength(3, worked)
207        self.assertEqual(worked[0], control)
208        self.assertLength(0, issues)
209        self.assertPathExists('repo')
210        self.assertPathExists('repo/.bzr')
211        self.assertPathDoesNotExist('repo/backup.bzr.~1~')
212        self.assertPathDoesNotExist('repo/branch1/backup.bzr.~1~')
213        self.assertPathDoesNotExist('repo/branch2/backup.bzr.~1~')
214        self.assertEqual(control.open_repository()._format,
215                         self.to_format._repository_format)
216        b1 = branch.Branch.open('repo/branch1')
217        self.assertEqual(b1._format, self.to_format._branch_format)
218