213f311e0d1d3eeee26b19810b6e4f89df3fc9ba
[jelmer/subvertpy.git] / tests / test_branch.py
1 # Copyright (C) 2006-2007 Jelmer Vernooij <jelmer@samba.org>
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17 """Branch tests."""
18
19 from bzrlib.branch import Branch
20 from bzrlib.bzrdir import BzrDir
21 from bzrlib.errors import NoSuchFile, NoSuchRevision, NotBranchError
22 from bzrlib.repository import Repository
23 from bzrlib.trace import mutter
24
25 import os
26 from unittest import TestCase
27
28 from branch import FakeControlFiles, SvnBranchFormat
29 from convert import load_dumpfile
30 from fileids import generate_svn_file_id
31 from repository import MAPPING_VERSION, generate_svn_revision_id, SVN_PROP_BZR_REVISION_ID
32 from tests import TestCaseWithSubversionRepository
33
34 class WorkingSubversionBranch(TestCaseWithSubversionRepository):
35     def test_last_rev_rev_hist(self):
36         repos_url = self.make_client("a", "dc")
37         branch = Branch.open(repos_url)
38         branch.revision_history()
39         self.assertEqual(branch.generate_revision_id(0), branch.last_revision())
40
41     def test_get_branch_path_root(self):
42         repos_url = self.make_client("a", "dc")
43         branch = Branch.open(repos_url)
44         self.assertEqual("", branch.get_branch_path())
45
46     def test_get_branch_path_subdir(self):
47         repos_url = self.make_client("a", "dc")
48         self.build_tree({"dc/trunk": None})
49         self.client_add("dc/trunk")
50         self.client_commit("dc", "Add branch")
51         branch = Branch.open(repos_url+"/trunk")
52         self.assertEqual("trunk", branch.get_branch_path())
53
54     def test_open_nonexistant(self):
55         repos_url = self.make_client("a", "dc")
56         self.assertRaises(NotBranchError, Branch.open, repos_url + "/trunk")
57
58     def test_last_rev_rev_info(self):
59         repos_url = self.make_client("a", "dc")
60         branch = Branch.open(repos_url)
61         self.assertEqual((1, branch.generate_revision_id(0)),
62                 branch.last_revision_info())
63         branch.revision_history()
64         self.assertEqual((1, branch.generate_revision_id(0)),
65                 branch.last_revision_info())
66
67     def test_lookup_revision_id_unknown(self):
68         repos_url = self.make_client("a", "dc")
69         branch = Branch.open(repos_url)
70         self.assertRaises(NoSuchRevision, 
71                 lambda: branch.lookup_revision_id("bla"))
72
73     def test_lookup_revision_id(self):
74         repos_url = self.make_client("a", "dc")
75         branch = Branch.open(repos_url)
76         self.assertEquals(0, 
77                 branch.lookup_revision_id(branch.last_revision()))
78
79     def test_set_parent(self):
80         repos_url = self.make_client('a', 'dc')
81         branch = Branch.open(repos_url)
82         branch.set_parent("foobar")
83
84     def test_num_revnums(self):
85         repos_url = self.make_client('a', 'dc')
86         bzrdir = BzrDir.open("svn+"+repos_url)
87         branch = bzrdir.open_branch()
88         self.assertEqual(branch.generate_revision_id(0),
89                          branch.last_revision())
90
91         self.build_tree({'dc/foo': "data"})
92         self.client_add("dc/foo")
93         self.client_commit("dc", "My Message")
94         self.client_update("dc")
95         
96         bzrdir = BzrDir.open("svn+"+repos_url)
97         branch = bzrdir.open_branch()
98         repos = bzrdir.find_repository()
99
100         self.assertEqual(repos.generate_revision_id(1, "", "none"), 
101                 branch.last_revision())
102
103         self.build_tree({'dc/foo': "data2"})
104         self.client_commit("dc", "My Message")
105
106         branch = Branch.open("svn+"+repos_url)
107         repos = Repository.open("svn+"+repos_url)
108
109         self.assertEqual(repos.generate_revision_id(2, "", "none"),
110                 branch.last_revision())
111
112     def test_set_revision_history(self):
113         repos_url = self.make_client('a', 'dc')
114         branch = Branch.open("svn+"+repos_url)
115         self.assertRaises(NotImplementedError, branch.set_revision_history, [])
116
117     def test_break_lock(self):
118         repos_url = self.make_client('a', 'dc')
119         branch = Branch.open("svn+"+repos_url)
120         branch.control_files.break_lock()
121
122     def test_repr(self):
123         repos_url = self.make_client('a', 'dc')
124         branch = Branch.open("svn+"+repos_url)
125         self.assertEqual("SvnBranch('svn+%s')" % repos_url, branch.__repr__())
126
127     def test_get_physical_lock_status(self):
128         repos_url = self.make_client('a', 'dc')
129         branch = Branch.open("svn+"+repos_url)
130         self.assertFalse(branch.get_physical_lock_status())
131
132     def test_set_push_location(self):
133         repos_url = self.make_client('a', 'dc')
134         branch = Branch.open("svn+"+repos_url)
135         self.assertRaises(NotImplementedError, branch.set_push_location, [])
136
137     def test_get_parent(self):
138         repos_url = self.make_client('a', 'dc')
139         branch = Branch.open("svn+"+repos_url)
140         self.assertEqual("svn+"+repos_url, branch.get_parent())
141
142     def test_append_revision(self):
143         repos_url = self.make_client('a', 'dc')
144         branch = Branch.open("svn+"+repos_url)
145         branch.append_revision([])
146
147     def test_get_push_location(self):
148         repos_url = self.make_client('a', 'dc')
149         branch = Branch.open("svn+"+repos_url)
150         self.assertIs(None, branch.get_push_location())
151
152     def test_revision_history(self):
153         repos_url = self.make_client('a', 'dc')
154
155         branch = Branch.open("svn+"+repos_url)
156         self.assertEqual([branch.generate_revision_id(0)], 
157                 branch.revision_history())
158
159         self.build_tree({'dc/foo': "data"})
160         self.client_add("dc/foo")
161         self.client_set_prop("dc", SVN_PROP_BZR_REVISION_ID+"none", 
162                 "42 mycommit\n")
163         self.client_commit("dc", "My Message")
164         self.client_update("dc")
165         
166         branch = Branch.open("svn+"+repos_url)
167         repos = Repository.open("svn+"+repos_url)
168
169         self.assertEqual([repos.generate_revision_id(0, "", "none"), 
170                     repos.generate_revision_id(1, "", "none")], 
171                 branch.revision_history())
172
173         self.build_tree({'dc/foo': "data34"})
174         self.client_commit("dc", "My Message")
175
176         branch = Branch.open("svn+"+repos_url)
177         repos = Repository.open("svn+"+repos_url)
178
179         self.assertEqual([
180             repos.generate_revision_id(0, "", "none"),
181             "mycommit",
182             repos.generate_revision_id(2, "", "none")],
183             branch.revision_history())
184
185     def test_revision_id_to_revno_none(self):
186         """The None revid should map to revno 0."""
187         repos_url = self.make_client('a', 'dc')
188         branch = Branch.open(repos_url)
189         self.assertEquals(0, branch.revision_id_to_revno(None))
190
191     def test_revision_id_to_revno_nonexistant(self):
192         """revision_id_to_revno() should raise NoSuchRevision if
193         the specified revision did not exist in the branch history."""
194         repos_url = self.make_client('a', 'dc')
195         branch = Branch.open(repos_url)
196         self.assertRaises(NoSuchRevision, branch.revision_id_to_revno, "bla")
197     
198     def test_revision_id_to_revno_simple(self):
199         repos_url = self.make_client('a', 'dc')
200         self.build_tree({'dc/foo': "data"})
201         self.client_add("dc/foo")
202         self.client_set_prop("dc", "bzr:revision-id:v%d-none" % MAPPING_VERSION, 
203                             "2 myrevid\n")
204         self.client_commit("dc", "My Message")
205         branch = Branch.open(repos_url)
206         self.assertEquals(2, branch.revision_id_to_revno("myrevid"))
207
208     def test_revision_id_to_revno_older(self):
209         repos_url = self.make_client('a', 'dc')
210         self.build_tree({'dc/foo': "data"})
211         self.client_add("dc/foo")
212         self.client_set_prop("dc", "bzr:revision-id:v%d-none" % MAPPING_VERSION, 
213                             "2 myrevid\n")
214         self.client_commit("dc", "My Message")
215         self.build_tree({'dc/foo': "someotherdata"})
216         self.client_set_prop("dc", "bzr:revision-id:v%d-none" % MAPPING_VERSION, 
217                             "2 myrevid\n3 mysecondrevid\n")
218         self.client_commit("dc", "My Message")
219         branch = Branch.open(repos_url)
220         self.assertEquals(3, branch.revision_id_to_revno("mysecondrevid"))
221         self.assertEquals(2, branch.revision_id_to_revno("myrevid"))
222
223     def test_get_nick_none(self):
224         repos_url = self.make_client('a', 'dc')
225
226         self.build_tree({'dc/foo': "data"})
227         self.client_add("dc/foo")
228         self.client_commit("dc", "My Message")
229
230         branch = Branch.open("svn+"+repos_url)
231
232         self.assertIs(None, branch.nick)
233
234     def test_get_nick_path(self):
235         repos_url = self.make_client('a', 'dc')
236
237         self.build_tree({'dc/trunk': None})
238         self.client_add("dc/trunk")
239         self.client_commit("dc", "My Message")
240
241         branch = Branch.open("svn+"+repos_url+"/trunk")
242
243         self.assertEqual("trunk", branch.nick)
244
245     def test_get_revprops(self):
246         repos_url = self.make_client('a', 'dc')
247
248         self.build_tree({'dc/foo': "data"})
249         self.client_add("dc/foo")
250         self.client_set_prop("dc", "bzr:revision-info", 
251                 "properties: \n\tbranch-nick: mybranch\n")
252         self.client_commit("dc", "My Message")
253
254         branch = Branch.open("svn+"+repos_url)
255
256         rev = branch.repository.get_revision(branch.last_revision())
257
258         self.assertEqual("mybranch", rev.properties["branch-nick"])
259
260     def test_fetch_replace(self):
261         filename = os.path.join(self.test_dir, "dumpfile")
262         open(filename, 'w').write("""SVN-fs-dump-format-version: 2
263
264 UUID: 6f95bc5c-e18d-4021-aca8-49ed51dbcb75
265
266 Revision-number: 0
267 Prop-content-length: 56
268 Content-length: 56
269
270 K 8
271 svn:date
272 V 27
273 2006-07-30T12:41:25.270824Z
274 PROPS-END
275
276 Revision-number: 1
277 Prop-content-length: 94
278 Content-length: 94
279
280 K 7
281 svn:log
282 V 0
283
284 K 10
285 svn:author
286 V 0
287
288 K 8
289 svn:date
290 V 27
291 2006-07-30T12:41:26.117512Z
292 PROPS-END
293
294 Node-path: trunk
295 Node-kind: dir
296 Node-action: add
297 Prop-content-length: 10
298 Content-length: 10
299
300 PROPS-END
301
302
303 Node-path: trunk/hosts
304 Node-kind: file
305 Node-action: add
306 Prop-content-length: 10
307 Text-content-length: 4
308 Text-content-md5: 771ec3328c29d17af5aacf7f895dd885
309 Content-length: 14
310
311 PROPS-END
312 hej1
313
314 Revision-number: 2
315 Prop-content-length: 94
316 Content-length: 94
317
318 K 7
319 svn:log
320 V 0
321
322 K 10
323 svn:author
324 V 0
325
326 K 8
327 svn:date
328 V 27
329 2006-07-30T12:41:27.130044Z
330 PROPS-END
331
332 Node-path: trunk/hosts
333 Node-kind: file
334 Node-action: change
335 Text-content-length: 4
336 Text-content-md5: 6c2479dbb342b8df96d84db7ab92c412
337 Content-length: 4
338
339 hej2
340
341 Revision-number: 3
342 Prop-content-length: 94
343 Content-length: 94
344
345 K 7
346 svn:log
347 V 0
348
349 K 10
350 svn:author
351 V 0
352
353 K 8
354 svn:date
355 V 27
356 2006-07-30T12:41:28.114350Z
357 PROPS-END
358
359 Node-path: trunk/hosts
360 Node-kind: file
361 Node-action: change
362 Text-content-length: 4
363 Text-content-md5: 368cb8d3db6186e2e83d9434f165c525
364 Content-length: 4
365
366 hej3
367
368 Revision-number: 4
369 Prop-content-length: 94
370 Content-length: 94
371
372 K 7
373 svn:log
374 V 0
375
376 K 10
377 svn:author
378 V 0
379
380 K 8
381 svn:date
382 V 27
383 2006-07-30T12:41:29.129563Z
384 PROPS-END
385
386 Node-path: branches
387 Node-kind: dir
388 Node-action: add
389 Prop-content-length: 10
390 Content-length: 10
391
392 PROPS-END
393
394
395 Revision-number: 5
396 Prop-content-length: 94
397 Content-length: 94
398
399 K 7
400 svn:log
401 V 0
402
403 K 10
404 svn:author
405 V 0
406
407 K 8
408 svn:date
409 V 27
410 2006-07-30T12:41:31.130508Z
411 PROPS-END
412
413 Node-path: branches/foobranch
414 Node-kind: dir
415 Node-action: add
416 Node-copyfrom-rev: 4
417 Node-copyfrom-path: trunk
418
419
420 Revision-number: 6
421 Prop-content-length: 94
422 Content-length: 94
423
424 K 7
425 svn:log
426 V 0
427
428 K 10
429 svn:author
430 V 0
431
432 K 8
433 svn:date
434 V 27
435 2006-07-30T12:41:33.129149Z
436 PROPS-END
437
438 Node-path: branches/foobranch/hosts
439 Node-kind: file
440 Node-action: delete
441
442 Node-path: branches/foobranch/hosts
443 Node-kind: file
444 Node-action: add
445 Node-copyfrom-rev: 2
446 Node-copyfrom-path: trunk/hosts
447
448
449
450
451 Revision-number: 7
452 Prop-content-length: 94
453 Content-length: 94
454
455 K 7
456 svn:log
457 V 0
458
459 K 10
460 svn:author
461 V 0
462
463 K 8
464 svn:date
465 V 27
466 2006-07-30T12:41:34.136423Z
467 PROPS-END
468
469 Node-path: branches/foobranch/hosts
470 Node-kind: file
471 Node-action: change
472 Text-content-length: 8
473 Text-content-md5: 0e328d3517a333a4879ebf3d88fd82bb
474 Content-length: 8
475
476 foohosts""")
477         os.mkdir("new")
478         os.mkdir("old")
479
480         load_dumpfile("dumpfile", "old")
481
482         url = "old/branches/foobranch"
483         mutter('open %r' % url)
484         olddir = BzrDir.open(url)
485
486         newdir = olddir.sprout("new")
487
488         newbranch = newdir.open_branch()
489
490         uuid = "6f95bc5c-e18d-4021-aca8-49ed51dbcb75"
491         tree = newbranch.repository.revision_tree(
492                 generate_svn_revision_id(uuid, 7, "branches/foobranch", 
493                 "trunk0"))
494
495         weave = newbranch.repository.weave_store.get_weave(
496             tree.inventory.path2id("hosts"),
497             newbranch.repository.get_transaction())
498         self.assertEqual([
499             generate_svn_revision_id(uuid, 6, "branches/foobranch", "trunk0"),
500             generate_svn_revision_id(uuid, 7, "branches/foobranch", "trunk0")],
501                           weave.versions())
502  
503
504     def test_fetch_odd(self):
505         repos_url = self.make_client('d', 'dc')
506
507         self.build_tree({'dc/trunk': None, 
508                          'dc/trunk/hosts': 'hej1'})
509         self.client_add("dc/trunk")
510         self.client_commit("dc", "created trunk and added hosts") #1
511
512         self.build_tree({'dc/trunk/hosts': 'hej2'})
513         self.client_commit("dc", "rev 2") #2
514
515         self.build_tree({'dc/trunk/hosts': 'hej3'})
516         self.client_commit("dc", "rev 3") #3
517
518         self.build_tree({'dc/branches': None})
519         self.client_add("dc/branches")
520         self.client_commit("dc", "added branches") #4
521
522         self.client_copy("dc/trunk", "dc/branches/foobranch")
523         self.client_commit("dc", "added branch foobranch") #5
524
525         self.build_tree({'dc/branches/foobranch/hosts': 'foohosts'})
526         self.client_commit("dc", "foohosts") #6
527
528         os.mkdir("new")
529
530         url = "svn+"+repos_url+"/branches/foobranch"
531         mutter('open %r' % url)
532         olddir = BzrDir.open(url)
533
534         newdir = olddir.sprout("new")
535
536         newbranch = newdir.open_branch()
537
538         uuid = olddir.find_repository().uuid
539         tree = newbranch.repository.revision_tree(
540              generate_svn_revision_id(uuid, 6, "branches/foobranch", "trunk0"))
541
542         weave = newbranch.repository.weave_store.get_weave(
543                 tree.inventory.path2id("hosts"), 
544                 newbranch.repository.get_transaction())
545         self.assertEqual([
546             generate_svn_revision_id(uuid, 1, "trunk", "trunk0"),
547             generate_svn_revision_id(uuid, 2, "trunk", "trunk0"),
548             generate_svn_revision_id(uuid, 3, "trunk", "trunk0"),
549             generate_svn_revision_id(uuid, 6, "branches/foobranch", "trunk0")],
550                           weave.versions())
551
552     def test_check(self):
553         self.make_client('d', 'dc')
554         branch = Branch.open('d')
555         result = branch.check()
556         self.assertEqual(branch, result.branch) 
557  
558     def test_generate_revision_id(self):
559         self.make_client('d', 'dc')
560         self.build_tree({'dc/bla/bloe': None})
561         self.client_add("dc/bla")
562         self.client_commit("dc", "bla")
563         branch = Branch.open('d')
564         self.assertEqual("svn-v%d-none:%s::1" % (MAPPING_VERSION, branch.repository.uuid),  branch.generate_revision_id(1))
565
566     def test_create_checkout(self):
567         repos_url = self.make_client('d', 'dc')
568
569         self.build_tree({'dc/trunk': None, 'dc/trunk/hosts': 'hej1'})
570         self.client_add("dc/trunk")
571         self.client_commit("dc", "created trunk and added hosts") #1
572
573         url = "svn+"+repos_url+"/trunk"
574         oldbranch = Branch.open(url)
575
576         newtree = self.create_checkout(oldbranch, "e")
577         self.assertTrue(newtree.branch.repository.has_revision(
578            oldbranch.generate_revision_id(1)))
579
580         self.assertTrue(os.path.exists("e/.bzr"))
581         self.assertFalse(os.path.exists("e/.svn"))
582
583     def test_create_checkout_lightweight(self):
584         repos_url = self.make_client('d', 'dc')
585
586         self.build_tree({'dc/trunk': None, 
587                          'dc/trunk/hosts': 'hej1'})
588         self.client_add("dc/trunk")
589         self.client_commit("dc", "created trunk and added hosts") #1
590
591         url = "svn+"+repos_url+"/trunk"
592         oldbranch = Branch.open(url)
593
594         newtree = self.create_checkout(oldbranch, "e", lightweight=True)
595         self.assertEqual(oldbranch.generate_revision_id(1), newtree.base_revid)
596         self.assertTrue(os.path.exists("e/.svn"))
597         self.assertFalse(os.path.exists("e/.bzr"))
598
599     def test_create_checkout_lightweight_stop_rev(self):
600         repos_url = self.make_client('d', 'dc')
601
602         self.build_tree({'dc/trunk': None, 
603                          'dc/trunk/hosts': 'hej1'})
604         self.client_add("dc/trunk")
605         self.client_commit("dc", "created trunk and added hosts") #1
606         
607         self.build_tree({'dc/trunk/hosts': 'bloe'})
608         self.client_commit("dc", "added another revision")
609
610         url = "svn+"+repos_url+"/trunk"
611         oldbranch = Branch.open(url)
612
613         newtree = self.create_checkout(oldbranch, "e", revision_id=
614            oldbranch.generate_revision_id(1), lightweight=True)
615         self.assertEqual(oldbranch.generate_revision_id(1),
616            newtree.base_revid)
617         self.assertTrue(os.path.exists("e/.svn"))
618         self.assertFalse(os.path.exists("e/.bzr"))
619
620     def test_fetch_branch(self):
621         self.make_client('d', 'sc')
622
623         self.build_tree({'sc/foo/bla': "data"})
624         self.client_add("sc/foo")
625         self.client_commit("sc", "foo")
626
627         olddir = self.open_checkout_bzrdir("sc")
628
629         os.mkdir("dc")
630         
631         newdir = olddir.sprout('dc')
632
633         self.assertEqual(
634                 olddir.open_branch().last_revision(),
635                 newdir.open_branch().last_revision())
636
637     def test_fetch_dir_upgrade(self):
638         repos_url = self.make_client('d', 'sc')
639
640         self.build_tree({'sc/trunk/mylib/bla': "data", "sc/branches": None})
641         self.client_add("sc/trunk")
642         self.client_add("sc/branches")
643         self.client_commit("sc", "foo")
644
645         self.client_copy("sc/trunk/mylib", "sc/branches/abranch")
646         self.client_commit("sc", "Promote mylib")
647
648         olddir = self.open_checkout_bzrdir("sc/branches/abranch")
649
650         os.mkdir("dc")
651         
652         newdir = olddir.sprout('dc')
653
654         self.assertEqual(
655                 olddir.open_branch().last_revision(),
656                 newdir.open_branch().last_revision())
657
658     def test_fetch_branch_downgrade(self):
659         repos_url = self.make_client('d', 'sc')
660
661         self.build_tree({'sc/trunk': None, "sc/branches/abranch/bla": 'foo'})
662         self.client_add("sc/trunk")
663         self.client_add("sc/branches")
664         self.client_commit("sc", "foo")
665
666         self.client_copy("sc/branches/abranch", "sc/trunk/mylib")
667         self.client_commit("sc", "Demote mylib")
668
669         olddir = self.open_checkout_bzrdir("sc/trunk")
670
671         os.mkdir("dc")
672         
673         newdir = olddir.sprout('dc')
674
675         self.assertEqual(
676                 olddir.open_branch().last_revision(),
677                 newdir.open_branch().last_revision())
678
679
680
681     def test_ghost_workingtree(self):
682         # Looks like bazaar has trouble creating a working tree of a 
683         # revision that has ghost parents
684         self.make_client('d', 'sc')
685
686         self.build_tree({'sc/foo/bla': "data"})
687         self.client_add("sc/foo")
688         self.client_set_prop("sc", "bzr:ancestry:v3-none", "some-ghost\n")
689         self.client_commit("sc", "foo")
690
691         olddir = self.open_checkout_bzrdir("sc")
692
693         os.mkdir("dc")
694         
695         newdir = olddir.sprout('dc')
696         newdir.find_repository().get_revision(
697                 newdir.open_branch().last_revision())
698         newdir.find_repository().get_revision_inventory(
699                 newdir.open_branch().last_revision())
700
701 class TestFakeControlFiles(TestCase):
702     def test_get_utf8(self):
703         f = FakeControlFiles()
704         self.assertRaises(NoSuchFile, f.get_utf8, "foo")
705
706
707     def test_get(self):
708         f = FakeControlFiles()
709         self.assertRaises(NoSuchFile, f.get, "foobla")
710
711 class BranchFormatTests(TestCase):
712     def setUp(self):
713         self.format = SvnBranchFormat()
714
715     def test_initialize(self):
716         self.assertRaises(NotImplementedError, self.format.initialize, None)
717
718     def test_get_format_string(self):
719         self.assertEqual("Subversion Smart Server", 
720                          self.format.get_format_string())
721
722     def test_get_format_description(self):
723         self.assertEqual("Subversion Smart Server", 
724                          self.format.get_format_description())