You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by rj...@apache.org on 2014/11/15 02:14:53 UTC

svn commit: r1639823 [14/29] - in /bloodhound/branches/trac-1.0.2-integration/trac: ./ contrib/ contrib/cgi-bin/ contrib/workflow/ doc/ doc/dev/ doc/utils/ sample-plugins/ sample-plugins/permissions/ sample-plugins/workflow/ trac/ trac/admin/ trac/admi...

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/better_twill.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/better_twill.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/better_twill.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/better_twill.py Sat Nov 15 01:14:46 2014
@@ -1,12 +1,26 @@
-#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008-2014 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
 """better_twill is a small wrapper around twill to set some sane defaults and
 monkey-patch some better versions of some of twill's methods.
 It also handles twill's absense.
 """
 
 import os
-from os.path import abspath, dirname, join
 import sys
+import urllib
+import urlparse
+from os.path import abspath, dirname, join
 from pkg_resources import parse_version as pv
 try:
     from cStringIO import StringIO
@@ -36,9 +50,9 @@ except ImportError:
 
 if twill:
     # We want Trac to generate valid html, and therefore want to test against
-    # the html as generated by Trac.  "tidy" tries to clean up broken html, and
-    # is responsible for one difficult to track down testcase failure (for
-    # #5497).  Therefore we turn it off here.
+    # the html as generated by Trac.  "tidy" tries to clean up broken html,
+    # and is responsible for one difficult to track down testcase failure
+    # (for #5497).  Therefore we turn it off here.
     twill.commands.config('use_tidy', '0')
 
     # We use a transparent proxy to access the global browser object through
@@ -90,9 +104,9 @@ if twill:
                 context = data.splitlines()[max(0, entry.line - 5):
                                             entry.line + 6]
                 msg.append("\n# %s\n# URL: %s\n# Line %d, column %d\n\n%s\n"
-                    % (entry.message, entry.filename,
-                       entry.line, entry.column,
-                       "\n".join([each.decode('utf-8') for each in context])))
+                           % (entry.message, entry.filename, entry.line,
+                              entry.column, "\n".join([each.decode('utf-8')
+                                                       for each in context])))
             return "\n".join(msg).encode('ascii', 'xmlcharrefreplace')
 
         def _validate_xhtml(func_name, *args, **kwargs):
@@ -120,6 +134,8 @@ if twill:
         """Write the current html to a file.  Name the file based on the
         current testcase.
         """
+        import unittest
+
         frame = sys._getframe()
         while frame:
             if frame.f_code.co_name in ('runTest', 'setUp', 'tearDown'):
@@ -127,19 +143,26 @@ if twill:
                 testname = testcase.__class__.__name__
                 tracdir = testcase._testenv.tracdir
                 break
+            elif isinstance(frame.f_locals.get('self'), unittest.TestCase):
+                testcase = frame.f_locals['self']
+                testname = '%s.%s' % (testcase.__class__.__name__,
+                                      testcase._testMethodName)
+                tracdir = testcase._testenv.tracdir
+                break
             frame = frame.f_back
         else:
             # We didn't find a testcase in the stack, so we have no clue what's
             # going on.
             raise Exception("No testcase was found on the stack.  This was "
-                "really not expected, and I don't know how to handle it.")
+                            "really not expected, and I don't know how to "
+                            "handle it.")
 
         filename = os.path.join(tracdir, 'log', "%s.html" % testname)
         html_file = open(filename, 'w')
         html_file.write(b.get_html())
         html_file.close()
 
-        return filename
+        return urlparse.urljoin('file:', urllib.pathname2url(filename))
 
     # Twill isn't as helpful with errors as I'd like it to be, so we replace
     # the formvalue function.  This would be better done as a patch to Twill.
@@ -149,8 +172,8 @@ if twill:
         except (twill.errors.TwillAssertionError,
                 twill.utils.ClientForm.ItemNotFoundError), e:
             filename = twill_write_html()
-            args = e.args + (filename,)
-            raise twill.errors.TwillAssertionError(*args)
+            raise twill.errors.TwillAssertionError('%s at %s' %
+                                                   (unicode(e), filename))
     tc.formvalue = better_formvalue
     tc.fv = better_formvalue
 
@@ -163,8 +186,8 @@ if twill:
         if formname is not None: # enhancement to directly specify the form
             browser._browser.form = browser.get_form(formname)
         old_submit(fieldname)
-
     b.submit = better_browser_submit
+
     def better_submit(fieldname=None, formname=None):
         b.submit(fieldname, formname)
     tc.submit = better_submit
@@ -186,39 +209,41 @@ if twill:
         control = b.get_form_field(form, fieldname)
 
         if not control.is_of_kind('file'):
-            raise twill.errors.TwillException('ERROR: field is not a file '
-                                              'upload field!')
+            raise twill.errors.TwillException("ERROR: field is not a file "
+                                              "upload field!")
 
         b.clicked(form, control)
         control.add_file(fp, content_type, filename)
     tc.formfile = better_formfile
 
-    # Twill's tc.find() does not provide any guidance on what we got instead of
-    # what was expected.
+    # Twill's tc.find() does not provide any guidance on what we got
+    # instead of what was expected.
     def better_find(what, flags='', tcfind=tc.find):
         try:
             tcfind(what, flags)
         except twill.errors.TwillAssertionError, e:
             filename = twill_write_html()
-            args = e.args + (filename,)
-            raise twill.errors.TwillAssertionError(*args)
+            raise twill.errors.TwillAssertionError('%s at %s' %
+                                                   (unicode(e), filename))
     tc.find = better_find
+
     def better_notfind(what, flags='', tcnotfind=tc.notfind):
         try:
             tcnotfind(what, flags)
         except twill.errors.TwillAssertionError, e:
             filename = twill_write_html()
-            args = e.args + (filename,)
-            raise twill.errors.TwillAssertionError(*args)
+            raise twill.errors.TwillAssertionError('%s at %s' %
+                                                   (unicode(e), filename))
     tc.notfind = better_notfind
+
     # Same for tc.url - no hint about what went wrong!
     def better_url(should_be, tcurl=tc.url):
         try:
             tcurl(should_be)
         except twill.errors.TwillAssertionError, e:
             filename = twill_write_html()
-            args = e.args + (filename,)
-            raise twill.errors.TwillAssertionError(*args)
+            raise twill.errors.TwillAssertionError('%s at %s' %
+                                                   (unicode(e), filename))
     tc.url = better_url
 else:
     b = tc = None

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/compat.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/compat.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/compat.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/compat.py Sat Nov 15 01:14:46 2014
@@ -1,18 +1,15 @@
-#!/usr/bin/python
-import os
-import shutil
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
 
+from trac.tests.compat import rmtree
 from trac.util.compat import close_fds
-
-# On Windows, shutil.rmtree doesn't remove files with the read-only
-# attribute set, so this function explicitly removes it on every error
-# before retrying.  Even on Linux, shutil.rmtree chokes on read-only
-# directories, so we use this version in all cases.
-# Fix from http://bitten.edgewall.org/changeset/521
-def rmtree(root):
-    """Catch shutil.rmtree failures on Windows when files are read-only."""
-    def _handle_error(fn, path, excinfo):
-        os.chmod(path, 0666)
-        fn(path)
-    return shutil.rmtree(root, onerror=_handle_error)
-

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/svntestenv.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/svntestenv.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/svntestenv.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/svntestenv.py Sat Nov 15 01:14:46 2014
@@ -1,31 +1,47 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2009-2014 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
 import os
 import re
 from subprocess import call
 
 from testenv import FunctionalTestEnvironment
-from trac.tests.functional.compat import close_fds
 from trac.tests.functional import logfile
+from trac.util.compat import close_fds
+
 
 class SvnFunctionalTestEnvironment(FunctionalTestEnvironment):
     def work_dir(self):
         return os.path.join(self.dirname, 'workdir')
 
+    def repo_path(self, filename):
+        return os.path.join(self.dirname, filename)
+
     def repo_path_for_initenv(self):
-        return os.path.join(self.dirname, 'repo')
+        return self.repo_path('repo')
 
     def create_repo(self):
         """
         Initialize a repo of the type :attr:`self.repotype`.
         """
-        if call(["svnadmin", "create", self.repo_path_for_initenv()],
-                 stdout=logfile, stderr=logfile, close_fds=close_fds):
-            raise Exception('unable to create subversion repository')
-        if call(['svn', 'co', self.repo_url(), self.work_dir()], stdout=logfile,
-                 stderr=logfile, close_fds=close_fds):
+        self.svnadmin_create()
+        if call(['svn', 'co', self.repo_url(), self.work_dir()],
+                stdout=logfile, stderr=logfile, close_fds=close_fds):
             raise Exception('Checkout from %s failed.' % self.repo_url())
 
     def destroy_repo(self):
-        """The deletion of the testenvironment will remove the repo as well."""
+        """The deletion of the test environment will remove the
+        repo as well."""
         pass
 
     def repo_url(self):
