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