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

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

Mergebot: add testcases to cover property related delete/modify conflicts

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