1# Copyright (C) 2008-2012, 2016 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 Branch.get_stacked_on_url and set_stacked_on_url.""" 18 19from breezy import ( 20 branch as _mod_branch, 21 controldir, 22 check, 23 errors, 24 ) 25from breezy.revision import NULL_REVISION 26from breezy.tests import fixtures, TestNotApplicable, transport_util 27from breezy.tests.per_branch import TestCaseWithBranch 28 29 30unstackable_format_errors = ( 31 _mod_branch.UnstackableBranchFormat, 32 errors.UnstackableRepositoryFormat, 33 ) 34 35 36class TestStacking(TestCaseWithBranch): 37 38 def check_lines_added_or_present(self, stacked_branch, revid): 39 # similar to a failure seen in bug 288751 by mbp 20081120 40 stacked_repo = stacked_branch.repository 41 with stacked_repo.lock_read(): 42 list(stacked_repo.inventories.iter_lines_added_or_present_in_keys( 43 [(revid,)])) 44 45 def test_get_set_stacked_on_url(self): 46 # branches must either: 47 # raise UnstackableBranchFormat or 48 # raise UnstackableRepositoryFormat or 49 # permit stacking to be done and then return the stacked location. 50 branch = self.make_branch('branch') 51 target = self.make_branch('target') 52 try: 53 branch.set_stacked_on_url(target.base) 54 except unstackable_format_errors: 55 # if the set failed, so must the get 56 self.assertRaises(unstackable_format_errors, 57 branch.get_stacked_on_url) 58 self.assertFalse(branch._format.supports_stacking()) 59 return 60 self.assertTrue(branch._format.supports_stacking()) 61 # now we have a stacked branch: 62 self.assertEqual(target.base, branch.get_stacked_on_url()) 63 branch.set_stacked_on_url(None) 64 self.assertRaises(errors.NotStacked, branch.get_stacked_on_url) 65 66 def test_get_set_stacked_on_relative(self): 67 # Branches can be stacked on other branches using relative paths. 68 branch = self.make_branch('branch') 69 target = self.make_branch('target') 70 try: 71 branch.set_stacked_on_url('../target') 72 except unstackable_format_errors: 73 # if the set failed, so must the get 74 self.assertRaises(unstackable_format_errors, 75 branch.get_stacked_on_url) 76 return 77 self.assertEqual('../target', branch.get_stacked_on_url()) 78 79 def test_set_stacked_on_same_branch_raises(self): 80 # Stacking on the same branch silently raises and doesn't execute the 81 # change. Reported in bug 376243. 82 branch = self.make_branch('branch') 83 try: 84 self.assertRaises(errors.UnstackableLocationError, 85 branch.set_stacked_on_url, '../branch') 86 except unstackable_format_errors: 87 # if the set failed, so must the get 88 self.assertRaises(unstackable_format_errors, 89 branch.get_stacked_on_url) 90 return 91 self.assertRaises(errors.NotStacked, branch.get_stacked_on_url) 92 93 def test_set_stacked_on_same_branch_after_being_stacked_raises(self): 94 # Stacking on the same branch silently raises and doesn't execute the 95 # change. 96 branch = self.make_branch('branch') 97 target = self.make_branch('target') 98 try: 99 branch.set_stacked_on_url('../target') 100 except unstackable_format_errors: 101 # if the set failed, so must the get 102 self.assertRaises(unstackable_format_errors, 103 branch.get_stacked_on_url) 104 return 105 self.assertRaises(errors.UnstackableLocationError, 106 branch.set_stacked_on_url, '../branch') 107 self.assertEqual('../target', branch.get_stacked_on_url()) 108 109 def assertRevisionInRepository(self, repo_path, revid): 110 """Check that a revision is in a repository, disregarding stacking.""" 111 repo = controldir.ControlDir.open(repo_path).open_repository() 112 self.assertTrue(repo.has_revision(revid)) 113 114 def assertRevisionNotInRepository(self, repo_path, revid): 115 """Check that a revision is not in a repository, disregarding stacking.""" 116 repo = controldir.ControlDir.open(repo_path).open_repository() 117 self.assertFalse(repo.has_revision(revid)) 118 119 def test_get_graph_stacked(self): 120 """A stacked repository shows the graph of its parent.""" 121 trunk_tree = self.make_branch_and_tree('mainline') 122 trunk_revid = trunk_tree.commit('mainline') 123 # make a new branch, and stack on the existing one. we don't use 124 # sprout(stacked=True) here because if that is buggy and copies data 125 # it would cause a false pass of this test. 126 new_branch = self.make_branch('new_branch') 127 try: 128 new_branch.set_stacked_on_url(trunk_tree.branch.base) 129 except unstackable_format_errors as e: 130 raise TestNotApplicable(e) 131 # reading the graph from the stacked branch's repository should see 132 # data from the stacked-on branch 133 new_repo = new_branch.repository 134 with new_repo.lock_read(): 135 self.assertEqual(new_repo.get_parent_map([trunk_revid]), 136 {trunk_revid: (NULL_REVISION, )}) 137 138 def test_sprout_stacked(self): 139 # We have a mainline 140 trunk_tree = self.make_branch_and_tree('mainline') 141 trunk_revid = trunk_tree.commit('mainline') 142 # and make branch from it which is stacked 143 try: 144 new_dir = trunk_tree.controldir.sprout('newbranch', stacked=True) 145 except unstackable_format_errors as e: 146 raise TestNotApplicable(e) 147 # stacked repository 148 self.assertRevisionNotInRepository('newbranch', trunk_revid) 149 tree = new_dir.open_branch().create_checkout('local') 150 new_branch_revid = tree.commit('something local') 151 self.assertRevisionNotInRepository( 152 trunk_tree.branch.base, new_branch_revid) 153 self.assertRevisionInRepository('newbranch', new_branch_revid) 154 155 def test_sprout_stacked_from_smart_server(self): 156 # We have a mainline 157 trunk_tree = self.make_branch_and_tree('mainline') 158 trunk_revid = trunk_tree.commit('mainline') 159 # Make sure that we can make a stacked branch from it 160 try: 161 trunk_tree.controldir.sprout('testbranch', stacked=True) 162 except unstackable_format_errors as e: 163 raise TestNotApplicable(e) 164 # Now serve the original mainline from a smart server 165 remote_transport = self.make_smart_server('mainline') 166 remote_bzrdir = controldir.ControlDir.open_from_transport( 167 remote_transport) 168 # and make branch from the smart server which is stacked 169 new_dir = remote_bzrdir.sprout('newbranch', stacked=True) 170 # stacked repository 171 self.assertRevisionNotInRepository('newbranch', trunk_revid) 172 tree = new_dir.open_branch().create_checkout('local') 173 new_branch_revid = tree.commit('something local') 174 self.assertRevisionNotInRepository(trunk_tree.branch.user_url, 175 new_branch_revid) 176 self.assertRevisionInRepository('newbranch', new_branch_revid) 177 178 def test_unstack_fetches(self): 179 """Removing the stacked-on branch pulls across all data""" 180 try: 181 builder = self.make_branch_builder('trunk') 182 except errors.UninitializableFormat: 183 raise TestNotApplicable('uninitializeable format') 184 # We have a mainline 185 trunk, mainline_revid, rev2 = fixtures.build_branch_with_non_ancestral_rev( 186 builder) 187 # and make branch from it which is stacked (with no tags) 188 try: 189 new_dir = trunk.controldir.sprout( 190 self.get_url('newbranch'), stacked=True) 191 except unstackable_format_errors as e: 192 raise TestNotApplicable(e) 193 # stacked repository 194 self.assertRevisionNotInRepository('newbranch', mainline_revid) 195 # TODO: we'd like to commit in the stacked repository; that requires 196 # some care (maybe a BranchBuilder) if it's remote and has no 197 # workingtree 198 # newbranch_revid = new_dir.open_workingtree().commit('revision in ' 199 # 'newbranch') 200 # now when we unstack that should implicitly fetch, to make sure that 201 # the branch will still work 202 new_branch = new_dir.open_branch() 203 try: 204 new_branch.tags.set_tag('tag-a', rev2) 205 except errors.TagsNotSupported: 206 tags_supported = False 207 else: 208 tags_supported = True 209 new_branch.set_stacked_on_url(None) 210 self.assertRevisionInRepository('newbranch', mainline_revid) 211 # of course it's still in the mainline 212 self.assertRevisionInRepository('trunk', mainline_revid) 213 if tags_supported: 214 # the tagged revision in trunk is now in newbranch too 215 self.assertRevisionInRepository('newbranch', rev2) 216 # and now we're no longer stacked 217 self.assertRaises(errors.NotStacked, new_branch.get_stacked_on_url) 218 219 def test_unstack_already_locked(self): 220 """Removing the stacked-on branch with an already write-locked branch 221 works. 222 223 This was bug 551525. 224 """ 225 try: 226 stacked_bzrdir = self.make_stacked_bzrdir() 227 except unstackable_format_errors as e: 228 raise TestNotApplicable(e) 229 stacked_branch = stacked_bzrdir.open_branch() 230 stacked_branch.lock_write() 231 stacked_branch.set_stacked_on_url(None) 232 stacked_branch.unlock() 233 234 def test_unstack_already_multiple_locked(self): 235 """Unstacking a branch preserves the lock count (even though it 236 replaces the br.repository object). 237 238 This is a more extreme variation of test_unstack_already_locked. 239 """ 240 try: 241 stacked_bzrdir = self.make_stacked_bzrdir() 242 except unstackable_format_errors as e: 243 raise TestNotApplicable(e) 244 stacked_branch = stacked_bzrdir.open_branch() 245 stacked_branch.lock_write() 246 stacked_branch.lock_write() 247 stacked_branch.lock_write() 248 stacked_branch.set_stacked_on_url(None) 249 stacked_branch.unlock() 250 stacked_branch.unlock() 251 stacked_branch.unlock() 252 253 def make_stacked_bzrdir(self, in_directory=None): 254 """Create a stacked branch and return its bzrdir. 255 256 :param in_directory: If not None, create a directory of this 257 name and create the stacking and stacked-on bzrdirs in 258 this directory. 259 """ 260 if in_directory is not None: 261 self.get_transport().mkdir(in_directory) 262 prefix = in_directory + '/' 263 else: 264 prefix = '' 265 tree = self.make_branch_and_tree(prefix + 'stacked-on') 266 tree.commit('Added foo') 267 stacked_bzrdir = tree.branch.controldir.sprout( 268 self.get_url(prefix + 'stacked'), tree.branch.last_revision(), 269 stacked=True) 270 return stacked_bzrdir 271 272 def test_clone_from_stacked_branch_preserve_stacking(self): 273 # We can clone from the bzrdir of a stacked branch. If 274 # preserve_stacking is True, the cloned branch is stacked on the 275 # same branch as the original. 276 try: 277 stacked_bzrdir = self.make_stacked_bzrdir() 278 except unstackable_format_errors as e: 279 raise TestNotApplicable(e) 280 cloned_bzrdir = stacked_bzrdir.clone('cloned', preserve_stacking=True) 281 try: 282 self.assertEqual( 283 stacked_bzrdir.open_branch().get_stacked_on_url(), 284 cloned_bzrdir.open_branch().get_stacked_on_url()) 285 except unstackable_format_errors as e: 286 pass 287 288 def test_clone_from_branch_stacked_on_relative_url_preserve_stacking(self): 289 # If a branch's stacked-on url is relative, we can still clone 290 # from it with preserve_stacking True and get a branch stacked 291 # on an appropriately adjusted relative url. 292 try: 293 stacked_bzrdir = self.make_stacked_bzrdir(in_directory='dir') 294 except unstackable_format_errors as e: 295 raise TestNotApplicable(e) 296 stacked_bzrdir.open_branch().set_stacked_on_url('../stacked-on') 297 cloned_bzrdir = stacked_bzrdir.clone( 298 self.get_url('cloned'), preserve_stacking=True) 299 self.assertEqual( 300 '../dir/stacked-on', 301 cloned_bzrdir.open_branch().get_stacked_on_url()) 302 303 def test_clone_from_stacked_branch_no_preserve_stacking(self): 304 try: 305 stacked_bzrdir = self.make_stacked_bzrdir() 306 except unstackable_format_errors as e: 307 # not a testable combination. 308 raise TestNotApplicable(e) 309 cloned_unstacked_bzrdir = stacked_bzrdir.clone('cloned-unstacked', 310 preserve_stacking=False) 311 unstacked_branch = cloned_unstacked_bzrdir.open_branch() 312 self.assertRaises((errors.NotStacked, _mod_branch.UnstackableBranchFormat), 313 unstacked_branch.get_stacked_on_url) 314 315 def test_no_op_preserve_stacking(self): 316 """With no stacking, preserve_stacking should be a no-op.""" 317 branch = self.make_branch('source') 318 cloned_bzrdir = branch.controldir.clone( 319 'cloned', preserve_stacking=True) 320 self.assertRaises((errors.NotStacked, _mod_branch.UnstackableBranchFormat), 321 cloned_bzrdir.open_branch().get_stacked_on_url) 322 323 def make_stacked_on_matching(self, source): 324 if source.repository.supports_rich_root(): 325 if source.repository._format.supports_chks: 326 format = "2a" 327 else: 328 format = "1.9-rich-root" 329 else: 330 format = "1.9" 331 return self.make_branch('stack-on', format) 332 333 def test_sprout_stacking_policy_handling(self): 334 """Obey policy where possible, ignore otherwise.""" 335 if self.bzrdir_format.fixed_components: 336 raise TestNotApplicable('Branch format 4 does not autoupgrade.') 337 source = self.make_branch('source') 338 stack_on = self.make_stacked_on_matching(source) 339 parent_bzrdir = self.make_controldir('.', format='default') 340 parent_bzrdir.get_config().set_default_stack_on('stack-on') 341 target = source.controldir.sprout('target').open_branch() 342 # When we sprout we upgrade the branch when there is a default stack_on 343 # set by a config *and* the targeted branch supports stacking. 344 if stack_on._format.supports_stacking(): 345 self.assertEqual('../stack-on', target.get_stacked_on_url()) 346 else: 347 self.assertRaises( 348 branch.UnstackableBranchFormat, target.get_stacked_on_url) 349 350 def test_clone_stacking_policy_handling(self): 351 """Obey policy where possible, ignore otherwise.""" 352 if self.bzrdir_format.fixed_components: 353 raise TestNotApplicable('Branch format 4 does not autoupgrade.') 354 source = self.make_branch('source') 355 stack_on = self.make_stacked_on_matching(source) 356 parent_bzrdir = self.make_controldir('.', format='default') 357 parent_bzrdir.get_config().set_default_stack_on('stack-on') 358 target = source.controldir.clone('target').open_branch() 359 # When we clone we upgrade the branch when there is a default stack_on 360 # set by a config *and* the targeted branch supports stacking. 361 if stack_on._format.supports_stacking(): 362 self.assertEqual('../stack-on', target.get_stacked_on_url()) 363 else: 364 self.assertRaises( 365 _mod_branch.UnstackableBranchFormat, target.get_stacked_on_url) 366 367 def test_sprout_to_smart_server_stacking_policy_handling(self): 368 """Obey policy where possible, ignore otherwise.""" 369 if not self.branch_format.supports_leaving_lock(): 370 raise TestNotApplicable('Branch format is not usable via HPSS.') 371 source = self.make_branch('source') 372 stack_on = self.make_stacked_on_matching(source) 373 parent_bzrdir = self.make_controldir('.', format='default') 374 parent_bzrdir.get_config().set_default_stack_on('stack-on') 375 url = self.make_smart_server('target').base 376 target = source.controldir.sprout(url).open_branch() 377 # When we sprout we upgrade the branch when there is a default stack_on 378 # set by a config *and* the targeted branch supports stacking. 379 if stack_on._format.supports_stacking(): 380 self.assertEqual('../stack-on', target.get_stacked_on_url()) 381 else: 382 self.assertRaises( 383 _mod_branch.UnstackableBranchFormat, target.get_stacked_on_url) 384 385 def prepare_stacked_on_fetch(self): 386 stack_on = self.make_branch_and_tree('stack-on') 387 rev1 = stack_on.commit('first commit') 388 try: 389 stacked_dir = stack_on.controldir.sprout('stacked', stacked=True) 390 except unstackable_format_errors as e: 391 raise TestNotApplicable('Format does not support stacking.') 392 unstacked = self.make_repository('unstacked') 393 return stacked_dir.open_workingtree(), unstacked, rev1 394 395 def test_fetch_copies_from_stacked_on(self): 396 stacked, unstacked, rev1 = self.prepare_stacked_on_fetch() 397 unstacked.fetch(stacked.branch.repository, rev1) 398 unstacked.get_revision(rev1) 399 400 def test_fetch_copies_from_stacked_on_and_stacked(self): 401 stacked, unstacked, rev1 = self.prepare_stacked_on_fetch() 402 tree = stacked.branch.create_checkout('local') 403 rev2 = tree.commit('second commit') 404 unstacked.fetch(stacked.branch.repository, rev2) 405 unstacked.get_revision(rev1) 406 unstacked.get_revision(rev2) 407 self.check_lines_added_or_present(stacked.branch, rev1) 408 self.check_lines_added_or_present(stacked.branch, rev2) 409 410 def test_autopack_when_stacked(self): 411 # in bzr.dev as of 20080730, autopack was reported to fail in stacked 412 # repositories because of problems with text deltas spanning physical 413 # repository boundaries. however, i didn't actually get this test to 414 # fail on that code. -- mbp 415 # see https://bugs.launchpad.net/bzr/+bug/252821 416 stack_on = self.make_branch_and_tree('stack-on') 417 if not stack_on.branch._format.supports_stacking(): 418 raise TestNotApplicable("%r does not support stacking" 419 % self.branch_format) 420 text_lines = [b'line %d blah blah blah\n' % i for i in range(20)] 421 self.build_tree_contents([('stack-on/a', b''.join(text_lines))]) 422 stack_on.add('a') 423 stack_on.commit('base commit') 424 stacked_dir = stack_on.controldir.sprout('stacked', stacked=True) 425 stacked_branch = stacked_dir.open_branch() 426 local_tree = stack_on.controldir.sprout('local').open_workingtree() 427 for i in range(20): 428 text_lines[0] = b'changed in %d\n' % i 429 self.build_tree_contents([('local/a', b''.join(text_lines))]) 430 local_tree.commit('commit %d' % i) 431 local_tree.branch.push(stacked_branch) 432 stacked_branch.repository.pack() 433 check.check_dwim(stacked_branch.base, False, True, True) 434 435 def test_pull_delta_when_stacked(self): 436 if not self.branch_format.supports_stacking(): 437 raise TestNotApplicable("%r does not support stacking" 438 % self.branch_format) 439 stack_on = self.make_branch_and_tree('stack-on') 440 text_lines = [b'line %d blah blah blah\n' % i for i in range(20)] 441 self.build_tree_contents([('stack-on/a', b''.join(text_lines))]) 442 stack_on.add('a') 443 stack_on.commit('base commit') 444 # make a stacked branch from the mainline 445 stacked_dir = stack_on.controldir.sprout('stacked', stacked=True) 446 stacked_tree = stacked_dir.open_workingtree() 447 # make a second non-stacked branch from the mainline 448 other_dir = stack_on.controldir.sprout('other') 449 other_tree = other_dir.open_workingtree() 450 text_lines[9] = b'changed in other\n' 451 self.build_tree_contents([('other/a', b''.join(text_lines))]) 452 stacked_revid = other_tree.commit('commit in other') 453 # this should have generated a delta; try to pull that across 454 # bug 252821 caused a RevisionNotPresent here... 455 stacked_tree.pull(other_tree.branch) 456 stacked_tree.branch.repository.pack() 457 check.check_dwim(stacked_tree.branch.base, False, True, True) 458 self.check_lines_added_or_present(stacked_tree.branch, stacked_revid) 459 460 def test_fetch_revisions_with_file_changes(self): 461 # Fetching revisions including file changes into a stacked branch 462 # works without error. 463 # Make the source tree. 464 src_tree = self.make_branch_and_tree('src') 465 self.build_tree_contents([('src/a', b'content')]) 466 src_tree.add('a') 467 src_tree.commit('first commit') 468 469 # Make the stacked-on branch. 470 src_tree.controldir.sprout('stacked-on') 471 472 # Make a branch stacked on it. 473 target = self.make_branch('target') 474 try: 475 target.set_stacked_on_url('../stacked-on') 476 except unstackable_format_errors as e: 477 raise TestNotApplicable('Format does not support stacking.') 478 479 # Change the source branch. 480 self.build_tree_contents([('src/a', b'new content')]) 481 rev2 = src_tree.commit('second commit') 482 483 # Fetch changes to the target. 484 target.fetch(src_tree.branch) 485 rtree = target.repository.revision_tree(rev2) 486 rtree.lock_read() 487 self.addCleanup(rtree.unlock) 488 self.assertEqual(b'new content', rtree.get_file_text('a')) 489 self.check_lines_added_or_present(target, rev2) 490 491 def test_transform_fallback_location_hook(self): 492 # The 'transform_fallback_location' branch hook allows us to inspect 493 # and transform the URL of the fallback location for the branch. 494 stack_on = self.make_branch('stack-on') 495 stacked = self.make_branch('stacked') 496 try: 497 stacked.set_stacked_on_url('../stack-on') 498 except unstackable_format_errors as e: 499 raise TestNotApplicable('Format does not support stacking.') 500 self.get_transport().rename('stack-on', 'new-stack-on') 501 hook_calls = [] 502 503 def hook(stacked_branch, url): 504 hook_calls.append(url) 505 return '../new-stack-on' 506 _mod_branch.Branch.hooks.install_named_hook( 507 'transform_fallback_location', hook, None) 508 _mod_branch.Branch.open('stacked') 509 self.assertEqual(['../stack-on'], hook_calls) 510 511 def test_stack_on_repository_branch(self): 512 # Stacking should work when the repo isn't co-located with the 513 # stack-on branch. 514 try: 515 repo = self.make_repository('repo', shared=True) 516 except errors.IncompatibleFormat: 517 raise TestNotApplicable() 518 if not repo._format.supports_nesting_repositories: 519 raise TestNotApplicable() 520 # Avoid make_branch, which produces standalone branches. 521 bzrdir = self.make_controldir('repo/stack-on') 522 try: 523 b = bzrdir.create_branch() 524 except errors.UninitializableFormat: 525 raise TestNotApplicable() 526 transport = self.get_transport('stacked') 527 b.controldir.clone_on_transport(transport, stacked_on=b.base) 528 # Ensure that opening the branch doesn't raise. 529 _mod_branch.Branch.open(transport.base) 530 531 def test_revision_history_of_stacked(self): 532 # See <https://launchpad.net/bugs/380314>. 533 stack_on = self.make_branch_and_tree('stack-on') 534 rev1 = stack_on.commit('first commit') 535 try: 536 stacked_dir = stack_on.controldir.sprout( 537 self.get_url('stacked'), stacked=True) 538 except unstackable_format_errors as e: 539 raise TestNotApplicable('Format does not support stacking.') 540 try: 541 stacked = stacked_dir.open_workingtree() 542 except errors.NoWorkingTree: 543 stacked = stacked_dir.open_branch().create_checkout( 544 'stacked-checkout', lightweight=True) 545 tree = stacked.branch.create_checkout('local') 546 rev2 = tree.commit('second commit') 547 # Sanity check: stacked's repo should not contain rev1, otherwise this 548 # test isn't testing what it's supposed to. 549 repo = stacked.branch.repository.controldir.open_repository() 550 repo.lock_read() 551 self.addCleanup(repo.unlock) 552 self.assertEqual({}, repo.get_parent_map([rev1])) 553 # revision_history should work, even though the history is spread over 554 # multiple repositories. 555 self.assertEqual((2, rev2), stacked.branch.last_revision_info()) 556 557 558class TestStackingConnections( 559 transport_util.TestCaseWithConnectionHookedTransport): 560 561 def setUp(self): 562 super(TestStackingConnections, self).setUp() 563 try: 564 base_tree = self.make_branch_and_tree('base', 565 format=self.bzrdir_format) 566 except errors.UninitializableFormat as e: 567 raise TestNotApplicable(e) 568 stacked = self.make_branch('stacked', format=self.bzrdir_format) 569 try: 570 stacked.set_stacked_on_url(base_tree.branch.base) 571 except unstackable_format_errors as e: 572 raise TestNotApplicable(e) 573 self.rev_base = base_tree.commit('first') 574 stacked.set_last_revision_info(1, self.rev_base) 575 stacked_relative = self.make_branch('stacked_relative', 576 format=self.bzrdir_format) 577 stacked_relative.set_stacked_on_url(base_tree.branch.user_url) 578 stacked.set_last_revision_info(1, self.rev_base) 579 self.start_logging_connections() 580 581 def test_open_stacked(self): 582 b = _mod_branch.Branch.open(self.get_url('stacked')) 583 rev = b.repository.get_revision(self.rev_base) 584 self.assertEqual(1, len(self.connections)) 585 586 def test_open_stacked_relative(self): 587 b = _mod_branch.Branch.open(self.get_url('stacked_relative')) 588 rev = b.repository.get_revision(self.rev_base) 589 self.assertEqual(1, len(self.connections)) 590