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

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

Mergebot: working on the tests

File size: 11.7 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
[16]19from trac.tests.contentgen import random_page #, random_sentence, random_word
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:
63                tc.reload()
64                tc.find(search)
65                return
66            except TwillAssertionError:
67                pass
68        raise TwillAssertionError("Unable to find %r within %s seconds" % (search, timeout))
69
70    def wait_until_notfind(self, search, timeout=5):
71        start = time.time()
72        while time.time() - start < timeout:
73            try:
74                tc.reload()
75                tc.notfind(search)
76                return
77            except TwillAssertionError:
78                pass
79        raise TwillAssertionError("Unable to notfind %r within %s seconds" % (search, timeout))
80
81    def go_to_mergebot(self):
82        tc.go(self.mergeboturl)
83        tc.url(self.mergeboturl)
84        tc.notfind('No handler matched request to /mergebot')
85
86    def branch(self, ticket_id, component, timeout=1):
87        """timeout is in seconds."""
88        self.go_to_mergebot()
89        tc.formvalue('ops-%s' % ticket_id, 'ticket', ticket_id) # Essentially a noop to select the right form
90        tc.submit('Branch')
[44]91        self.wait_until_find('Nothing in the queue', timeout)
[16]92        tc.find('Rebranch')
93        tc.find('Merge')
94        tc.find('CheckMerge')
95        self.go_to_ticket(ticket_id)
96        tc.find('Created branch from .* for .*')
97        retval = call(['svn', 'ls', self.repo_url + '/' + component + '/branches/ticket-%s' % ticket_id],
98                    stdout=logfile, stderr=logfile)
99        if retval:
100            raise Exception('svn ls failed with exit code %s' % retval)
101
[44]102    def rebranch(self, ticket_id, component, timeout=15):
[16]103        """timeout is in seconds."""
104        self.go_to_mergebot()
105        tc.formvalue('ops-%s' % ticket_id, 'ticket', ticket_id) # Essentially a noop to select the right form
[44]106        print "submitting rebranch request for %s" % (ticket_id)
[16]107        tc.submit('Rebranch')
[44]108        self.wait_until_find('Nothing in the queue', timeout)
[16]109        tc.find('Rebranch')
110        tc.find('Merge')
111        tc.find('CheckMerge')
112        self.go_to_ticket(ticket_id)
113        tc.find('Rebranched from .* for .*')
114        retval = call(['svn', 'ls', self.repo_url + '/' + component + '/branches/ticket-%s' % ticket_id],
115                    stdout=logfile, stderr=logfile)
116        if retval:
117            raise Exception('svn ls failed with exit code %s' % retval)
118
119    def merge(self, ticket_id, component, timeout=5):
120        """timeout is in seconds."""
121        self.go_to_mergebot()
122        tc.formvalue('ops-%s' % ticket_id, 'ticket', ticket_id) # Essentially a noop to select the right form
123        tc.submit('Merge')
[44]124        self.wait_until_find('Nothing in the queue', timeout)
[16]125        tc.find('Branch')
126        self.go_to_ticket(ticket_id)
127        tc.find('Merged .* to .* for')
128        # TODO: We may want to change this to remove the "dead" branch
129        retval = call(['svn', 'ls', self.repo_url + '/' + component + '/branches/ticket-%s' % ticket_id],
130                    stdout=logfile, stderr=logfile)
131        if retval:
132            raise Exception('svn ls failed with exit code %s' % retval)
133
134    def checkmerge(self, ticket_id, component, timeout=5):
135        """timeout is in seconds."""
136        self.go_to_mergebot()
137        tc.formvalue('ops-%s' % ticket_id, 'ticket', ticket_id) # Essentially a noop to select the right form
138        tc.submit('CheckMerge')
[44]139        self.wait_until_find('Nothing in the queue', timeout)
[16]140        tc.find('Rebranch')
141        tc.find('Merge')
142        tc.find('CheckMerge')
143        self.go_to_ticket(ticket_id)
144        tc.find('while checking merge of')
145        # TODO: We may want to change this to remove the "dead" branch
146        retval = call(['svn', 'ls', self.repo_url + '/' + component + '/branches/ticket-%s' % ticket_id],
147                    stdout=logfile, stderr=logfile)
148        if retval:
149            raise Exception('svn ls failed with exit code %s' % retval)
150
151
152class MergeBotTestSuite(FunctionalTestSuite):
153    def setUp(self):
154        port = 8889
155        baseurl = "http://localhost:%s" % port
[40]156        self._testenv = SvnFunctionalTestEnvironment("testenv%s" % port, port, baseurl)
[16]157
158        # Configure mergebot
159        env = self._testenv.get_trac_environment()
160        env.config.set('components', 'mergebot.web_ui.mergebotmodule', 'enabled')
[40]161        env.config.save()
[44]162        os.mkdir(os.path.join("testenv%s" % port, 'trac', 'mergebot'))
[40]163        self._testenv._tracadmin('upgrade') # sets up the bulk of the mergebot config
164        env.config.parse_if_needed()
[16]165        env.config.set('mergebot', 'repository_url', self._testenv.repo_url())
166        env.config.set('logging', 'log_type', 'file')
167        env.config.save()
168        env.config.parse_if_needed()
169
170        self._testenv.start()
[44]171        self._tester = MergeBotFunctionalTester(baseurl, self._testenv.repo_url())
[40]172        self.fixture = (self._testenv, self._tester)
[16]173
174        # Setup some common component stuff for MergeBot's use:
175        svnurl = self._testenv.repo_url()
176        for component in ['stuff', 'flagship', 'submarine']:
177            self._tester.create_component(component)
178            if call(['svn', '-m', 'Create tree for "%s".' % component, 'mkdir',
179                     svnurl + '/' + component,
180                     svnurl + '/' + component + '/trunk',
181                     svnurl + '/' + component + '/tags',
182                     svnurl + '/' + component + '/branches'],
183                    stdout=logfile, stderr=logfile):
184                raise Exception("svn mkdir failed")
185
186        self._tester.create_version('trunk')
187
188
[17]189class MergeBotTestEnabled(FunctionalTwillTestCaseSetup):
[16]190    def runTest(self):
191        self._tester.logout()
192        tc.go(self._tester.url)
193        self._tester.login('admin')
194        tc.follow('MergeBot')
195        mergeboturl = self._tester.url + '/mergebot'
196        tc.url(mergeboturl)
197        tc.notfind('No handler matched request to /mergebot')
198
199
[17]200class MergeBotTestNoVersion(FunctionalTwillTestCaseSetup):
[16]201    """Verify that if a ticket does not have the version field set, it will not
202    appear in the MergeBot list.
203    """
204    def runTest(self):
205        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
206            info={'component':'stuff', 'version':''})
207        tc.follow('MergeBot')
208        tc.notfind(self.__class__.__name__)
209
210
[17]211class MergeBotTestBranch(FunctionalTwillTestCaseSetup):
[16]212    def runTest(self):
213        """Verify that the 'branch' button works"""
214        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
215            info={'component':'stuff', 'version':'trunk'})
216        self._tester.branch(ticket_id, 'stuff')
217
218
[17]219class MergeBotTestRebranch(FunctionalTwillTestCaseSetup):
[16]220    def runTest(self):
221        """Verify that the 'rebranch' button works"""
222        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
223            info={'component':'stuff', 'version':'trunk'})
224        self._tester.branch(ticket_id, 'stuff')
225        self._tester.rebranch(ticket_id, 'stuff')
226
227
[17]228class MergeBotTestMerge(FunctionalTwillTestCaseSetup):
[16]229    def runTest(self):
230        """Verify that the 'merge' button works"""
231        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
232            info={'component':'stuff', 'version':'trunk'})
233        self._tester.branch(ticket_id, 'stuff')
234        self._tester.merge(ticket_id, 'stuff')
235
236
[17]237class MergeBotTestCheckMerge(FunctionalTwillTestCaseSetup):
[16]238    def runTest(self):
239        """Verify that the 'checkmerge' button works"""
240        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
241            info={'component':'stuff', 'version':'trunk'})
242        self._tester.branch(ticket_id, 'stuff')
243        self._tester.checkmerge(ticket_id, 'stuff')
244
245
[17]246class MergeBotTestSingleUseCase(FunctionalTwillTestCaseSetup):
[16]247    def runTest(self):
248        """Create a branch, make a change, checkmerge, and merge it."""
249        ticket_id = self._tester.create_ticket(summary=self.__class__.__name__,
250            info={'component':'stuff', 'version':'trunk'})
251        self._tester.branch(ticket_id, 'stuff')
252        # checkout a working copy & make a change
253        svnurl = self._testenv.repo_url()
254        workdir = os.path.join(self._testenv.dirname, self.__class__.__name__)
255        retval = call(['svn', 'checkout', svnurl + '/stuff/branches/ticket-%s' % ticket_id, workdir],
256            stdout=logfile, stderr=logfile)
257        self.assertEqual(retval, 0, "svn checkout failed with error %s" % (retval))
258        # Create & add a new file
259        newfile = os.path.join(workdir, self.__class__.__name__)
260        open(newfile, 'w').write(random_page())
261        retval = call(['svn', 'add', self.__class__.__name__],
262            cwd=workdir,
263            stdout=logfile, stderr=logfile)
264        self.assertEqual(retval, 0, "svn add failed with error %s" % (retval))
265        retval = call(['svn', 'commit', '-m', 'Add a new file', self.__class__.__name__],
266            cwd=workdir,
267            stdout=logfile, stderr=logfile)
268        self.assertEqual(retval, 0, "svn commit failed with error %s" % (retval))
269
270        self._tester.checkmerge(ticket_id, 'stuff')
271        self._tester.merge(ticket_id, 'stuff')
272
273        shutil.rmtree(workdir) # cleanup working copy
274
275
276def suite():
277    suite = MergeBotTestSuite()
278    suite.addTest(MergeBotTestEnabled())
279    suite.addTest(MergeBotTestNoVersion())
280    suite.addTest(MergeBotTestBranch())
[44]281    #suite.addTest(MergeBotTestRebranch())
[16]282    suite.addTest(MergeBotTestCheckMerge())
283    suite.addTest(MergeBotTestSingleUseCase())
[44]284    suite.addTest(MergeBotTestMerge())
[16]285    return suite
286
287if __name__ == '__main__':
288    unittest.main(defaultTest='suite')
Note: See TracBrowser for help on using the repository browser.