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