source: mergebot/trunk/utils/test.py @ 65

Last change on this file since 65 was 65, checked in by retracile, 15 years ago

Mergebot: add a missing cleanup call

File size: 32.0 KB
Line 
1#!/usr/bin/python
2"""Automated tests for MergeBot
3
4Run from a Trac source tree with mergebot installed system-wide.  (This needs
5to be reworked to be less cumbersome.)
6"""
7
8# TODO: The testcases need to be extended to cover the following:
9# - using a ticket #number as a version
10# - using a release version number as a version
11# - verify inter-ticket dependency checking
12# - verify failure cascades through inter-ticket dependencies
13
14import os
15import unittest
16import time
17import shutil
18
19from subprocess import call, Popen #, PIPE, STDOUT
20from twill.errors import TwillAssertionError
21
22
23from trac.tests.functional import FunctionalTestSuite, FunctionalTester, FunctionalTwillTestCaseSetup, tc, b, logfile
24from trac.tests.functional.svntestenv import SvnFunctionalTestEnvironment
25from trac.tests.contentgen import random_page, random_sentence #, random_word
26
27
28#class MergeBotTestEnvironment(FunctionalTestEnvironment):
29#    """Slight change to FunctionalTestEnvironment to keep the PYTHONPATH from
30#    our environment.
31#    """
32#    def start(self):
33#        """Starts the webserver"""
34#        server = Popen(["python", "./trac/web/standalone.py",
35#                        "--port=%s" % self.port, "-s",
36#                        "--basic-auth=trac,%s," % self.htpasswd,
37#                        self.tracdir],
38#                       #env={'PYTHONPATH':'.'},
39#                       stdout=logfile, stderr=logfile,
40#                      )
41#        self.pid = server.pid
42#        time.sleep(1) # Give the server time to come up
43#
44#    def _tracadmin(self, *args):
45#        """Internal utility method for calling trac-admin"""
46#        if call(["python", "./trac/admin/console.py", self.tracdir] +
47#                list(args),
48#                #env={'PYTHONPATH':'.'},
49#                stdout=logfile, stderr=logfile):
50#            raise Exception('Failed running trac-admin with %r' % (args, ))
51#
52#
53#FunctionalTestEnvironment = MergeBotTestEnvironment
54
55
56class MergeBotFunctionalTester(FunctionalTester):
57    """Adds some MergeBot functionality to the functional tester."""
58    # FIXME: the tc.find( <various actions> ) checks are bogus: any ticket can
59    # satisfy them, not just the one we're working on.
60    def __init__(self, trac_url, repo_url):
61        FunctionalTester.__init__(self, trac_url)
62        self.repo_url = repo_url
63        self.mergeboturl = self.url + '/mergebot'
64
65    def wait_until_find(self, search, timeout=5):
66        start = time.time()
67        while time.time() - start < timeout:
68            try:
69                #tc.reload() # This appears to re-POST
70                tc.go(b.get_url())
71                tc.find(search)
72                return
73            except TwillAssertionError:
74                pass
75        raise TwillAssertionError("Unable to find %r within %s seconds" % (search, timeout))
76
77    def wait_until_notfind(self, search, timeout=5):
78        start = time.time()
79        while time.time() - start < timeout:
80            try:
81                #tc.reload() # This appears to re-POST
82                tc.go(b.get_url())
83                tc.notfind(search)
84                return
85            except TwillAssertionError:
86                pass
87        raise TwillAssertionError("Unable to notfind %r within %s seconds" % (search, timeout))
88
89    def go_to_mergebot(self):
90        tc.go(self.mergeboturl)
91        tc.url(self.mergeboturl)
92        tc.notfind('No handler matched request to /mergebot')
93
94    def branch(self, ticket_id, component, timeout=1):
95        """timeout is in seconds."""
96        self.go_to_mergebot()
97        tc.formvalue('ops-%s' % ticket_id, 'ticket', ticket_id) # Essentially a noop to select the right form
98        tc.submit('Branch')
99        self.wait_until_find('Nothing in the queue', timeout)
100        tc.find('Rebranch')
101        tc.find('Merge')
102        tc.find('CheckMerge')
103        self.go_to_ticket(ticket_id)
104        tc.find('Created branch from .* for .*')
105        retval = call(['svn', 'ls', self.repo_url + '/' + component + '/branches/ticket-%s' % ticket_id],
106                    stdout=logfile, stderr=logfile)
107        if retval:
108            raise Exception('svn ls failed with exit code %s' % retval)
109
110    def _rebranch(self, ticket_id, component, search, timeout=15):
111        """timeout is in seconds."""
112        self.go_to_mergebot()
113        tc.formvalue('ops-%s' % ticket_id, 'ticket', ticket_id) # Essentially a noop to select the right form
114        tc.submit('Rebranch')
115        self.wait_until_find('Nothing in the queue', timeout)
116        tc.find('Rebranch')
117        tc.find('Merge')
118        tc.find('CheckMerge')
119        self.go_to_ticket(ticket_id)
120        tc.find(search)
121        retval = call(['svn', 'ls', self.repo_url + '/' + component + '/branches/ticket-%s' % ticket_id],
122                    stdout=logfile, stderr=logfile)
123        if retval:
124            raise Exception('svn ls failed with exit code %s' % retval)
125
126    def rebranch(self, ticket_id, component, timeout=15):
127        self._rebranch(ticket_id, component, 'Rebranched from .* for .*', timeout)
128
129    def rebranch_conflict(self, ticket_id, component, timeout=15):
130        self._rebranch(ticket_id, component, 'There were conflicts on rebranching', timeout)
131
132    def merge(self, ticket_id, component, timeout=5):
133        self._merge(ticket_id, component, 'Merged .* to .* for', timeout)
134
135    def merge_conflict(self, ticket_id, component, timeout=5):
136        self._merge(ticket_id, component, 'Found [0-9]+ conflicts? in attempt to merge ', timeout)
137
138    def _merge(self, ticket_id, component, search, timeout=5):
139        """timeout is in seconds."""
140        self.go_to_mergebot()
141        tc.formvalue('ops-%s' % ticket_id, 'ticket', ticket_id) # Essentially a noop to select the right form
142        tc.submit('Merge')
143        self.wait_until_find('Nothing in the queue', timeout)
144        tc.find('Branch')
145        self.go_to_ticket(ticket_id)
146        tc.find(search)
147        # TODO: We may want to change this to remove the "dead" branch
148        retval = call(['svn', 'ls', self.repo_url + '/' + component + '/branches/ticket-%s' % ticket_id],
149                    stdout=logfile, stderr=logfile)
150        if retval:
151            raise Exception('svn ls failed with exit code %s' % retval)
152
153    def checkmerge(self, ticket_id, component, timeout=5):
154        """timeout is in seconds."""
155        self.go_to_mergebot()
156        tc.formvalue('ops-%s' % ticket_id, 'ticket', ticket_id) # Essentially a noop to select the right form
157        tc.submit('CheckMerge')
158        self.wait_until_find('Nothing in the queue', timeout)
159        tc.find('Rebranch')
160        tc.find('Merge')
161        tc.find('CheckMerge')
162        self.go_to_ticket(ticket_id)
163        tc.find('while checking merge of')
164        retval = call(['svn', 'ls', self.repo_url + '/' + component + '/branches/ticket-%s' % ticket_id],
165                    stdout=logfile, stderr=logfile)
166        if retval:
167            raise Exception('svn ls failed with exit code %s' % retval)
168
169
170class MergeBotTestSuite(FunctionalTestSuite):
171    def setUp(self):
172        port = 8889
173        baseurl = "http://localhost:%s" % port
174        self._testenv = SvnFunctionalTestEnvironment("testenv%s" % port, port, baseurl)
175
176        # Configure mergebot
177        env = self._testenv.get_trac_environment()
178        env.config.set('components', 'mergebot.web_ui.mergebotmodule', 'enabled')
179        env.config.save()
180        os.mkdir(os.path.join("testenv%s" % port, 'trac', 'mergebot'))
181        self._testenv._tracadmin('upgrade') # sets up the bulk of the mergebot config
182        env.config.parse_if_needed()
183        env.config.set('mergebot', 'repository_url', self._testenv.repo_url())
184        env.config.set('logging', 'log_type', 'file')
185        env.config.save()
186        env.config.parse_if_needed()
187
188        self._testenv.start()
189        self._tester = MergeBotFunctionalTester(baseurl, self._testenv.repo_url())
190        os.system('mergebotdaemon -f "%s" > %s/mergebotdaemon.log 2>&1 &' % (self._testenv.tracdir, self._testenv.tracdir))
191        self.fixture = (self._testenv, self._tester)
192
193        # Setup some common component stuff for MergeBot's use:
194        svnurl = self._testenv.repo_url()
195        for component in ['stuff', 'flagship', 'submarine']:
196            self._tester.create_component(component)
197            if call(['svn', '-m', 'Create tree for "%s".' % component, 'mkdir',
198                     svnurl + '/' + component,
199                     svnurl + '/' + component + '/trunk',
200                     svnurl + '/' + component + '/tags',
201                     svnurl + '/' + component + '/branches'],
202                    stdout=logfile, stderr=logfile):
203                raise Exception("svn mkdir failed")
204
205        self._tester.create_version('trunk')
206
207
208class FunctionalSvnTestCaseSetup(FunctionalTwillTestCaseSetup):
209    def get_workdir(self):
210        return os.path.join(self._testenv.dirname, self.__class__.__name__)
211
212    def checkout(self, ticket_id=None):
213        """checkout a working copy of the branch for the given ticket, or trunk if none given"""
214        if ticket_id is None:
215            svnurl = self._testenv.repo_url() + '/stuff/trunk'
216        else:
217            svnurl = self._testenv.repo_url() + '/stuff/branches/ticket-%s' % ticket_id
218        retval = call(['svn', 'checkout', svnurl, self.get_workdir()],
219            stdout=logfile, stderr=logfile)
220        self.assertEqual(retval, 0, "svn checkout failed with error %s" % (retval))
221
222    def cleanup(self):
223        shutil.rmtree(self.get_workdir())
224
225    def switch(self, ticket_id=None):
226        if ticket_id is None:
227            svnurl = self._testenv.repo_url() + '/stuff/trunk'
228        else:
229            svnurl = self._testenv.repo_url() + '/stuff/branches/ticket-%s' % ticket_id
230        retval = call(['svn', 'switch', svnurl, self.get_workdir()],
231            stdout=logfile, stderr=logfile)
232        self.assertEqual(retval, 0, "svn checkout failed with error %s" % (retval))
233
234    def add_new_file(self, filename=None):
235        workdir = self.get_workdir()
236        if filename is None:
237            newfile = os.path.join(workdir, self.__class__.__name__)
238        else:
239            newfile = os.path.join(workdir, filename)
240        open(newfile, 'w').write(random_page())
241        retval = call(['svn', 'add', newfile],
242            cwd=workdir,
243            stdout=logfile, stderr=logfile)
244        self.assertEqual(retval, 0, "svn add failed with error %s" % (retval))
245
246    def commit(self, message, files=None):
247        if files is None:
248            files = ['.']
249        commit_message = self.__class__.__name__ + ": " + message
250        retval = call(['svn', 'commit', '-m', commit_message] + list(files),
251            cwd=self.get_workdir(),
252            stdout=logfile, stderr=logfile)
253        self.assertEqual(retval, 0, "svn commit failed with error %s" % (retval))
254
255    def mv(self, oldname, newname):
256        retval = call(['svn', 'mv', oldname, newname],
257            cwd=self.get_workdir(),
258            stdout=logfile, stderr=logfile)
259        self.assertEqual(retval, 0, "svn mv failed with error %s" % (retval))
260
261    def propset(self, propname, propvalue, filename):
262        retval = call(['svn', 'propset', propname, propvalue, filename],
263            cwd=self.get_workdir(),
264            stdout=logfile, stderr=logfile)
265        self.assertEqual(retval, 0, "svn prposet failed with error %s" % (retval))
266       
267    def propdel(self, propname, filename):
268        retval = call(['svn', 'propdel', propname, filename],
269            cwd=self.get_workdir(),
270            stdout=logfile, stderr=logfile)
271        self.assertEqual(retval, 0, "svn prposet failed with error %s" % (retval))
272
273
274class MergeBotTestEnabled(FunctionalTwillTestCaseSetup):
275    def runTest(self):
276        self._tester.logout()
277        tc.go(self._tester.url)
278        self._tester.login('admin')
279        tc.follow('MergeBot')
280        mergeboturl = self._tester.url + '/mergebot'
281        tc.url(mergeboturl)
282        tc.notfind('No handler matched request to /mergebot')
283
284
285class MergeBotTestNoVersion(FunctionalTwillTestCaseSetup):
286    """Verify that if a ticket does not have the version field set, it will not
287    appear in the MergeBot list.
288    """
289    def runTest(self):
290        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
291            info={'component':'stuff', 'version':''})
292        tc.follow('MergeBot')
293        tc.notfind(self.__class__.__name__)
294
295
296class MergeBotTestBranch(FunctionalTwillTestCaseSetup):
297    def runTest(self):
298        """Verify that the 'branch' button works"""
299        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
300            info={'component':'stuff', 'version':'trunk'})
301        self._tester.branch(ticket_id, 'stuff')
302
303
304class MergeBotTestRebranch(FunctionalTwillTestCaseSetup):
305    def runTest(self):
306        """Verify that the 'rebranch' button works"""
307        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
308            info={'component':'stuff', 'version':'trunk'})
309        self._tester.branch(ticket_id, 'stuff')
310        self._tester.rebranch(ticket_id, 'stuff')
311
312
313class MergeBotTestMerge(FunctionalTwillTestCaseSetup):
314    def runTest(self):
315        """Verify that the 'merge' button works"""
316        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
317            info={'component':'stuff', 'version':'trunk'})
318        self._tester.branch(ticket_id, 'stuff')
319        self._tester.merge(ticket_id, 'stuff')
320
321
322class MergeBotTestMergeWithChange(FunctionalSvnTestCaseSetup):
323    def runTest(self):
324        """Verify that the 'merge' button works with changes on the branch"""
325        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
326            info={'component':'stuff', 'version':'trunk'})
327        self._tester.branch(ticket_id, 'stuff')
328
329        # checkout a working copy & make a change
330        self.checkout(ticket_id)
331        # Create & add a new file
332        self.add_new_file()
333        self.commit('Add a new file')
334
335        self._tester.merge(ticket_id, 'stuff')
336
337        self.cleanup()
338
339class MergeBotTestMergeWithChangeAndTrunkChange(FunctionalSvnTestCaseSetup):
340    def runTest(self):
341        """Verify that the 'merge' button works with changes on the branch and trunk"""
342        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
343            info={'component':'stuff', 'version':'trunk'})
344        self._tester.branch(ticket_id, 'stuff')
345
346        # checkout a working copy & make a change
347        self.checkout(ticket_id)
348        # Create & add a new file
349        basename = self.__class__.__name__
350        self.add_new_file(basename + '-ticket')
351        self.commit('Add a new file on ticket')
352        self.switch()
353        self.add_new_file(basename + '-trunk')
354        self.commit('Add a new file on trunk')
355
356        self._tester.merge(ticket_id, 'stuff')
357        self.cleanup()
358
359
360class MergeBotTestMergeWithConflict(FunctionalSvnTestCaseSetup):
361    def runTest(self):
362        """Verify that the 'merge' button detects conflicts between the branch and trunk"""
363        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
364            info={'component':'stuff', 'version':'trunk'})
365        basename = self.__class__.__name__
366
367        # create a file in which to have conflicts
368        self.checkout()
369        self.add_new_file(basename)
370        self.commit('Add a new file on trunk')
371
372        # create the branch
373        self._tester.branch(ticket_id, 'stuff')
374
375        # modify the file on trunk
376        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
377        self.commit('Modify the file on trunk')
378
379        # modify the file on the branch
380        self.switch(ticket_id)
381        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
382        self.commit('Modify the file on branch')
383
384        # merge, make sure it shows a conflict
385        self._tester.merge_conflict(ticket_id, 'stuff')
386
387        self.cleanup()
388
389
390class MergeBotTestMergeWithPropertyConflict(FunctionalSvnTestCaseSetup):
391    def runTest(self):
392        """Verify that the 'merge' button detects property conflicts between the branch and trunk"""
393        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
394            info={'component':'stuff', 'version':'trunk'})
395        basename = self.__class__.__name__
396
397        self.checkout()
398        self.propset('svn:ignore', basename, '.')
399        self.commit('set property on trunk')
400
401        # create the branch
402        self._tester.branch(ticket_id, 'stuff')
403
404        # modify the property on trunk
405        self.propset('svn:ignore', basename + '\ntrunk', '.')
406        self.commit('Modify the property on trunk')
407
408        # modify the property on the branch
409        self.switch(ticket_id)
410        self.propset('svn:ignore', basename + '\nbranch', '.')
411        self.commit('Modify the property on branch')
412
413        # merge, make sure it shows a conflict
414        self._tester.merge_conflict(ticket_id, 'stuff')
415
416        self.cleanup()
417
418
419class MergeBotTestMergeWithPropertyBranchDeleteConflict(FunctionalSvnTestCaseSetup):
420    def runTest(self):
421        """Verify that the 'merge' button detects property deleted on branch and modified on trunk"""
422        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
423            info={'component':'stuff', 'version':'trunk'})
424        basename = self.__class__.__name__
425
426        self.checkout()
427        self.propset('svn:ignore', basename, '.')
428        self.commit('set property on trunk')
429
430        # create the branch
431        self._tester.branch(ticket_id, 'stuff')
432
433        # modify the property on trunk
434        self.propset('svn:ignore', basename + '\ntrunk', '.')
435        self.commit('Modify the property on trunk')
436
437        # delete the property on the branch
438        self.switch(ticket_id)
439        self.propdel('svn:ignore', '.')
440        self.commit('Delete the property on branch')
441
442        # merge, make sure it shows a conflict
443        self._tester.merge_conflict(ticket_id, 'stuff')
444
445        self.cleanup()
446
447
448class MergeBotTestMergeWithPropertyTrunkDeleteConflict(FunctionalSvnTestCaseSetup):
449    def runTest(self):
450        """Verify that the 'merge' button detects property deleted on trunk and modified on branch"""
451        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
452            info={'component':'stuff', 'version':'trunk'})
453        basename = self.__class__.__name__
454
455        self.checkout()
456        self.propset('svn:ignore', basename, '.')
457        self.commit('set property on trunk')
458
459        # create the branch
460        self._tester.branch(ticket_id, 'stuff')
461
462        # delete the property on trunk
463        self.propdel('svn:ignore', '.')
464        self.commit('Delete the property on trunk')
465
466        # delete the property on the branch
467        self.switch(ticket_id)
468        self.propset('svn:ignore', basename + '\nbranch', '.')
469        self.commit('Modify the property on branch')
470
471        # merge, make sure it shows a conflict
472        self._tester.merge_conflict(ticket_id, 'stuff')
473
474        self.cleanup()
475
476
477class MergeBotTestMergeWithBranchRenameConflict(FunctionalSvnTestCaseSetup):
478    def runTest(self):
479        """Verify that the 'merge' button detects a conflict when a file renamed on the branch was modified on trunk"""
480        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
481            info={'component':'stuff', 'version':'trunk'})
482        basename = self.__class__.__name__
483
484        # create a file in which to have conflicts
485        self.checkout()
486        self.add_new_file(basename)
487        self.commit('Add a new file on trunk')
488
489        # create the branch
490        self._tester.branch(ticket_id, 'stuff')
491
492        # modify the file on trunk
493        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
494        self.commit('Modify the file on trunk')
495
496        # rename the file on the branch
497        self.switch(ticket_id)
498        self.mv(basename, basename + '-renamed')
499        self.commit('Rename the file on the branch')
500
501        self._tester.merge_conflict(ticket_id, 'stuff')
502
503        self.cleanup()
504
505
506class MergeBotTestMergeWithTrunkRenameConflict(FunctionalSvnTestCaseSetup):
507    def runTest(self):
508        """Verify that the 'merge' button detects conflicts when a file renamed on trunk was modified on the branch"""
509        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
510            info={'component':'stuff', 'version':'trunk'})
511        basename = self.__class__.__name__
512
513        # create a file in which to have conflicts
514        self.checkout()
515        self.add_new_file(basename)
516        self.commit('Add a new file on trunk')
517
518        # create the branch
519        self._tester.branch(ticket_id, 'stuff')
520
521        # rename the file on trunk
522        self.mv(basename, basename + '-renamed')
523        self.commit('Rename the file on trunk')
524
525        # rename the file on the branch
526        self.switch(ticket_id)
527        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
528        self.commit('Modify the file on the branch')
529
530        # make sure it finds the conflict
531        self._tester.merge_conflict(ticket_id, 'stuff')
532
533        self.cleanup()
534
535
536class MergeBotTestCheckMerge(FunctionalTwillTestCaseSetup):
537    def runTest(self):
538        """Verify that the 'checkmerge' button works"""
539        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
540            info={'component':'stuff', 'version':'trunk'})
541        self._tester.branch(ticket_id, 'stuff')
542        self._tester.checkmerge(ticket_id, 'stuff')
543
544
545class MergeBotTestRebranchWithChange(FunctionalSvnTestCaseSetup):
546    def runTest(self):
547        """Verify that the 'rebranch' button works with changes on the branch"""
548        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
549            info={'component':'stuff', 'version':'trunk'})
550        self._tester.branch(ticket_id, 'stuff')
551
552        # checkout a working copy & make a change
553        self.checkout(ticket_id)
554        # Create & add a new file
555        self.add_new_file()
556        self.commit('Add a new file')
557
558        self._tester.rebranch(ticket_id, 'stuff')
559        self.cleanup()
560
561
562class MergeBotTestRebranchWithChangeAndTrunkChange(FunctionalSvnTestCaseSetup):
563    def runTest(self):
564        """Verify that the 'rebranch' button works with changes on the branch and trunk"""
565        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
566            info={'component':'stuff', 'version':'trunk'})
567        self._tester.branch(ticket_id, 'stuff')
568
569        # checkout a working copy & make a change
570        self.checkout(ticket_id)
571        # Create & add a new file
572        basename = self.__class__.__name__
573        self.add_new_file(basename + '-ticket')
574        self.commit('Add a new file on ticket')
575        self.switch()
576        self.add_new_file(basename + '-trunk')
577        self.commit('Add a new file on trunk')
578
579        self._tester.rebranch(ticket_id, 'stuff')
580        self.cleanup()
581
582
583class MergeBotTestRebranchWithConflict(FunctionalSvnTestCaseSetup):
584    def runTest(self):
585        """Verify that the 'rebranch' button detects conflicts between the branch and trunk"""
586        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
587            info={'component':'stuff', 'version':'trunk'})
588        basename = self.__class__.__name__
589
590        # create a file in which to have conflicts
591        self.checkout()
592        self.add_new_file(basename)
593        self.commit('Add a new file on trunk')
594
595        # create the branch
596        self._tester.branch(ticket_id, 'stuff')
597
598        # modify the file on trunk
599        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
600        self.commit('Modify the file on trunk')
601
602        # modify the file on the branch
603        self.switch(ticket_id)
604        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
605        self.commit('Modify the file on branch')
606
607        # rebranch, make sure it shows a conflict
608        self._tester.rebranch_conflict(ticket_id, 'stuff')
609
610        self.cleanup()
611
612
613class MergeBotTestRebranchWithPropertyConflict(FunctionalSvnTestCaseSetup):
614    def runTest(self):
615        """Verify that the 'rebranch' button detects property conflicts between the branch and trunk"""
616        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
617            info={'component':'stuff', 'version':'trunk'})
618        basename = self.__class__.__name__
619
620        self.checkout()
621        self.propset('svn:ignore', basename, '.')
622        self.commit('set property on trunk')
623
624        # create the branch
625        self._tester.branch(ticket_id, 'stuff')
626
627        # modify the property on trunk
628        self.propset('svn:ignore', basename + '\ntrunk', '.')
629        self.commit('Modify the property on trunk')
630
631        # modify the property on the branch
632        self.switch(ticket_id)
633        self.propset('svn:ignore', basename + '\nbranch', '.')
634        self.commit('Modify the property on branch')
635
636        # rebranch, make sure it shows a conflict
637        self._tester.rebranch_conflict(ticket_id, 'stuff')
638
639        self.cleanup()
640
641
642class MergeBotTestRebranchWithPropertyBranchDeleteConflict(FunctionalSvnTestCaseSetup):
643    def runTest(self):
644        """Verify that the 'rebranch' button detects property deleted on branch and modified on trunk"""
645        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
646            info={'component':'stuff', 'version':'trunk'})
647        basename = self.__class__.__name__
648
649        self.checkout()
650        self.propset('svn:ignore', basename, '.')
651        self.commit('set property on trunk')
652
653        # create the branch
654        self._tester.branch(ticket_id, 'stuff')
655
656        # modify the property on trunk
657        self.propset('svn:ignore', basename + '\ntrunk', '.')
658        self.commit('Modify the property on trunk')
659
660        # delete the property on the branch
661        self.switch(ticket_id)
662        self.propdel('svn:ignore', '.')
663        self.commit('Delete the property on branch')
664
665        # rebranch, make sure it shows a conflict
666        self._tester.rebranch_conflict(ticket_id, 'stuff')
667
668        self.cleanup()
669
670
671class MergeBotTestRebranchWithPropertyTrunkDeleteConflict(FunctionalSvnTestCaseSetup):
672    def runTest(self):
673        """Verify that the 'rebranch' button detects property deleted on trunk and modified on branch"""
674        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
675            info={'component':'stuff', 'version':'trunk'})
676        basename = self.__class__.__name__
677
678        self.checkout()
679        self.propset('svn:ignore', basename, '.')
680        self.commit('set property on trunk')
681
682        # create the branch
683        self._tester.branch(ticket_id, 'stuff')
684
685        # delete the property on trunk
686        self.propdel('svn:ignore', '.')
687        self.commit('Delete the property on trunk')
688
689        # delete the property on the branch
690        self.switch(ticket_id)
691        self.propset('svn:ignore', basename + '\nbranch', '.')
692        self.commit('Modify the property on branch')
693
694        # rebranch, make sure it shows a conflict
695        self._tester.rebranch_conflict(ticket_id, 'stuff')
696
697        self.cleanup()
698
699
700class MergeBotTestRebranchWithBranchRenameConflict(FunctionalSvnTestCaseSetup):
701    def runTest(self):
702        """Verify that the 'rebranch' button detects a conflict when a file renamed on the branch was modified on trunk"""
703        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
704            info={'component':'stuff', 'version':'trunk'})
705        basename = self.__class__.__name__
706
707        # create a file in which to have conflicts
708        self.checkout()
709        self.add_new_file(basename)
710        self.commit('Add a new file on trunk')
711
712        # create the branch
713        self._tester.branch(ticket_id, 'stuff')
714
715        # modify the file on trunk
716        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
717        self.commit('Modify the file on trunk')
718
719        # rename the file on the branch
720        self.switch(ticket_id)
721        self.mv(basename, basename + '-renamed')
722        self.commit('Rename the file on the branch')
723
724        self._tester.rebranch_conflict(ticket_id, 'stuff')
725
726        self.cleanup()
727
728
729class MergeBotTestRebranchWithTrunkRenameConflict(FunctionalSvnTestCaseSetup):
730    def runTest(self):
731        """Verify that the 'rebranch' button detects conflicts when a file renamed on trunk was modified on the branch"""
732        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
733            info={'component':'stuff', 'version':'trunk'})
734        basename = self.__class__.__name__
735
736        # create a file in which to have conflicts
737        self.checkout()
738        self.add_new_file(basename)
739        self.commit('Add a new file on trunk')
740
741        # create the branch
742        self._tester.branch(ticket_id, 'stuff')
743
744        # rename the file on trunk
745        self.mv(basename, basename + '-renamed')
746        self.commit('Rename the file on trunk')
747
748        # rename the file on the branch
749        self.switch(ticket_id)
750        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
751        self.commit('Modify the file on the branch')
752
753        # make sure it finds the conflict
754        self._tester.rebranch_conflict(ticket_id, 'stuff')
755
756        self.cleanup()
757
758
759class MergeBotTestSingleUseCase(FunctionalSvnTestCaseSetup):
760    def runTest(self):
761        """Create a branch, make a change, checkmerge, and merge it."""
762        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
763            info={'component':'stuff', 'version':'trunk'})
764        self._tester.branch(ticket_id, 'stuff')
765        # checkout a working copy & make a change
766        self.checkout(ticket_id)
767        # Create & add a new file
768        self.add_new_file()
769        self.commit('Add a new file')
770        self._tester.checkmerge(ticket_id, 'stuff')
771        self._tester.merge(ticket_id, 'stuff')
772        self.cleanup()
773
774
775class MergeBotTestBranchReuse(FunctionalSvnTestCaseSetup):
776    def runTest(self):
777        """Merge a branch, branch it again, and merge it a second time."""
778        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
779            info={'component':'stuff', 'version':'trunk'})
780        basename = self.__class__.__name__
781
782        self.checkout()
783        self.add_new_file(basename)
784        self.commit('Add a new file')
785
786        self._tester.branch(ticket_id, 'stuff')
787        self.switch(ticket_id)
788        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
789        self.commit('Make a modification')
790        self._tester.merge(ticket_id, 'stuff')
791
792        self._tester.branch(ticket_id, 'stuff')
793        self.switch(ticket_id)
794        open(os.path.join(self.get_workdir(), basename), 'a').write(random_sentence())
795        self.commit('Make a second modification')
796        self._tester.merge(ticket_id, 'stuff')
797        self.cleanup()
798
799
800def suite():
801    suite = MergeBotTestSuite()
802    suite.addTest(MergeBotTestEnabled())
803    suite.addTest(MergeBotTestNoVersion())
804    suite.addTest(MergeBotTestBranch())
805    suite.addTest(MergeBotTestRebranch())
806    suite.addTest(MergeBotTestCheckMerge())
807    suite.addTest(MergeBotTestMerge())
808    suite.addTest(MergeBotTestRebranchWithChange())
809    suite.addTest(MergeBotTestRebranchWithChangeAndTrunkChange())
810    suite.addTest(MergeBotTestRebranchWithConflict())
811    suite.addTest(MergeBotTestRebranchWithPropertyConflict())
812    suite.addTest(MergeBotTestRebranchWithBranchRenameConflict())
813    suite.addTest(MergeBotTestRebranchWithTrunkRenameConflict())
814    suite.addTest(MergeBotTestRebranchWithPropertyBranchDeleteConflict())
815    suite.addTest(MergeBotTestRebranchWithPropertyTrunkDeleteConflict())
816    suite.addTest(MergeBotTestMergeWithChange())
817    suite.addTest(MergeBotTestMergeWithChangeAndTrunkChange())
818    suite.addTest(MergeBotTestMergeWithConflict())
819    suite.addTest(MergeBotTestMergeWithPropertyConflict())
820    suite.addTest(MergeBotTestMergeWithBranchRenameConflict())
821    suite.addTest(MergeBotTestMergeWithTrunkRenameConflict())
822    suite.addTest(MergeBotTestMergeWithPropertyBranchDeleteConflict())
823    suite.addTest(MergeBotTestMergeWithPropertyTrunkDeleteConflict())
824    suite.addTest(MergeBotTestSingleUseCase())
825    suite.addTest(MergeBotTestBranchReuse())
826    return suite
827
828if __name__ == '__main__':
829    unittest.main(defaultTest='suite')
Note: See TracBrowser for help on using the repository browser.