@@ -38,6 +54,18 @@ class SvnFunctionalTestEnvironment(Funct
         else:
             return 'file://' + repodir
 
+    def svnadmin_create(self, filename=None):
+        """Subversion helper to create a new repository."""
+        if filename is None:
+            path = self.repo_path_for_initenv()
+        else:
+            path = self.repo_path(filename)
+        if call(["svnadmin", "create", path],
+                stdout=logfile, stderr=logfile, close_fds=close_fds):
+            raise Exception('unable to create subversion repository: %r' %
+                            path)
+        return path
+
     def svn_mkdir(self, paths, msg, username='admin'):
         """Subversion helper to create a new directory within the main
         repository.  Operates directly on the repository url, so a working
@@ -48,11 +76,12 @@ class SvnFunctionalTestEnvironment(Funct
             self._testenv.svn_mkdir(["abc", "def"], "Add dirs")
 
         """
-        self.call_in_workdir(['svn', '--username=%s' % username, 'mkdir', '-m', msg]
-                + [self.repo_url() + '/' + d for d in paths])
+        self.call_in_workdir(['svn', '--username=%s' % username,
+                              'mkdir', '-m', msg]
+                             + [self.repo_url() + '/' + d for d in paths])
         self.call_in_workdir(['svn', 'update'])
 
-    def svn_add(self, filename, data):
+    def svn_add(self, filename, data, msg=None, username='admin'):
         """Subversion helper to add a file to the given path within the main
         repository.
 
@@ -67,8 +96,10 @@ class SvnFunctionalTestEnvironment(Funct
         self.call_in_workdir(['svn', 'add', filename])
         environ = os.environ.copy()
         environ['LC_ALL'] = 'C'     # Force English messages in svn
-        output = self.call_in_workdir(['svn', '--username=admin', 'commit', '-m',
-                        'Add %s' % filename, filename], environ=environ)
+        msg = 'Add %s' % filename if msg is None else msg
+        output = self.call_in_workdir(['svn', '--username=%s' % username,
+                                       'commit', '-m', msg, filename],
+                                      environ=environ)
         try:
             revision = re.search(r'Committed revision ([0-9]+)\.',
                                  output).group(1)
@@ -77,3 +108,5 @@ class SvnFunctionalTestEnvironment(Funct
             raise Exception(*args)
         return int(revision)
 
+    def call_in_workdir(self, args, environ=None):
+        return self.call_in_dir(self.work_dir(), args, environ)

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/testcases.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/testcases.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/testcases.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/testcases.py Sat Nov 15 01:14:46 2014
@@ -1,17 +1,96 @@
-# -*- encoding: utf-8 -*-
-#!/usr/bin/python
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
 import os
+
 from trac.tests.functional import *
+from trac.util import create_file
+
+
+class TestAttachmentNonexistentParent(FunctionalTwillTestCaseSetup):
+    def runTest(self):
+        """TracError should be raised when navigating to the attachment
+        page for a nonexistent resource."""
+        self._tester.go_to_wiki('NonexistentPage')
+        tc.find("The page NonexistentPage does not exist. "
+                "You can create it here.")
+        tc.find(r"\bCreate this page\b")
+
+        tc.go(self._tester.url + '/attachment/wiki/NonexistentPage')
+        tc.find('<h1>Trac Error</h1>\s+<p class="message">'
+                'Parent resource NonexistentPage doesn\'t exist</p>')
+
+
+class TestErrorPage(FunctionalTwillTestCaseSetup):
+    """Validate the error page.
+    Defects reported to trac-hacks should use the Component defined in the
+    plugin's URL (#11434).
+    """
+    def runTest(self):
+        env = self._testenv.get_trac_environment()
+        env.config.set('components', 'RaiseExceptionPlugin.*', 'enabled')
+        env.config.save()
+        create_file(os.path.join(env.path, 'plugins',
+                                 'RaiseExceptionPlugin.py'),
+"""\
+from trac.core import Component, implements
+from trac.web.api import IRequestHandler
+
+url = None
+
+class RaiseExceptionPlugin(Component):
+    implements(IRequestHandler)
+
+    def match_request(self, req):
+        if req.path_info.startswith('/raise-exception'):
+            return True
+
+    def process_request(self, req):
+        print 'maybe?'
+        if req.args.get('report') == 'tho':
+            global url
+            url = 'http://trac-hacks.org/wiki/HelloWorldMacro'
+        raise Exception
+
+""")
+        self._testenv.restart()
+
+        try:
+            tc.go(self._tester.url + '/raise-exception')
+            tc.find(internal_error)
+            tc.find('<form class="newticket" method="get" '
+                    'action="http://trac.edgewall.org/newticket">')
+
+            tc.go(self._tester.url + '/raise-exception?report=tho')
+            tc.find(internal_error)
+            tc.find('<form class="newticket" method="get" '
+                    'action="http://trac-hacks.org/newticket">')
+            tc.find('<input type="hidden" name="component" '
+                    'value="HelloWorldMacro" />')
+        finally:
+            env.config.set('components', 'RaiseExceptionPlugin.*', 'disabled')
 
 
 class RegressionTestRev6017(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Test for regression of the plugin reload fix in r6017"""
         # Setup the DeleteTicket plugin
-        plugin = open(os.path.join(self._testenv.command_cwd, 'sample-plugins',
-            'workflow', 'DeleteTicket.py')).read()
-        open(os.path.join(self._testenv.tracdir, 'plugins', 'DeleteTicket.py'),
-             'w').write(plugin)
+        plugin = open(os.path.join(self._testenv.trac_src,
+                                   'sample-plugins', 'workflow',
+                                   'DeleteTicket.py')).read()
+        open(os.path.join(self._testenv.tracdir, 'plugins',
+                          'DeleteTicket.py'), 'w').write(plugin)
         env = self._testenv.get_trac_environment()
         prevconfig = env.config.get('ticket', 'workflow')
         env.config.set('ticket', 'workflow',
@@ -30,7 +109,6 @@ class RegressionTestRev6017(FunctionalTw
             # Remove the DeleteTicket plugin
             env.config.set('ticket', 'workflow', prevconfig)
             env.config.save()
-            self._testenv.restart()
             for ext in ('py', 'pyc', 'pyo'):
                 filename = os.path.join(self._testenv.tracdir, 'plugins',
                                         'DeleteTicket.%s' % ext)
@@ -52,7 +130,8 @@ class RegressionTestTicket3833a(Function
         env.log.debug("RegressionTestTicket3833 debug1")
         debug1 = traclogfile.read()
         self.assertNotEqual(debug1.find("RegressionTestTicket3833 debug1"), -1,
-            'Logging off when it should have been on.\n%r' % debug1)
+                            'Logging off when it should have been on.\n%r'
+                            % debug1)
 
 
 class RegressionTestTicket3833b(FunctionalTestCaseSetup):
@@ -75,7 +154,8 @@ class RegressionTestTicket3833b(Function
         self.assertNotEqual(debug2.find("RegressionTestTicket3833 info2"), -1,
                             'Logging at info failed.\n%r' % debug2)
         self.assertEqual(debug2.find("RegressionTestTicket3833 debug2"), -1,
-            'Logging still on when it should have been off.\n%r' % debug2)
+                         'Logging still on when it should have been off.\n%r'
+                         % debug2)
 
 
 class RegressionTestTicket3833c(FunctionalTestCaseSetup):
@@ -103,12 +183,11 @@ class RegressionTestTicket3833c(Function
         success = debug3.find("RegressionTestTicket3833 debug3") != -1
         if not success:
             # Ok, the testcase failed, but we really need logging enabled.
-            self._testenv.restart()
             env.log.debug("RegressionTestTicket3833 fixup3")
             fixup3 = traclogfile.read()
             message = 'Logging still off when it should have been on.\n' \
                       '%r\n%r' % (debug3, fixup3)
-        self.assert_(success, message)
+        self.assertTrue(success, message)
 
 
 class RegressionTestTicket5572(FunctionalTwillTestCaseSetup):
@@ -122,29 +201,28 @@ class RegressionTestTicket5572(Functiona
 class RegressionTestTicket7209(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Test for regression of http://trac.edgewall.org/ticket/7209"""
-        summary = random_sentence(5)
-        ticketid = self._tester.create_ticket(summary)
+        ticketid = self._tester.create_ticket()
         self._tester.create_ticket()
         self._tester.add_comment(ticketid)
-        self._tester.attach_file_to_ticket(ticketid, tempfilename='hello.txt',
+        self._tester.attach_file_to_ticket(ticketid, filename='hello.txt',
                                            description='Preserved Descr')
         self._tester.go_to_ticket(ticketid)
         tc.find('Preserved Descr')
         # Now replace the existing attachment, and the description should come
         # through.
-        self._tester.attach_file_to_ticket(ticketid, tempfilename='hello.txt',
+        self._tester.attach_file_to_ticket(ticketid, filename='hello.txt',
                                            description='', replace=True)
         self._tester.go_to_ticket(ticketid)
         tc.find('Preserved Descr')
 
-        self._tester.attach_file_to_ticket(ticketid, tempfilename='blah.txt',
+        self._tester.attach_file_to_ticket(ticketid, filename='blah.txt',
                                            description='Second Attachment')
         self._tester.go_to_ticket(ticketid)
         tc.find('Second Attachment')
 
         # This one should get a new description when it's replaced
         # (Second->Other)
-        self._tester.attach_file_to_ticket(ticketid, tempfilename='blah.txt',
+        self._tester.attach_file_to_ticket(ticketid, filename='blah.txt',
                                            description='Other Attachment',
                                            replace=True)
         self._tester.go_to_ticket(ticketid)
@@ -159,10 +237,9 @@ class RegressionTestTicket9880(Functiona
         Upload of a file which the browsers associates a Content-Type
         of multipart/related (e.g. an .mht file) should succeed.
         """
-        summary = random_sentence(5)
-        ticketid = self._tester.create_ticket(summary)
+        ticketid = self._tester.create_ticket()
         self._tester.create_ticket()
-        self._tester.attach_file_to_ticket(ticketid, tempfilename='hello.mht',
+        self._tester.attach_file_to_ticket(ticketid, filename='hello.mht',
                                            content_type='multipart/related',
                                            data="""
 Well, the actual content of the file doesn't matter, the problem is
@@ -171,15 +248,6 @@ See also http://bugs.python.org/issue155
 """)
 
 
-class ErrorPageValidation(FunctionalTwillTestCaseSetup):
-    def runTest(self):
-        """Validate the error page"""
-        url = self._tester.url + '/wiki/WikiStart'
-        tc.go(url + '?version=bug')
-        tc.url(url)
-        tc.find(internal_error)
-
-
 class RegressionTestTicket3663(FunctionalTwillTestCaseSetup):
     def runTest(self):
         """Regression test for non-UTF-8 PATH_INFO (#3663)
@@ -196,14 +264,79 @@ class RegressionTestTicket3663(Functiona
         tc.find('Invalid URL encoding')
 
 
-def functionalSuite():
-    suite = FunctionalTestSuite()
-    return suite
+class RegressionTestTicket6318(FunctionalTwillTestCaseSetup):
+    def runTest(self):
+        """Regression test for non-ascii usernames (#6318)
+        """
+        # first do a logout, otherwise we might end up logged in as
+        # admin again, as this is the first thing the tester does.
+        # ... but even before that we need to make sure we're coming
+        # from a valid URL, which is not the case if we're just coming
+        # from the above test! ('/wiki/\xE9t\xE9')
+        self._tester.go_to_front()
+        self._tester.logout()
+        try:
+            # also test a regular ascii user name
+            self._testenv.adduser(u'user')
+            self._tester.login(u'user')
+            self._tester.go_to_front()
+            self._tester.logout()
+            # now test utf-8 user name
+            self._testenv.adduser(u'joé')
+            self._tester.login(u'joé')
+            self._tester.go_to_front()
+            self._tester.logout()
+            # finally restore expected 'admin' login
+            self._tester.login('admin')
+        finally:
+            self._testenv.deluser(u'joé')
+
+
+class RegressionTestTicket11434(FunctionalTwillTestCaseSetup):
+    """Test for regression of http://trac.edgewall.org/ticket/11434
+    Defects reported to trac-hacks should use the Component defined in the
+    plugin's URL.
+    """
+    def runTest(self):
+        env = self._testenv.get_trac_environment()
+        env.config.set('components', 'RaiseExceptionPlugin.*', 'enabled')
+        env.config.save()
+        create_file(os.path.join(env.path, 'plugins', 'RaiseExceptionPlugin.py'),
+"""\
+from trac.core import Component, implements
+from trac.web.api import IRequestHandler
+
+url = 'http://trac-hacks.org/wiki/HelloWorldMacro'
+
+class RaiseExceptionPlugin(Component):
+    implements(IRequestHandler)
+
+    def match_request(self, req):
+        if req.path_info == '/raise-exception':
+            return True
+
+    def process_request(self, req):
+        raise Exception
+
+""")
 
+        try:
+            tc.go(self._tester.url + '/raise-exception')
+            tc.find(internal_error)
+            tc.find('<form class="newticket" method="get" '
+                    'action="http://trac-hacks.org/newticket">')
+            tc.find('<input type="hidden" name="component" '
+                    'value="HelloWorldMacro" />')
+        finally:
+            env.config.set('components', 'RaiseExceptionPlugin.*', 'disabled')
 
-def suite():
-    suite = functionalSuite()
 
+def functionalSuite(suite=None):
+    if not suite:
+        import trac.tests.functional
+        suite = trac.tests.functional.functionalSuite()
+    suite.addTest(TestAttachmentNonexistentParent())
+    suite.addTest(TestErrorPage())
     suite.addTest(RegressionTestRev6017())
     suite.addTest(RegressionTestTicket3833a())
     suite.addTest(RegressionTestTicket3833b())
@@ -211,27 +344,11 @@ def suite():
     suite.addTest(RegressionTestTicket5572())
     suite.addTest(RegressionTestTicket7209())
     suite.addTest(RegressionTestTicket9880())
-    suite.addTest(ErrorPageValidation())
     suite.addTest(RegressionTestTicket3663())
-
-    import trac.versioncontrol.tests
-    trac.versioncontrol.tests.functionalSuite(suite)
-    import trac.ticket.tests
-    trac.ticket.tests.functionalSuite(suite)
-    import trac.prefs.tests
-    trac.prefs.tests.functionalSuite(suite)
-    import trac.wiki.tests
-    trac.wiki.tests.functionalSuite(suite)
-    import trac.timeline.tests
-    trac.timeline.tests.functionalSuite(suite)
-    import trac.admin.tests
-    trac.admin.tests.functionalSuite(suite)
-    # The db tests should be last since the backup test occurs there.
-    import trac.db.tests
-    trac.db.tests.functionalSuite(suite)
-
+    suite.addTest(RegressionTestTicket6318())
+    suite.addTest(RegressionTestTicket11434())
     return suite
 
 
 if __name__ == '__main__':
-    unittest.main(defaultTest='suite')
+    unittest.main(defaultTest='functionalSuite')

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/testenv.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/testenv.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/testenv.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/testenv.py Sat Nov 15 01:14:46 2014
@@ -1,24 +1,40 @@
-#!/usr/bin/python
 # -*- coding: utf-8 -*-
 #
+# Copyright (C) 2008-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
 """Object for creating and destroying a Trac environment for testing purposes.
 Provides some Trac environment-wide utility functions, and a way to call
 :command:`trac-admin` without it being on the path."""
 
+import locale
 import os
-import time
-import signal
+import re
 import sys
-import errno
-import locale
+import time
 from subprocess import call, Popen, PIPE, STDOUT
 
 from trac.env import open_environment
 from trac.test import EnvironmentStub, get_dburi
-from trac.tests.functional.compat import rmtree
-from trac.tests.functional import logfile
+from trac.tests.compat import rmtree
+from trac.tests.functional import logfile, trac_source_tree
 from trac.tests.functional.better_twill import tc, ConnectError
-from trac.util.compat import close_fds
+from trac.util import terminate
+from trac.util.compat import close_fds, wait_for_file_mtime_change
+from trac.util.text import to_utf8
+
+try:
+    from configobj import ConfigObj
+except ImportError:
+    ConfigObj = None
 
 # TODO: refactor to support testing multiple frontends, backends
 #       (and maybe repositories and authentication).
@@ -33,6 +49,7 @@ from trac.util.compat import close_fds
 #       (those need to test search escaping, among many other things like long
 #       paths in browser and unicode chars being allowed/translating...)
 
+
 class FunctionalTestEnvironment(object):
     """Common location for convenience functions that work with the test
     environment on Trac.  Subclass this and override some methods if you are
@@ -47,6 +64,7 @@ class FunctionalTestEnvironment(object):
     def __init__(self, dirname, port, url):
         """Create a :class:`FunctionalTestEnvironment`, see the class itself
         for parameter information."""
+        self.trac_src = trac_source_tree
         self.url = url
         self.command_cwd = os.path.normpath(os.path.join(dirname, '..'))
         self.dirname = os.path.abspath(dirname)
@@ -60,8 +78,6 @@ class FunctionalTestEnvironment(object):
         self.create()
         locale.setlocale(locale.LC_ALL, '')
 
-    trac_src = '.'
-
     @property
     def dburi(self):
         dburi = get_dburi()
@@ -97,11 +113,13 @@ class FunctionalTestEnvironment(object):
 
     def post_create(self, env):
         """Hook for modifying the environment after creation.  For example, to
-        set configuration like::
+        set configuration like:
+        ::
 
             def post_create(self, env):
                 env.config.set('git', 'path', '/usr/bin/git')
                 env.config.save()
+
         """
         pass
 
@@ -125,10 +143,11 @@ class FunctionalTestEnvironment(object):
         if call([sys.executable,
                  os.path.join(self.trac_src, 'contrib', 'htpasswd.py'), "-c",
                  "-b", self.htpasswd, "admin", "admin"], close_fds=close_fds,
-                 cwd=self.command_cwd):
+                cwd=self.command_cwd):
             raise Exception('Unable to setup admin password')
         self.adduser('user')
-        self._tracadmin('permission', 'add', 'admin', 'TRAC_ADMIN')
+        self.adduser('joe')
+        self.grant_perm('admin', 'TRAC_ADMIN')
         # Setup Trac logging
         env = self.get_trac_environment()
         env.config.set('logging', 'log_type', 'file')
@@ -140,23 +159,89 @@ class FunctionalTestEnvironment(object):
     def adduser(self, user):
         """Add a user to the environment.  The password will be set to the
         same as username."""
+        user = to_utf8(user)
         if call([sys.executable, os.path.join(self.trac_src, 'contrib',
                  'htpasswd.py'), '-b', self.htpasswd,
                  user, user], close_fds=close_fds, cwd=self.command_cwd):
             raise Exception('Unable to setup password for user "%s"' % user)
 
+    def deluser(self, user):
+        """Delete a user from the environment."""
+        user = to_utf8(user)
+        self._tracadmin('session', 'delete', user)
+        if call([sys.executable, os.path.join(self.trac_src, 'contrib',
+                 'htpasswd.py'), '-D', self.htpasswd, user],
+                close_fds=close_fds, cwd=self.command_cwd):
+            raise Exception('Unable to remove password for user "%s"' % user)
+
+    def grant_perm(self, user, perm):
+        """Grant permission(s) to specified user. A single permission may
+        be specified as a string, or multiple permissions may be
+        specified as a list or tuple of strings."""
+        if isinstance(perm, (list, tuple)):
+            self._tracadmin('permission', 'add', user, *perm)
+        else:
+            self._tracadmin('permission', 'add', user, perm)
+        # We need to force an environment reset, as this is necessary
+        # for the permission change to take effect: grant only
+        # invalidates the `DefaultPermissionStore._all_permissions`
+        # cache, but the `DefaultPermissionPolicy.permission_cache` is
+        # unaffected.
+        self.get_trac_environment().config.touch()
+
+    def revoke_perm(self, user, perm):
+        """Revoke permission(s) from specified user. A single permission
+        may be specified as a string, or multiple permissions may be
+        specified as a list or tuple of strings."""
+        if isinstance(perm, (list, tuple)):
+            self._tracadmin('permission', 'remove', user, *perm)
+        else:
+            self._tracadmin('permission', 'remove', user, perm)
+        # Force an environment reset (see grant_perm above)
+        self.get_trac_environment().config.touch()
+
+    def set_config(self, *args):
+        """Calls trac-admin to get the value for the given option
+        in `trac.ini`."""
+        self._tracadmin('config', 'set', *args)
+
+    def get_config(self, *args):
+        """Calls trac-admin to set the value for the given option
+        in `trac.ini`."""
+        return self._tracadmin('config', 'get', *args)
+
+    def remove_config(self, *args):
+        """Calls trac-admin to remove the value for the given option
+        in `trac.ini`."""
+        return self._tracadmin('config', 'remove', *args)
+
     def _tracadmin(self, *args):
         """Internal utility method for calling trac-admin"""
         proc = Popen([sys.executable, os.path.join(self.trac_src, 'trac',
-                      'admin', 'console.py'), self.tracdir]
-                      + list(args), stdout=PIPE, stderr=STDOUT,
-                      close_fds=close_fds, cwd=self.command_cwd)
-        out = proc.communicate()[0]
+                      'admin', 'console.py'), self.tracdir],
+                     stdin=PIPE, stdout=PIPE, stderr=STDOUT,
+                     close_fds=close_fds, cwd=self.command_cwd)
+        if args:
+            if any('\n' in arg for arg in args):
+                raise Exception(
+                    "trac-admin in interactive mode doesn't support "
+                    "arguments with newline characters: %r" % (args,))
+            # Don't quote first token which is sub-command name
+            input = ' '.join(('"%s"' % to_utf8(arg) if idx else arg)
+                             for idx, arg in enumerate(args))
+        else:
+            input = None
+        out = proc.communicate(input=input)[0]
         if proc.returncode:
             print(out)
             logfile.write(out)
-            raise Exception('Failed with exitcode %s running trac-admin ' \
-                            'with %r' % (proc.returncode, args))
+            raise Exception("Failed while running trac-admin with arguments %r.\n"
+                            "Exitcode: %s \n%s"
+                            % (args, proc.returncode, out))
+        else:
+            # trac-admin is started in interactive mode, so we strip away
+            # everything up to the to the interactive prompt
+            return re.split(r'\r?\nTrac \[[^]]+\]> ', out, 2)[1]
 
     def start(self):
         """Starts the webserver, and waits for it to come up."""
@@ -177,8 +262,7 @@ class FunctionalTestEnvironment(object):
         server = Popen(args + options + [self.tracdir],
                        stdout=logfile, stderr=logfile,
                        close_fds=close_fds,
-                       cwd=self.command_cwd,
-                      )
+                       cwd=self.command_cwd)
         self.pid = server.pid
         # Verify that the url is ok
         timeout = 30
@@ -199,17 +283,7 @@ class FunctionalTestEnvironment(object):
         FIXME: probably needs a nicer way to exit for coverage to work
         """
         if self.pid:
-            if os.name == 'nt':
-                # Untested
-                res = call(["taskkill", "/f", "/pid", str(self.pid)],
-                     stdin=PIPE, stdout=PIPE, stderr=PIPE)
-            else:
-                os.kill(self.pid, signal.SIGTERM)
-                try:
-                    os.waitpid(self.pid, 0)
-                except OSError, e:
-                    if e.errno != errno.ESRCH:
-                        raise
+            terminate(self)
 
     def restart(self):
         """Restarts the webserver"""
@@ -224,13 +298,73 @@ class FunctionalTestEnvironment(object):
         """Default to no repository"""
         return "''" # needed for Python 2.3 and 2.4 on win32
 
-    def call_in_workdir(self, args, environ=None):
+    def call_in_dir(self, dir, args, environ=None):
         proc = Popen(args, stdout=PIPE, stderr=logfile,
-                     close_fds=close_fds, cwd=self.work_dir(), env=environ)
+                     close_fds=close_fds, cwd=dir, env=environ)
         (data, _) = proc.communicate()
         if proc.wait():
             raise Exception('Unable to run command %s in %s' %
-                            (args, self.work_dir()))
-
+                            (args, dir))
         logfile.write(data)
         return data
+
+    def enable_authz_permpolicy(self, authz_content, filename=None):
+        """Enables the Authz permissions policy. The `authz_content` will
+        be written to `filename`, and may be specified in a triple-quoted
+        string.::
+
+           [wiki:WikiStart@*]
+           * = WIKI_VIEW
+           [wiki:PrivatePage@*]
+           john = WIKI_VIEW
+           * = !WIKI_VIEW
+
+        `authz_content` may also be a dictionary of dictionaries specifying
+        the sections and key/value pairs of each section, however this form
+        should only be used when the order of the entries in the file is not
+        important, as the order cannot be known.::
+
+           {
+            'wiki:WikiStart@*': {'*': 'WIKI_VIEW'},
+            'wiki:PrivatePage@*': {'john': 'WIKI_VIEW', '*': '!WIKI_VIEW'},
+           }
+
+        The `filename` parameter is optional, and if omitted a filename will
+        be generated by computing a hash of `authz_content`, prefixed with
+        "authz-".
+        """
+        if not ConfigObj:
+            raise ImportError("Can't enable authz permissions policy. " +
+                              "ConfigObj not installed.")
+        if filename is None:
+            from hashlib import md5
+            filename = 'authz-' + md5(str(authz_content)).hexdigest()[0:9]
+        env = self.get_trac_environment()
+        permission_policies = env.config.get('trac', 'permission_policies')
+        env.config.set('trac', 'permission_policies',
+                       'AuthzPolicy, ' + permission_policies)
+        authz_file = self.tracdir + '/conf/' + filename
+        if isinstance(authz_content, basestring):
+            authz_content = [line.strip() for line in
+                             authz_content.strip().splitlines()]
+        authz_config = ConfigObj(authz_content, encoding='utf8',
+                                 write_empty_values=True, indent_type='')
+        authz_config.filename = authz_file
+        wait_for_file_mtime_change(authz_file)
+        authz_config.write()
+        env.config.set('authz_policy', 'authz_file', authz_file)
+        env.config.set('components', 'tracopt.perm.authz_policy.*', 'enabled')
+        env.config.save()
+
+    def disable_authz_permpolicy(self):
+        """Disables the Authz permission policy."""
+        env = self.get_trac_environment()
+        permission_policies = env.config.get('trac', 'permission_policies')
+        pp_list = [p.strip() for p in permission_policies.split(',')]
+        if 'AuthzPolicy' in pp_list:
+            pp_list.remove('AuthzPolicy')
+        permission_policies = ', '.join(pp_list)
+        env.config.set('trac', 'permission_policies', permission_policies)
+        env.config.remove('authz_policy', 'authz_file')
+        env.config.remove('components', 'tracopt.perm.authz_policy.*')
+        env.config.save()

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/tester.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/tester.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/tester.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/functional/tester.py Sat Nov 15 01:14:46 2014
@@ -1,19 +1,34 @@
-#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
 """The :class:`FunctionalTester` object provides a higher-level interface to
 working with a Trac environment to make test cases more succinct.
 """
 
+import re
+
 from trac.tests.functional import internal_error
 from trac.tests.functional.better_twill import tc, b
 from trac.tests.contentgen import random_page, random_sentence, random_word, \
-    random_unique_camel
-from trac.util.text import unicode_quote
+                                  random_unique_camel
+from trac.util.text import to_utf8, unicode_quote
 
 try:
     from cStringIO import StringIO
 except ImportError:
     from StringIO import StringIO
 
+
 class FunctionalTester(object):
     """Provides a library of higher-level operations for interacting with a
     test environment.
@@ -34,10 +49,11 @@ class FunctionalTester(object):
 
     def login(self, username):
         """Login as the given user"""
+        username = to_utf8(username)
         tc.add_auth("", self.url, username, username)
         self.go_to_front()
         tc.find("Login")
-        tc.follow("Login")
+        tc.follow(r"\bLogin\b")
         # We've provided authentication info earlier, so this should
         # redirect back to the base url.
         tc.find("logged in as %s" % username)
@@ -47,8 +63,9 @@ class FunctionalTester(object):
 
     def logout(self):
         """Logout"""
-        tc.follow("Logout")
+        tc.submit('logout', 'logout')
         tc.notfind(internal_error)
+        tc.notfind('logged in as')
 
     def create_ticket(self, summary=None, info=None):
         """Create a new (random) ticket in the test environment.  Returns
@@ -63,10 +80,10 @@ class FunctionalTester(object):
         `summary` and `description` default to randomly-generated values.
         """
         self.go_to_front()
-        tc.follow('New Ticket')
+        tc.follow(r"\bNew Ticket\b")
         tc.notfind(internal_error)
-        if summary == None:
-            summary = random_sentence(4)
+        if summary is None:
+            summary = random_sentence(5)
         tc.formvalue('propertyform', 'field_summary', summary)
         tc.formvalue('propertyform', 'field_description', random_page())
         if info:
@@ -75,17 +92,12 @@ class FunctionalTester(object):
         tc.submit('submit')
         # we should be looking at the newly created ticket
         tc.url(self.url + '/ticket/%s' % (self.ticketcount + 1))
+        tc.notfind(internal_error)
         # Increment self.ticketcount /after/ we've verified that the ticket
         # was created so a failure does not trigger spurious later
         # failures.
         self.ticketcount += 1
 
-        # verify the ticket creation event shows up in the timeline
-        self.go_to_timeline()
-        tc.formvalue('prefs', 'ticket', True)
-        tc.submit()
-        tc.find('Ticket.*#%s.*created' % self.ticketcount)
-
         return self.ticketcount
 
     def quickjump(self, search):
@@ -94,51 +106,91 @@ class FunctionalTester(object):
         tc.submit()
         tc.notfind(internal_error)
 
+    def go_to_url(self, url):
+        tc.go(url)
+        tc.url(re.escape(url))
+        tc.notfind(internal_error)
+
     def go_to_front(self):
         """Go to the Trac front page"""
-        tc.go(self.url)
-        tc.url(self.url)
-        tc.notfind(internal_error)
+        self.go_to_url(self.url)
 
-    def go_to_ticket(self, ticketid):
-        """Surf to the page for the given ticket ID.  Assumes ticket
-        exists."""
-        ticket_url = self.url + "/ticket/%s" % ticketid
-        tc.go(ticket_url)
-        tc.url(ticket_url)
+    def go_to_ticket(self, ticketid=None):
+        """Surf to the page for the given ticket ID, or to the NewTicket page
+        if `ticketid` is not specified or is `None`. If `ticketid` is
+        specified, it assumes the ticket exists."""
+        if ticketid is not None:
+            ticket_url = self.url + '/ticket/%s' % ticketid
+        else:
+            ticket_url = self.url + '/newticket'
+        self.go_to_url(ticket_url)
+        tc.url(ticket_url + '$')
+
+    def go_to_wiki(self, name, version=None):
+        """Surf to the wiki page. By default this will be the latest version
+        of the page.
 
-    def go_to_wiki(self, name):
-        """Surf to the page for the given wiki page."""
+        :param name: name of the wiki page.
+        :param version: version of the wiki page.
+        """
         # Used to go based on a quickjump, but if the wiki pagename isn't
         # camel case, that won't work.
         wiki_url = self.url + '/wiki/%s' % name
-        tc.go(wiki_url)
-        tc.url(wiki_url)
+        if version:
+            wiki_url += '?version=%s' % version
+        self.go_to_url(wiki_url)
 
     def go_to_timeline(self):
         """Surf to the timeline page."""
         self.go_to_front()
-        tc.follow('Timeline')
+        tc.follow(r"\bTimeline\b")
         tc.url(self.url + '/timeline')
 
+    def go_to_view_tickets(self, href='report'):
+        """Surf to the View Tickets page. By default this will be the Reports
+        page, but 'query' can be specified for the `href` argument to support
+        non-default configurations."""
+        self.go_to_front()
+        tc.follow(r"\bView Tickets\b")
+        tc.url(self.url + '/' + href.lstrip('/'))
+
     def go_to_query(self):
         """Surf to the custom query page."""
         self.go_to_front()
-        tc.follow('View Tickets')
-        tc.follow('Custom Query')
+        tc.follow(r"\bView Tickets\b")
+        tc.follow(r"\bCustom Query\b")
         tc.url(self.url + '/query')
 
-    def go_to_admin(self):
-        """Surf to the webadmin page."""
+    def go_to_admin(self, panel_label=None):
+        """Surf to the webadmin page. Continue surfing to a specific
+        admin page if `panel_label` is specified."""
         self.go_to_front()
-        tc.follow('\\bAdmin\\b')
+        tc.follow(r"\bAdmin\b")
+        tc.url(self.url + '/admin')
+        if panel_label is not None:
+            tc.follow(r"\b%s\b" % panel_label)
 
     def go_to_roadmap(self):
         """Surf to the roadmap page."""
         self.go_to_front()
-        tc.follow('\\bRoadmap\\b')
+        tc.follow(r"\bRoadmap\b")
         tc.url(self.url + '/roadmap')
 
+    def go_to_milestone(self, name):
+        """Surf to the specified milestone page. Assumes milestone exists."""
+        self.go_to_roadmap()
+        tc.follow(r"\bMilestone: %s\b" % name)
+        tc.url(self.url + '/milestone/%s' % name)
+
+    def go_to_preferences(self, panel_label=None):
+        """Surf to the preferences page. Continue surfing to a specific
+        preferences panel if `panel_label` is specified."""
+        self.go_to_front()
+        tc.follow(r"\bPreferences\b")
+        tc.url(self.url + '/prefs')
+        if panel_label is not None:
+            tc.follow(r"\b%s\b" % panel_label)
+
     def add_comment(self, ticketid, comment=None):
         """Adds a comment to the given ticket ID, assumes ticket exists."""
         self.go_to_ticket(ticketid)
@@ -152,35 +204,16 @@ class FunctionalTester(object):
         tc.url(self.url + '/ticket/%s(?:#comment:.*)?$' % ticketid)
         return comment
 
-    def attach_file_to_ticket(self, ticketid, data=None, tempfilename=None,
+    def attach_file_to_ticket(self, ticketid, data=None, filename=None,
                               description=None, replace=False,
                               content_type=None):
         """Attaches a file to the given ticket id, with random data if none is
         provided.  Assumes the ticket exists.
         """
-        if data is None:
-            data = random_page()
-        if description is None:
-            description = random_sentence()
-        if tempfilename is None:
-            tempfilename = random_word()
-
         self.go_to_ticket(ticketid)
-        # set the value to what it already is, so that twill will know we
-        # want this form.
-        tc.formvalue('attachfile', 'action', 'new')
-        tc.submit()
-        tc.url(self.url + "/attachment/ticket/" \
-               "%s/\\?action=new&attachfilebutton=Attach\\+file" % ticketid)
-        fp = StringIO(data)
-        tc.formfile('attachment', 'attachment', tempfilename,
-                    content_type=content_type, fp=fp)
-        tc.formvalue('attachment', 'description', description)
-        if replace:
-            tc.formvalue('attachment', 'replace', True)
-        tc.submit()
-        tc.url(self.url + '/attachment/ticket/%s/$' % ticketid)
-        return tempfilename
+        return self._attach_file_to_resource('ticket', ticketid, data,
+                                             filename, description,
+                                             replace, content_type)
 
     def clone_ticket(self, ticketid):
         """Create a clone of the given ticket id using the clone button."""
@@ -194,57 +227,66 @@ class FunctionalTester(object):
         tc.url(self.url + "/ticket/%s" % self.ticketcount)
         return self.ticketcount
 
-    def create_wiki_page(self, page, content=None):
-        """Creates the specified wiki page, with random content if none is
-        provided.
+    def create_wiki_page(self, name=None, content=None, comment=None):
+        """Creates a wiki page, with a random unique CamelCase name if none
+        is provided, random content if none is provided and a random comment
+        if none is provided.  Returns the name of the wiki page.
         """
-        if content == None:
+        if name is None:
+            name = random_unique_camel()
+        if content is None:
             content = random_page()
-        page_url = self.url + "/wiki/" + page
-        tc.go(page_url)
-        tc.url(page_url)
-        tc.find("The page %s does not exist." % page)
-        tc.formvalue('modifypage', 'action', 'edit')
-        tc.submit()
-        tc.url(page_url + '\\?action=edit')
+        self.go_to_wiki(name)
+        tc.find("The page %s does not exist." % name)
 
-        tc.formvalue('edit', 'text', content)
-        tc.submit('save')
-        tc.url(page_url+'$')
+        self.edit_wiki_page(name, content, comment)
 
         # verify the event shows up in the timeline
         self.go_to_timeline()
         tc.formvalue('prefs', 'wiki', True)
         tc.submit()
-        tc.find(page + ".*created")
+        tc.find(name + ".*created")
 
-    def attach_file_to_wiki(self, name, data=None, tempfilename=None):
+        self.go_to_wiki(name)
+
+        return name
+
+    def edit_wiki_page(self, name, content=None, comment=None):
+        """Edits a wiki page, with random content is none is provided.
+        and a random comment if none is provided. Returns the content.
+        """
+        if content is None:
+            content = random_page()
+        if comment is None:
+            comment = random_sentence()
+        self.go_to_wiki(name)
+        tc.formvalue('modifypage', 'action', 'edit')
+        tc.submit()
+        tc.formvalue('edit', 'text', content)
+        tc.formvalue('edit', 'comment', comment)
+        tc.submit('save')
+        page_url = self.url + '/wiki/%s' % name
+        tc.url(page_url+'$')
+
+        return content
+
+    def attach_file_to_wiki(self, name, data=None, filename=None,
+                            description=None, replace=False,
+                            content_type=None):
         """Attaches a file to the given wiki page, with random content if none
         is provided.  Assumes the wiki page exists.
         """
-        if data == None:
-            data = random_page()
-        if tempfilename is None:
-            tempfilename = random_word()
+
         self.go_to_wiki(name)
-        # set the value to what it already is, so that twill will know we
-        # want this form.
-        tc.formvalue('attachfile', 'action', 'new')
-        tc.submit()
-        tc.url(self.url + "/attachment/wiki/" \
-               "%s/\\?action=new&attachfilebutton=Attach\\+file" % name)
-        fp = StringIO(data)
-        tc.formfile('attachment', 'attachment', tempfilename, fp=fp)
-        tc.formvalue('attachment', 'description', random_sentence())
-        tc.submit()
-        tc.url(self.url + '/attachment/wiki/%s/$' % name)
-        return tempfilename
+        return self._attach_file_to_resource('wiki', name, data,
+                                             filename, description,
+                                             replace, content_type)
 
     def create_milestone(self, name=None, due=None):
         """Creates the specified milestone, with a random name if none is
         provided.  Returns the name of the milestone.
         """
-        if name == None:
+        if name is None:
             name = random_unique_camel()
         milestone_url = self.url + "/admin/ticket/milestones"
         tc.go(milestone_url)
@@ -260,32 +302,51 @@ class FunctionalTester(object):
         tc.find(name)
 
         # Make sure it's on the roadmap.
-        tc.follow('Roadmap')
+        tc.follow(r"\bRoadmap\b")
         tc.url(self.url + "/roadmap")
         tc.find('Milestone:.*%s' % name)
-        tc.follow(name)
+        tc.follow(r"\b%s\b" % name)
         tc.url('%s/milestone/%s' % (self.url, unicode_quote(name)))
         if not due:
             tc.find('No date set')
 
         return name
 
-    def create_component(self, name=None, user=None):
+    def attach_file_to_milestone(self, name, data=None, filename=None,
+                                 description=None, replace=False,
+                                 content_type=None):
+        """Attaches a file to the given milestone, with random content if none
+        is provided.  Assumes the milestone exists.
+        """
+
+        self.go_to_milestone(name)
+        return self._attach_file_to_resource('milestone', name, data,
+                                             filename, description,
+                                             replace, content_type)
+
+    def create_component(self, name=None, owner=None, description=None):
         """Creates the specified component, with a random camel-cased name if
         none is provided.  Returns the name."""
-        if name == None:
+        if name is None:
             name = random_unique_camel()
         component_url = self.url + "/admin/ticket/components"
         tc.go(component_url)
         tc.url(component_url)
         tc.formvalue('addcomponent', 'name', name)
-        if user != None:
-            tc.formvalue('addcomponent', 'owner', user)
+        if owner is not None:
+            tc.formvalue('addcomponent', 'owner', owner)
         tc.submit()
         # Verify the component appears in the component list
         tc.url(component_url)
         tc.find(name)
         tc.notfind(internal_error)
+        if description is not None:
+            tc.follow(r"\b%s\b" % name)
+            tc.formvalue('modcomp', 'description', description)
+            tc.submit('save')
+            tc.url(component_url)
+            tc.find("Your changes have been saved.")
+            tc.notfind(internal_error)
         # TODO: verify the component shows up in the newticket page
         return name
 
@@ -294,7 +355,7 @@ class FunctionalTester(object):
         ``severity``, etc). If no name is given, a unique random word is used.
         The name is returned.
         """
-        if name == None:
+        if name is None:
             name = random_unique_camel()
         priority_url = self.url + "/admin/ticket/" + kind
         tc.go(priority_url)
@@ -326,12 +387,12 @@ class FunctionalTester(object):
         """Create a new version.  The name defaults to a random camel-cased
         word if not provided."""
         version_admin = self.url + "/admin/ticket/versions"
-        if name == None:
+        if name is None:
             name = random_unique_camel()
         tc.go(version_admin)
         tc.url(version_admin)
         tc.formvalue('addversion', 'name', name)
-        if releasetime != None:
+        if releasetime is not None:
             tc.formvalue('addversion', 'time', releasetime)
         tc.submit()
         tc.url(version_admin)
@@ -342,7 +403,7 @@ class FunctionalTester(object):
     def create_report(self, title, query, description):
         """Create a new report with the given title, query, and description"""
         self.go_to_front()
-        tc.follow('View Tickets')
+        tc.follow(r"\bView Tickets\b")
         tc.formvalue('create_report', 'action', 'new') # select the right form
         tc.submit()
         tc.find('New Report')
@@ -364,3 +425,29 @@ class FunctionalTester(object):
         tc.formvalue('propertyform', 'milestone', milestone)
         tc.submit('submit')
         # TODO: verify the change occurred.
+
+    def _attach_file_to_resource(self, realm, name, data=None,
+                                 filename=None, description=None,
+                                 replace=False, content_type=None):
+        """Attaches a file to a resource. Assumes the resource exists and
+           has already been navigated to."""
+
+        if data is None:
+            data = random_page()
+        if description is None:
+            description = random_sentence()
+        if filename is None:
+            filename = random_word()
+
+        tc.submit('attachfilebutton', 'attachfile')
+        tc.url(self.url + r'/attachment/%s/%s/\?action=new$' % (realm, name))
+        fp = StringIO(data)
+        tc.formfile('attachment', 'attachment', filename,
+                    content_type=content_type, fp=fp)
+        tc.formvalue('attachment', 'description', description)
+        if replace:
+            tc.formvalue('attachment', 'replace', True)
+        tc.submit()
+        tc.url(self.url + r'/attachment/%s/%s/$' % (realm, name))
+
+        return filename

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/notification.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/notification.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/notification.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/notification.py Sat Nov 15 01:14:46 2014
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2005-2009 Edgewall Software
+# Copyright (C) 2005-2013 Edgewall Software
 # Copyright (C) 2005-2006 Emmanuel Blot <em...@free.fr>
 # All rights reserved.
 #
@@ -19,24 +19,30 @@
 # classes to run SMTP notification tests
 #
 
+import base64
+import os
+import quopri
+import re
 import socket
 import string
 import threading
-import re
-import base64
-import quopri
+import unittest
 
+from trac.config import ConfigurationError
+from trac.notification import SendmailEmailSender, SmtpEmailSender
+from trac.test import EnvironmentStub
 
 LF = '\n'
 CR = '\r'
-email_re = re.compile(r"([\w\d_\.\-])+\@(([\w\d\-])+\.)+([\w\d]{2,4})+")
+SMTP_TEST_PORT = 7000 + os.getpid() % 1000
+email_re = re.compile(r'([\w\d_\.\-])+\@(([\w\d\-])+\.)+([\w\d]{2,4})+')
 header_re = re.compile(r'^=\?(?P<charset>[\w\d\-]+)\?(?P<code>[qb])\?(?P<value>.*)\?=$')
 
 
 class SMTPServerInterface:
     """
-    A base class for the imlementation of an application specific SMTP
-    Server. Applications should subclass this and overide these
+    A base class for the implementation of an application specific SMTP
+    Server. Applications should subclass this and override these
     methods, which by default do nothing.
 
     A method is defined for each RFC821 command. For each of these
@@ -44,7 +50,7 @@ class SMTPServerInterface:
     client. The 'data' method is called after all of the client DATA
     is received.
 
-    If a method returns 'None', then a '250 OK'message is
+    If a method returns 'None', then a '250 OK' message is
     automatically sent to the client. If a subclass returns a non-null
     string then it is returned instead.
     """
@@ -67,10 +73,10 @@ class SMTPServerInterface:
     def reset(self, args):
         return None
 
+
 #
 # Some helper functions for manipulating from & to addresses etc.
 #
-
 def strip_address(address):
     """
     Strip the leading & trailing <> from an address.  Handy for
@@ -80,6 +86,7 @@ def strip_address(address):
     end = string.index(address, '>')
     return address[start:end]
 
+
 def split_to(address):
     """
     Return 'address' as undressed (host, fulladdress) tuple.
@@ -88,7 +95,7 @@ def split_to(address):
     start = string.index(address, '<') + 1
     sep = string.index(address, '@') + 1
     end = string.index(address, '>')
-    return (address[sep:end], address[start:end],)
+    return address[sep:end], address[start:end]
 
 
 #
@@ -133,13 +140,13 @@ class SMTPServerEngine:
                     lump = self.socket.recv(1024)
                     if len(lump):
                         data += lump
-                        if (len(data) >= 2) and data[-2:] == '\r\n':
+                        if len(data) >= 2 and data[-2:] == '\r\n':
                             completeLine = 1
                             if self.state != SMTPServerEngine.ST_DATA:
                                 rsp, keep = self.do_command(data)
                             else:
                                 rsp = self.do_data(data)
-                                if rsp == None:
+                                if rsp is None:
                                     continue
                             self.socket.send(rsp + "\r\n")
                             if keep == 0:
@@ -171,28 +178,28 @@ class SMTPServerEngine:
             keep = 0
         elif cmd == "MAIL":
             if self.state != SMTPServerEngine.ST_HELO:
-                return ("503 Bad command sequence", 1)
+                return "503 Bad command sequence", 1
             self.state = SMTPServerEngine.ST_MAIL
             rv = self.impl.mail_from(data[5:])
         elif cmd == "RCPT":
             if (self.state != SMTPServerEngine.ST_MAIL) and \
                (self.state != SMTPServerEngine.ST_RCPT):
-                return ("503 Bad command sequence", 1)
+                return "503 Bad command sequence", 1
             self.state = SMTPServerEngine.ST_RCPT
             rv = self.impl.rcpt_to(data[5:])
         elif cmd == "DATA":
             if self.state != SMTPServerEngine.ST_RCPT:
-                return ("503 Bad command sequence", 1)
+                return "503 Bad command sequence", 1
             self.state = SMTPServerEngine.ST_DATA
             self.data_accum = ""
-            return ("354 OK, Enter data, terminated with a \\r\\n.\\r\\n", 1)
+            return "354 OK, Enter data, terminated with a \\r\\n.\\r\\n", 1
         else:
-            return ("505 Eh? WTF was that?", 1)
+            return "505 Eh? WTF was that?", 1
 
         if rv:
-            return (rv, keep)
+            return rv, keep
         else:
-            return("250 OK", keep)
+            return "250 OK", keep
 
     def do_data(self, data):
         """
@@ -227,7 +234,7 @@ class SMTPServer:
         self._socket_service = None
 
     def serve(self, impl):
-        while ( self._resume ):
+        while self._resume:
             try:
                 nsd = self._socket.accept()
             except socket.error:
@@ -273,11 +280,11 @@ class SMTPServerStore(SMTPServerInterfac
 
     def mail_from(self, args):
         if args.lower().startswith('from:'):
-            self.sender = strip_address(args[5:].replace('\r\n','').strip())
+            self.sender = strip_address(args[5:].replace('\r\n', '').strip())
 
     def rcpt_to(self, args):
         if args.lower().startswith('to:'):
-            rcpt = args[3:].replace('\r\n','').strip()
+            rcpt = args[3:].replace('\r\n', '').strip()
             self.recipients.append(strip_address(rcpt))
 
     def data(self, args):
@@ -300,12 +307,12 @@ class SMTPThreadedServer(threading.Threa
     def __init__(self, port):
         self.port = port
         self.server = SMTPServer(port)
-        self.store  = SMTPServerStore()
+        self.store = SMTPServerStore()
         threading.Thread.__init__(self)
 
     def run(self):
         # run from within the SMTP server thread
-        self.server.serve(impl = self.store)
+        self.server.serve(impl=self.store)
 
     def start(self):
         # run from the main thread
@@ -356,19 +363,19 @@ def decode_header(header):
     # header does not seem to be MIME-encoded
     if not mo:
         return header
-    # attempts to decode the hedear,
-    # following the specified MIME endoding and charset
+    # attempts to decode the header,
+    # following the specified MIME encoding and charset
     try:
         encoding = mo.group('code').lower()
-        if encoding  == 'q':
+        if encoding == 'q':
             val = quopri.decodestring(mo.group('value'), header=True)
         elif encoding == 'b':
             val = base64.decodestring(mo.group('value'))
         else:
-            raise AssertionError, "unsupported encoding: %s" % encoding
+            raise AssertionError("unsupported encoding: %s" % encoding)
         header = unicode(val, mo.group('charset'))
     except Exception, e:
-        raise AssertionError, e
+        raise AssertionError(e)
     return header
 
 
@@ -384,19 +391,19 @@ def parse_smtp_message(msg):
     # last line does not contain the final line ending
     msg += '\r\n'
     for line in msg.splitlines(True):
-        if body != None:
+        if body is not None:
             # append current line to the body
             if line[-2] == CR:
                 body += line[0:-2]
                 body += '\n'
             else:
-                raise AssertionError, "body misses CRLF: %s (0x%x)" \
-                                      % (line, ord(line[-1]))
+                raise AssertionError("body misses CRLF: %s (0x%x)"
+                                     % (line, ord(line[-1])))
         else:
             if line[-2] != CR:
                 # RFC822 requires CRLF at end of field line
-                raise AssertionError, "header field misses CRLF: %s (0x%x)" \
-                                      % (line, ord(line[-1]))
+                raise AssertionError("header field misses CRLF: %s (0x%x)"
+                                     % (line, ord(line[-1])))
             # discards CR
             line = line[0:-2]
             if line.strip() == '':
@@ -405,11 +412,11 @@ def parse_smtp_message(msg):
             else:
                 val = None
                 if line[0] in ' \t':
-                    # continution of the previous line
+                    # continuation of the previous line
                     if not lh:
                         # unexpected multiline
-                        raise AssertionError, \
-                             "unexpected folded line: %s" % line
+                        raise AssertionError("unexpected folded line: %s"
+                                             % line)
                     val = decode_header(line.strip(' \t'))
                     # appends the current line to the previous one
                     if not isinstance(headers[lh], tuple):
@@ -420,14 +427,52 @@ def parse_smtp_message(msg):
                     # splits header name from value
                     (h, v) = line.split(':', 1)
                     val = decode_header(v.strip())
-                    if headers.has_key(h):
+                    if h in headers:
                         if isinstance(headers[h], tuple):
                             headers[h] += val
                         else:
                             headers[h] = (headers[h], val)
                     else:
                         headers[h] = val
-                    # stores the last header (for multilines headers)
+                    # stores the last header (for multi-line headers)
                     lh = h
     # returns the headers and the message body
-    return (headers, body)
+    return headers, body
+
+
+class SendmailEmailSenderTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.env = EnvironmentStub()
+
+    def test_sendmail_path_not_found_raises(self):
+        sender = SendmailEmailSender(self.env)
+        self.env.config.set('notification', 'sendmail_path',
+                            os.path.join(os.path.dirname(__file__),
+                                         'sendmail'))
+        self.assertRaises(ConfigurationError, sender.send,
+                          'admin@domain.com', ['foo@domain.com'], "")
+
+
+class SmtpEmailSenderTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.env = EnvironmentStub()
+
+    def test_smtp_server_not_found_raises(self):
+        sender = SmtpEmailSender(self.env)
+        self.env.config.set('notification', 'smtp_server', 'localhost')
+        self.env.config.set('notification', 'smtp_port', '65536')
+        self.assertRaises(ConfigurationError, sender.send,
+                          'admin@domain.com', ['foo@domain.com'], "")
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(SendmailEmailSenderTestCase))
+    suite.addTest(unittest.makeSuite(SmtpEmailSenderTestCase))
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='suite')

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/perm.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/perm.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/perm.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/perm.py Sat Nov 15 01:14:46 2014
@@ -1,15 +1,30 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2004-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
+import unittest
+
 from trac import perm
 from trac.core import *
+from trac.resource import Resource
 from trac.test import EnvironmentStub
 
-import unittest
-
 
 class DefaultPermissionStoreTestCase(unittest.TestCase):
 
     def setUp(self):
-        self.env = EnvironmentStub(enable=[perm.DefaultPermissionStore,
-                                           perm.DefaultPermissionGroupProvider])
+        self.env = \
+            EnvironmentStub(enable=[perm.DefaultPermissionStore,
+                                    perm.DefaultPermissionGroupProvider])
         self.store = perm.DefaultPermissionStore(self.env)
 
     def tearDown(self):
@@ -21,10 +36,10 @@ class DefaultPermissionStoreTestCase(uni
             [('john', 'WIKI_MODIFY'),
              ('john', 'REPORT_ADMIN'),
              ('kate', 'TICKET_CREATE')])
-        self.assertEquals(['REPORT_ADMIN', 'WIKI_MODIFY'],
-                          sorted(self.store.get_user_permissions('john')))
-        self.assertEquals(['TICKET_CREATE'],
-                          self.store.get_user_permissions('kate'))
+        self.assertEqual(['REPORT_ADMIN', 'WIKI_MODIFY'],
+                         sorted(self.store.get_user_permissions('john')))
+        self.assertEqual(['TICKET_CREATE'],
+                         self.store.get_user_permissions('kate'))
 
     def test_simple_group(self):
         self.env.db_transaction.executemany(
@@ -32,8 +47,8 @@ class DefaultPermissionStoreTestCase(uni
             [('dev', 'WIKI_MODIFY'),
              ('dev', 'REPORT_ADMIN'),
              ('john', 'dev')])
-        self.assertEquals(['REPORT_ADMIN', 'WIKI_MODIFY'],
-                          sorted(self.store.get_user_permissions('john')))
+        self.assertEqual(['REPORT_ADMIN', 'WIKI_MODIFY'],
+                         sorted(self.store.get_user_permissions('john')))
 
     def test_nested_groups(self):
         self.env.db_transaction.executemany(
@@ -42,8 +57,8 @@ class DefaultPermissionStoreTestCase(uni
              ('dev', 'REPORT_ADMIN'),
              ('admin', 'dev'),
              ('john', 'admin')])
-        self.assertEquals(['REPORT_ADMIN', 'WIKI_MODIFY'],
-                          sorted(self.store.get_user_permissions('john')))
+        self.assertEqual(['REPORT_ADMIN', 'WIKI_MODIFY'],
+                         sorted(self.store.get_user_permissions('john')))
 
     def test_mixed_case_group(self):
         self.env.db_transaction.executemany(
@@ -52,8 +67,8 @@ class DefaultPermissionStoreTestCase(uni
              ('Dev', 'REPORT_ADMIN'),
              ('Admin', 'Dev'),
              ('john', 'Admin')])
-        self.assertEquals(['REPORT_ADMIN', 'WIKI_MODIFY'],
-                          sorted(self.store.get_user_permissions('john')))
+        self.assertEqual(['REPORT_ADMIN', 'WIKI_MODIFY'],
+                         sorted(self.store.get_user_permissions('john')))
 
     def test_builtin_groups(self):
         self.env.db_transaction.executemany(
@@ -61,10 +76,10 @@ class DefaultPermissionStoreTestCase(uni
             [('authenticated', 'WIKI_MODIFY'),
              ('authenticated', 'REPORT_ADMIN'),
              ('anonymous', 'TICKET_CREATE')])
-        self.assertEquals(['REPORT_ADMIN', 'TICKET_CREATE', 'WIKI_MODIFY'],
-                          sorted(self.store.get_user_permissions('john')))
-        self.assertEquals(['TICKET_CREATE'],
-                          self.store.get_user_permissions('anonymous'))
+        self.assertEqual(['REPORT_ADMIN', 'TICKET_CREATE', 'WIKI_MODIFY'],
+                         sorted(self.store.get_user_permissions('john')))
+        self.assertEqual(['TICKET_CREATE'],
+                         self.store.get_user_permissions('anonymous'))
 
     def test_get_all_permissions(self):
         self.env.db_transaction.executemany(
@@ -76,7 +91,7 @@ class DefaultPermissionStoreTestCase(uni
                     ('dev', 'REPORT_ADMIN'),
                     ('john', 'dev')]
         for res in self.store.get_all_permissions():
-            self.failIf(res not in expected)
+            self.assertFalse(res not in expected)
 
 
 class TestPermissionRequestor(Component):
@@ -89,6 +104,48 @@ class TestPermissionRequestor(Component)
                 ('TEST_ADMIN', ['TEST_MODIFY'])]
 
 
+class PermissionErrorTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.env = EnvironmentStub()
+
+    def test_default_message(self):
+        permission_error = perm.PermissionError()
+        self.assertEqual(None, permission_error.action)
+        self.assertEqual(None, permission_error.resource)
+        self.assertEqual(None, permission_error.env)
+        self.assertEqual("Insufficient privileges to perform this operation.",
+                         unicode(permission_error))
+        self.assertEqual("Forbidden", permission_error.title)
+        self.assertEqual(unicode(permission_error), permission_error.msg)
+
+    def test_message_specified(self):
+        message = "The message."
+        permission_error = perm.PermissionError(msg=message)
+        self.assertEqual(message, unicode(permission_error))
+
+    def test_message_from_action(self):
+        action = 'WIKI_VIEW'
+        permission_error = perm.PermissionError(action)
+        self.assertEqual(action, permission_error.action)
+        self.assertEqual(None, permission_error.resource)
+        self.assertEqual(None, permission_error.env)
+        self.assertEqual("WIKI_VIEW privileges are required to perform this "
+                         "operation. You don't have the required "
+                         "permissions.", unicode(permission_error))
+
+    def test_message_from_action_and_resource(self):
+        action = 'WIKI_VIEW'
+        resource = Resource('wiki', 'WikiStart')
+        permission_error = perm.PermissionError(action, resource, self.env)
+        self.assertEqual(action, permission_error.action)
+        self.assertEqual(resource, permission_error.resource)
+        self.assertEqual(self.env, permission_error.env)
+        self.assertEqual("WIKI_VIEW privileges are required to perform this "
+                         "operation on WikiStart. You don't have the "
+                         "required permissions.", unicode(permission_error))
+
+
 class PermissionSystemTestCase(unittest.TestCase):
 
     def setUp(self):
@@ -130,7 +187,7 @@ class PermissionSystemTestCase(unittest.
         expected = [('bob', 'TEST_CREATE'),
                     ('jane', 'TEST_ADMIN')]
         for res in self.perm.get_all_permissions():
-            self.failIf(res not in expected)
+            self.assertFalse(res not in expected)
 
     def test_expand_actions_iter_7467(self):
         # Check that expand_actions works with iterators (#7467)
@@ -146,6 +203,8 @@ class PermissionCacheTestCase(unittest.T
         self.env = EnvironmentStub(enable=[perm.DefaultPermissionStore,
                                            perm.DefaultPermissionPolicy,
                                            TestPermissionRequestor])
+        self.env.config.set('trac', 'permission_policies',
+                            'DefaultPermissionPolicy')
         self.perm_system = perm.PermissionSystem(self.env)
         # by-pass DefaultPermissionPolicy cache:
         perm.DefaultPermissionPolicy.CACHE_EXPIRY = -1
@@ -157,19 +216,20 @@ class PermissionCacheTestCase(unittest.T
         self.env.reset_db()
 
     def test_contains(self):
-        self.assertEqual(True, 'TEST_MODIFY' in self.perm)
-        self.assertEqual(True, 'TEST_ADMIN' in self.perm)
-        self.assertEqual(False, 'TRAC_ADMIN' in self.perm)
+        self.assertTrue('TEST_MODIFY' in self.perm)
+        self.assertTrue('TEST_ADMIN' in self.perm)
+        self.assertFalse('TRAC_ADMIN' in self.perm)
 
     def test_has_permission(self):
-        self.assertEqual(True, self.perm.has_permission('TEST_MODIFY'))
-        self.assertEqual(True, self.perm.has_permission('TEST_ADMIN'))
-        self.assertEqual(False, self.perm.has_permission('TRAC_ADMIN'))
+        self.assertTrue(self.perm.has_permission('TEST_MODIFY'))
+        self.assertTrue(self.perm.has_permission('TEST_ADMIN'))
+        self.assertFalse(self.perm.has_permission('TRAC_ADMIN'))
 
     def test_require(self):
         self.perm.require('TEST_MODIFY')
         self.perm.require('TEST_ADMIN')
-        self.assertRaises(perm.PermissionError, self.perm.require, 'TRAC_ADMIN')
+        self.assertRaises(perm.PermissionError,
+                          self.perm.require, 'TRAC_ADMIN')
 
     def test_assert_permission(self):
         self.perm.assert_permission('TEST_MODIFY')
@@ -216,12 +276,14 @@ class TestPermissionPolicy(Component):
 
 
 class PermissionPolicyTestCase(unittest.TestCase):
+
     def setUp(self):
         self.env = EnvironmentStub(enable=[perm.DefaultPermissionStore,
                                            perm.DefaultPermissionPolicy,
                                            TestPermissionPolicy,
                                            TestPermissionRequestor])
-        self.env.config.set('trac', 'permission_policies', 'TestPermissionPolicy')
+        self.env.config.set('trac', 'permission_policies',
+                            'TestPermissionPolicy')
         self.policy = TestPermissionPolicy(self.env)
         self.perm = perm.PermissionCache(self.env, 'testuser')
 
@@ -246,7 +308,8 @@ class PermissionPolicyTestCase(unittest.
                           ('testuser', 'TEST_ADMIN'): True})
 
     def test_policy_chaining(self):
-        self.env.config.set('trac', 'permission_policies', 'TestPermissionPolicy,DefaultPermissionPolicy')
+        self.env.config.set('trac', 'permission_policies',
+                            'TestPermissionPolicy,DefaultPermissionPolicy')
         self.policy.grant('testuser', ['TEST_MODIFY'])
         system = perm.PermissionSystem(self.env)
         system.grant_permission('testuser', 'TEST_ADMIN')
@@ -259,13 +322,17 @@ class PermissionPolicyTestCase(unittest.
         self.assertEqual(self.policy.results,
                          {('testuser', 'TEST_MODIFY'): True,
                           ('testuser', 'TEST_ADMIN'): None})
+
+
 def suite():
     suite = unittest.TestSuite()
-    suite.addTest(unittest.makeSuite(DefaultPermissionStoreTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(PermissionSystemTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(PermissionCacheTestCase, 'test'))
-    suite.addTest(unittest.makeSuite(PermissionPolicyTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(DefaultPermissionStoreTestCase))
+    suite.addTest(unittest.makeSuite(PermissionErrorTestCase))
+    suite.addTest(unittest.makeSuite(PermissionSystemTestCase))
+    suite.addTest(unittest.makeSuite(PermissionCacheTestCase))
+    suite.addTest(unittest.makeSuite(PermissionPolicyTestCase))
     return suite
 
+
 if __name__ == '__main__':
-    unittest.main()
+    unittest.main(defaultTest='suite')

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/resource.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/resource.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/resource.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/resource.py Sat Nov 15 01:14:46 2014
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2007-2009 Edgewall Software
+# Copyright (C) 2007-2013 Edgewall Software
 # All rights reserved.
 #
 # This software is licensed as described in the file COPYING, which
@@ -165,7 +165,7 @@ class TestResourceChangeListener(Compone
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(doctest.DocTestSuite(resource))
-    suite.addTest(unittest.makeSuite(ResourceTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(ResourceTestCase))
     suite.addTest(unittest.makeSuite(NeighborhoodTestCase, 'test'))
     return suite
 

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/wikisyntax.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/wikisyntax.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/wikisyntax.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/tests/wikisyntax.py Sat Nov 15 01:14:46 2014
@@ -1,4 +1,18 @@
-import os
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2006-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
+from __future__ import with_statement
+
 import shutil
 import tempfile
 import unittest
@@ -11,6 +25,7 @@ from trac.test import MockPerm
 from trac.web.href import Href
 from trac.wiki.tests import formatter
 
+
 SEARCH_TEST_CASES = u"""
 ============================== search: link resolver
 search:foo
@@ -116,12 +131,14 @@ attachment:file.txt?format=raw
 def attachment_setup(tc):
     import trac.ticket.api
     import trac.wiki.api
-    tc.env.path = os.path.join(tempfile.gettempdir(), 'trac-tempenv')
-    os.mkdir(tc.env.path)
-    attachment = Attachment(tc.env, 'wiki', 'WikiStart')
-    attachment.insert('file.txt', tempfile.TemporaryFile(), 0)
+    tc.env.path = tempfile.mkdtemp(prefix='trac-tempenv-')
+    with tc.env.db_transaction as db:
+        db("INSERT INTO wiki (name,version) VALUES ('SomePage/SubPage',1)")
+        db("INSERT INTO ticket (id) VALUES (123)")
     attachment = Attachment(tc.env, 'ticket', 123)
     attachment.insert('file.txt', tempfile.TemporaryFile(), 0)
+    attachment = Attachment(tc.env, 'wiki', 'WikiStart')
+    attachment.insert('file.txt', tempfile.TemporaryFile(), 0)
     attachment = Attachment(tc.env, 'wiki', 'SomePage/SubPage')
     attachment.insert('foo.txt', tempfile.TemporaryFile(), 0)
 
@@ -188,4 +205,3 @@ def suite():
 
 if __name__ == '__main__':
     unittest.main(defaultTest='suite')
-

Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/ticket/__init__.py
URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/ticket/__init__.py?rev=1639823&r1=1639822&r2=1639823&view=diff
==============================================================================
--- bloodhound/branches/trac-1.0.2-integration/trac/trac/ticket/__init__.py (original)
+++ bloodhound/branches/trac-1.0.2-integration/trac/trac/ticket/__init__.py Sat Nov 15 01:14:46 2014
@@ -1,3 +1,16 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2005-2013 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
 from trac.ticket.api import *
 from trac.ticket.default_workflow import *
 from trac.ticket.model import *