class HdfdumpTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.req = MockRequest(self.env, args={'hdfdump': '1'}) self.env.clear_component_registry() self.request_dispatcher = RequestDispatcher(self.env) perm = self.req.perm self.request_dispatcher._get_perm = lambda req: perm def tearDown(self): self.env.restore_component_registry() def test_hdfdump(self): class HdfdumpRequestHandler(Component): implements(IRequestHandler) def match_request(self, req): return True def process_request(self, req): data = {'name': 'value'} return 'error.html', data, None self.env.config.set('trac', 'default_handler', 'HdfdumpRequestHandler') self.assertRaises(RequestDone, self.request_dispatcher.dispatch, self.req) self.assertIn("{'name': 'value'}\n", self.req.response_sent.getvalue()) self.assertEqual('text/plain;charset=utf-8', self.req.headers_sent['Content-Type'])
class TracAdminHelpMacroTestCase(TracAdminTestCaseBase): def setUp(self): self.env = EnvironmentStub( enable=['%s.UnicodeHelpCommand' % self.__module__]) self.env.clear_component_registry() def tearDown(self): self.env.restore_component_registry() self.env.reset_db() def test_unicode_help(self): unicode_help = u'Hélp text with unicöde charàcters' class UnicodeHelpCommand(Component): implements(IAdminCommandProvider) def get_admin_commands(self): yield ('unicode-help', '', unicode_help, None, self._cmd) def _cmd(self): pass macro = TracAdminHelpMacro(self.env) help = unicode(macro.expand_macro(None, None, 'unicode-help')) self.assertIn(unicode_help, help) def test_invalid_command(self): macro = TracAdminHelpMacro(self.env) try: macro.expand_macro(None, None, 'copystatic') self.fail("MacroError not raised") except MacroError as e: self.assertEqual('Unknown trac-admin command "copystatic"', unicode(e))
class ProcessRequestTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.config.set('trac', 'default_handler', 'DefaultHandler') self.env.clear_component_registry() class DefaultHandler(Component): implements(IRequestHandler) def match_request(self, req): return True def process_request(self, req): raise req.exc_class("Raised in process_request") def tearDown(self): self.env.restore_component_registry() def test_permission_error_raises_http_forbidden(self): """TracError in process_request is trapped and an HTTPForbidden error is raised. """ req = MockRequest(self.env) req.exc_class = PermissionError try: RequestDispatcher(self.env).dispatch(req) except HTTPForbidden, e: self.assertEqual( "403 Forbidden (Raised in process_request " "privileges are required to perform this operation. You " "don't have the required permissions.)", unicode(e)) else:
class PreProcessRequestTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.config.set('trac', 'default_handler', 'DefaultHandler') self.env.clear_component_registry() class DefaultHandler(Component): implements(IRequestHandler) def match_request(self, req): return True def process_request(self, req): pass def tearDown(self): self.env.restore_component_registry() def test_trac_error_raises_http_internal_server_error(self): """TracError in pre_process_request is trapped and an HTTPInternalServerError is raised. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, req, handler): raise TracError("Raised in pre_process_request") def post_process_request(self, req, template, data, content_type): return template, data, content_type req = MockRequest(self.env) try: RequestDispatcher(self.env).dispatch(req) except HTTPInternalServerError as e: self.assertEqual("500 Trac Error (Raised in pre_process_request)", unicode(e)) else: self.fail("HTTPInternalServerError not raised")
class SystemInfoProviderTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.clear_component_registry() class SystemInfoProvider1(Component): implements(ISystemInfoProvider) def get_system_info(self): yield 'pkg1', 1.0 yield 'pkg2', 2.0 class SystemInfoProvider2(Component): implements(ISystemInfoProvider) def get_system_info(self): yield 'pkg1', 1.0 self.env.enable_component(SystemInfoProvider1) self.env.enable_component(SystemInfoProvider2) def tearDown(self): self.env.restore_component_registry() def test_system_info_property(self): """The system_info property returns a list of all tuples generated by ISystemInfoProvider implementations. """ system_info = self.env.system_info self.assertEqual(system_info, self.env.get_systeminfo()) self.assertEqual(2, len(system_info)) self.assertIn(('pkg1', 1.0), system_info) self.assertIn(('pkg2', 2.0), system_info) def test_duplicate_entries_are_removed(self): """Duplicate entries are removed.""" system_info = self.env.system_info self.assertIn(('pkg1', 1.0), system_info) self.assertEqual(len(system_info), len(set(system_info)))
class HdfdumpTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.request_dispatcher = RequestDispatcher(self.env) self.req = Mock(chrome={'warnings': []}, method='GET', perm=MockPerm(), args={'hdfdump': '1'}, session={}, callbacks={}, send=self._req_send) self.content = None self.content_type = None self.env.clear_component_registry() def tearDown(self): self.env.restore_component_registry() def _req_send(self, content, content_type='text/html'): self.content = content self.content_type = content_type raise RequestDone() def test_hdfdump(self): class HdfdumpRequestHandler(Component): implements(IRequestHandler) def match_request(self, req): return True def process_request(self, req): data = {'name': 'value'} return 'error.html', data, None self.env.config.set('trac', 'default_handler', 'HdfdumpRequestHandler') self.assertRaises(RequestDone, self.request_dispatcher.dispatch, self.req) self.assertEqual("{'name': 'value'}\n", self.content) self.assertEqual('text/plain', self.content_type)
class RepositoryAdminPanelTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.clear_component_registry() def tearDown(self): self.env.restore_component_registry() self.env.reset_db() def test_panel_not_exists_when_no_repository_connectors(self): """Repositories admin panel is not present when there are no repository connectors enabled. """ req = MockRequest(self.env) rap = RepositoryAdminPanel(self.env) panels = [panel for panel in rap.get_admin_panels(req)] self.assertEqual(0, len(panels)) def test_panel_exists_when_repository_connectors(self): """Repositories admin panel is present when there are repository connectors enabled. """ class RepositoryConnector(Component): implements(IRepositoryConnector) def get_supported_types(self): yield 'RepositoryConnector', 1 def get_repository(self, repos_type, repos_dir, params): pass req = MockRequest(self.env) rap = RepositoryAdminPanel(self.env) panels = [panel for panel in rap.get_admin_panels(req)] self.assertEqual(1, len(panels))
class AuthenticateTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(disable=['trac.web.auth.LoginModule']) self.request_dispatcher = RequestDispatcher(self.env) self.req = MockRequest(self.env) self.env.clear_component_registry() def tearDown(self): self.env.restore_component_registry() def test_authenticate_returns_first_successful(self): class SuccessfulAuthenticator1(Component): implements(IAuthenticator) def authenticate(self, req): return 'user1' class SuccessfulAuthenticator2(Component): implements(IAuthenticator) def authenticate(self, req): return 'user2' self.assertEqual(2, len(self.request_dispatcher.authenticators)) self.assertIsInstance(self.request_dispatcher.authenticators[0], SuccessfulAuthenticator1) self.assertIsInstance(self.request_dispatcher.authenticators[1], SuccessfulAuthenticator2) self.assertEqual('user1', self.request_dispatcher.authenticate(self.req)) def test_authenticate_skips_unsuccessful(self): class UnsuccessfulAuthenticator(Component): implements(IAuthenticator) def authenticate(self, req): return None class SuccessfulAuthenticator(Component): implements(IAuthenticator) def authenticate(self, req): return 'user' self.assertEqual(2, len(self.request_dispatcher.authenticators)) self.assertIsInstance(self.request_dispatcher.authenticators[0], UnsuccessfulAuthenticator) self.assertIsInstance(self.request_dispatcher.authenticators[1], SuccessfulAuthenticator) self.assertEqual('user', self.request_dispatcher.authenticate(self.req)) def test_authenticate_raises(self): class RaisingAuthenticator(Component): implements(IAuthenticator) def authenticate(self, req): raise TracError("Bad attempt") class SuccessfulAuthenticator(Component): implements(IAuthenticator) def authenticate(self, req): return 'user' self.assertEqual(2, len(self.request_dispatcher.authenticators)) self.assertIsInstance(self.request_dispatcher.authenticators[0], RaisingAuthenticator) self.assertIsInstance(self.request_dispatcher.authenticators[1], SuccessfulAuthenticator) self.assertEqual('anonymous', self.request_dispatcher.authenticate(self.req)) self.assertEqual(1, len(self.req.chrome['warnings'])) expected = "Can't authenticate using RaisingAuthenticator: " for level, message in self.env.log_messages: if expected in message.split('\n'): self.assertEqual('ERROR', level) break else: self.fail("Expected log message not found: \"%s\"" % expected) def test_authenticate_once(self): class Authenticator(Component): implements(IAuthenticator) def authenticate(self, req): authenticated[0] += 1 return 'admin' class AuthenticateRequestHandler(Component): implements(IRequestHandler) def match_request(self, req): return bool(req.perm) def process_request(self, req): req.authname req.send('') self.env.config.set('trac', 'default_handler', 'AuthenticateRequestHandler') authenticated = [0] req = MockRequest(self.env) self.assertEqual(1, len(self.request_dispatcher.authenticators)) self.assertIsInstance(self.request_dispatcher.authenticators[0], Authenticator) self.assertRaises(RequestDone, self.request_dispatcher.dispatch, req) self.assertEqual(1, authenticated[0])
class PostProcessRequestTestCase(unittest.TestCase): """Test cases for handling of the optional `method` argument in RequestDispatcher._post_process_request.""" def setUp(self): self.env = EnvironmentStub() self.req = MockRequest(self.env) self.request_dispatcher = RequestDispatcher(self.env) self.compmgr = ComponentManager() self.env.clear_component_registry() def tearDown(self): self.env.restore_component_registry() def test_no_request_filters_request_handler_returns_method_false(self): """IRequestHandler doesn't return `method` and no IRequestFilters are registered. The `method` is set to `None`. """ args = ('template.html', {}, 'text/html') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(0, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args + (None, ), resp) def test_no_request_filters_request_handler_returns_method_true(self): """IRequestHandler returns `method` and no IRequestFilters are registered. The `method` is forwarded. """ args = ('template.html', {}, 'text/html', 'xhtml') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(0, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args, resp) def test_4arg_post_process_request_request_handler_returns_method_false( self): """IRequestHandler doesn't return `method` and IRequestFilter doesn't accept `method` as an argument. The `method` is set to `None`. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, handler): return handler def post_process_request(self, req, template, data, content_type): return template, data, content_type args = ('template.html', {}, 'text/html') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args + (None, ), resp) def test_4arg_post_process_request_request_handler_returns_method_true( self): """IRequestHandler returns `method` and IRequestFilter doesn't accept the argument. The `method` argument is forwarded over IRequestFilter implementations that don't accept the argument. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, handler): return handler def post_process_request(self, req, template, data, content_type): return template, data, content_type args = ('template.html', {}, 'text/html', 'xhtml') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args, resp) def test_5arg_post_process_request_request_handler_returns_method_false( self): """IRequestHandler doesn't return `method` and IRequestFilter accepts `method` as an argument. The `method` is set to `None`. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, handler): return handler def post_process_request(self, req, template, data, content_type, method=None): return template, data, content_type, method args = ('template.html', {}, 'text/html') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args[:3] + (None, ), resp) def test_5arg_post_process_request_request_handler_returns_method_true( self): """IRequestHandler returns `method` and IRequestFilter accepts the argument. The `method` argument is passed through IRequestFilter implementations. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, handler): return handler def post_process_request(self, req, template, data, content_type, method=None): return template, data, content_type, method args = ('template.html', {}, 'text/html', 'xhtml') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args, resp) def test_5arg_post_process_request_request_handler_adds_method(self): """IRequestFilter adds `method` not returned by IRequestHandler. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, handler): return handler def post_process_request(self, req, template, data, content_type, method=None): return template, data, content_type, 'xml' args = ('template.html', {}, 'text/html') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args[:3] + ('xml', ), resp) def test_5arg_post_process_request_request_handler_modifies_method(self): """IRequestFilter modifies `method` returned by IRequestHandler. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, handler): return handler def post_process_request(self, req, template, data, content_type, method=None): return template, data, content_type, 'xml' args = ('template.html', {}, 'text/html', 'xhtml') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args[:3] + ('xml', ), resp)
class ProcessRequestTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.config.set('trac', 'default_handler', 'DefaultHandler') self.env.clear_component_registry() class DefaultHandler(Component): implements(IRequestHandler) def match_request(self, req): return True def process_request(self, req): raise req.exc_class("Raised in process_request") def tearDown(self): self.env.restore_component_registry() def test_permission_error_raises_http_forbidden(self): """TracError in process_request is trapped and an HTTPForbidden error is raised. """ req = MockRequest(self.env) req.exc_class = PermissionError try: RequestDispatcher(self.env).dispatch(req) except HTTPForbidden as e: self.assertEqual( "403 Forbidden (Raised in process_request " "privileges are required to perform this operation. You " "don't have the required permissions.)", unicode(e)) else: self.fail("HTTPForbidden not raised") def test_resource_not_found_raises_http_not_found(self): """ResourceNotFound error in process_request is trapped and an HTTPNotFound error is raised. """ req = MockRequest(self.env) req.exc_class = ResourceNotFound try: RequestDispatcher(self.env).dispatch(req) except HTTPNotFound as e: self.assertEqual("404 Trac Error (Raised in process_request)", unicode(e)) else: self.fail("HTTPNotFound not raised") def test_trac_error_raises_http_internal_server_error(self): """TracError in process_request is trapped and an HTTPInternalServerError is raised. """ req = MockRequest(self.env) req.exc_class = TracError try: RequestDispatcher(self.env).dispatch(req) except HTTPInternalServerError as e: self.assertEqual("500 Trac Error (Raised in process_request)", unicode(e)) else: self.fail("HTTPInternalServerError not raised") def test_not_implemented_error_raises_http_internal_server_error(self): """NotImplementedError in process_request is trapped and an HTTPInternalServerError is raised. """ req = MockRequest(self.env) req.exc_class = NotImplementedError try: RequestDispatcher(self.env).dispatch(req) except HTTPInternalServerError as e: self.assertEqual( "500 Not Implemented Error (Raised in " "process_request)", unicode(e)) else: self.fail("HTTPInternalServerError not raised")
class PostProcessRequestTestCase(unittest.TestCase): """Test cases for handling of the optional `method` argument in RequestDispatcher._post_process_request.""" def setUp(self): self.env = EnvironmentStub() self.req = MockRequest(self.env) self.request_dispatcher = RequestDispatcher(self.env) self.compmgr = ComponentManager() self.env.clear_component_registry() def tearDown(self): self.env.restore_component_registry() def test_no_request_filters_request_handler_returns_method_false(self): """IRequestHandler doesn't return `method` and no IRequestFilters are registered. The `method` is set to `None`. """ args = ('template.html', {}, 'text/html') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(0, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args + (None, ), resp) def test_no_request_filters_request_handler_returns_method_true(self): """IRequestHandler returns `method` and no IRequestFilters are registered. The `method` is forwarded. """ args = ('template.html', {}, 'text/html', 'xhtml') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(0, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args, resp) def test_4arg_post_process_request_request_handler_returns_method_false( self): """IRequestHandler doesn't return `method` and IRequestFilter doesn't accept `method` as an argument. The `method` is set to `None`. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type): return template, data, content_type args = ('template.html', {}, 'text/html') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args + (None, ), resp) def test_4arg_post_process_request_request_handler_returns_method_true( self): """IRequestHandler returns `method` and IRequestFilter doesn't accept the argument. The `method` argument is forwarded over IRequestFilter implementations that don't accept the argument. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type): return template, data, content_type args = ('template.html', {}, 'text/html', 'xhtml') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args, resp) def test_5arg_post_process_request_request_handler_returns_method_false( self): """IRequestHandler doesn't return `method` and IRequestFilter accepts `method` as an argument. The `method` is set to `None`. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type, method=None): return template, data, content_type, method args = ('template.html', {}, 'text/html') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args[:3] + (None, ), resp) def test_5arg_post_process_request_request_handler_returns_method_true( self): """IRequestHandler returns `method` and IRequestFilter accepts the argument. The `method` argument is passed through IRequestFilter implementations. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type, method=None): return template, data, content_type, method args = ('template.html', {}, 'text/html', 'xhtml') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args, resp) def test_5arg_post_process_request_request_handler_adds_method(self): """IRequestFilter adds `method` not returned by IRequestHandler. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type, method=None): return template, data, content_type, 'xml' args = ('template.html', {}, 'text/html') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args[:3] + ('xml', ), resp) def test_5arg_post_process_request_request_handler_modifies_method(self): """IRequestFilter modifies `method` returned by IRequestHandler. """ class RequestFilter(Component): implements(IRequestFilter) def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type, method=None): return template, data, content_type, 'xml' args = ('template.html', {}, 'text/html', 'xhtml') resp = self.request_dispatcher._post_process_request(self.req, *args) self.assertEqual(1, len(self.request_dispatcher.filters)) self.assertEqual(4, len(resp)) self.assertEqual(args[:3] + ('xml', ), resp) def test_redirect_on_permission_error(self): """The post_process_request method can redirect during exception handling from an exception raised in process_request. """ class RedirectOnPermissionErrorStub(Component): implements(IRequestHandler, IRequestFilter) def match_request(self, req): return re.match(r'/perm-error', req.path_info) def process_request(self, req): req.entered_process_request = True raise PermissionError("No permission to view") def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type): if (template, data, content_type) == (None, None, None): req.entered_post_process_request = True req.redirect(req.href('/redirect-target')) return template, data, content_type dispatcher = RequestDispatcher(self.env) req = MockRequest(self.env, method='GET', path_info='/perm-error') req.entered_process_request = False req.entered_post_process_request = False try: dispatcher.dispatch(req) except RequestDone: pass else: self.fail("RequestDone not raised") self.assertTrue(req.entered_process_request) self.assertTrue(req.entered_post_process_request)
class NavigationOrderTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.clear_component_registry() self.req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='/', add_redirect_listener=lambda listener: None) self.chrome = Chrome(self.env) class TestNavigationContributor1(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'metanav', 'test1', 'Test 1' class TestNavigationContributor2(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'metanav', 'test2', 'Test 2' def tearDown(self): self.env.restore_component_registry() def test_explicit_ordering(self): """Ordering is explicitly specified.""" self.env.config.set('metanav', 'test1.order', 2) self.env.config.set('metanav', 'test2.order', 1) items = self.chrome.prepare_request(self.req)['nav']['metanav'] self.assertEqual('test2', items[0]['name']) self.assertEqual('test1', items[1]['name']) def test_partial_explicit_ordering_1(self): """Ordering for one item is explicitly specified.""" self.env.config.set('metanav', 'test1.order', 1) items = self.chrome.prepare_request(self.req)['nav']['metanav'] self.assertEqual('test1', items[0]['name']) self.assertEqual('test2', items[1]['name']) def test_partial_explicit_ordering_2(self): """Ordering for one item is explicitly specified.""" self.env.config.set('metanav', 'test2.order', 1) items = self.chrome.prepare_request(self.req)['nav']['metanav'] self.assertEqual('test2', items[0]['name']) self.assertEqual('test1', items[1]['name']) def test_implicit_ordering(self): """When not specified, ordering is alphabetical.""" self.env.config.set('metanav', 'foo.order', 1) self.env.config.set('metanav', 'bar.order', 2) items = self.chrome.prepare_request(self.req)['nav']['metanav'] self.assertEqual('test1', items[0]['name']) self.assertEqual('test2', items[1]['name'])
class ChromeTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.clear_component_registry() def tearDown(self): self.env.restore_component_registry() def _get_navigation_item(self, items, name): for item in items: if item['name'] == name: return item return {} def test_add_meta(self): req = Request(href=Href('/trac.cgi')) add_meta(req, 'Jim Smith', name='Author', scheme='test', lang='en-us') add_meta(req, 'Tue, 20 Aug 1996 14:25:27 GMT', http_equiv='Expires') metas = req.chrome['metas'] self.assertEqual(2, len(metas)) meta = metas[0] self.assertEqual('Jim Smith', meta['content']) self.assertEqual('Author', meta['name']) self.assertEqual('test', meta['scheme']) self.assertEqual('en-us', meta['lang']) self.assertEqual('en-us', meta['xml:lang']) meta = metas[1] self.assertEqual('Tue, 20 Aug 1996 14:25:27 GMT', meta['content']) self.assertEqual('Expires', meta['http-equiv']) def test_add_link_simple(self): req = Request(href=Href('/trac.cgi')) add_link(req, 'start', '/trac/wiki') self.assertEqual('/trac/wiki', req.chrome['links']['start'][0]['href']) def test_add_link_advanced(self): req = Request(href=Href('/trac.cgi')) add_link(req, 'start', '/trac/wiki', 'Start page', 'text/html', 'home') link = req.chrome['links']['start'][0] self.assertEqual('/trac/wiki', link['href']) self.assertEqual('Start page', link['title']) self.assertEqual('text/html', link['type']) self.assertEqual('home', link['class']) def test_add_script(self): req = Request(base_path='/trac.cgi', href=Href('/trac.cgi')) add_script(req, 'common/js/trac.js') add_script(req, 'common/js/trac.js') add_script(req, 'http://example.com/trac.js') add_script(req, '//example.com/trac.js') add_script(req, '/dynamic.js') add_script(req, 'plugin/js/plugin.js') scripts = req.chrome['scripts'] self.assertEqual(5, len(scripts)) self.assertEqual('text/javascript', scripts[0]['type']) self.assertEqual('/trac.cgi/chrome/common/js/trac.js', scripts[0]['href']) self.assertEqual('text/javascript', scripts[1]['type']) self.assertEqual('http://example.com/trac.js', scripts[1]['href']) self.assertEqual('text/javascript', scripts[2]['type']) self.assertEqual('//example.com/trac.js', scripts[2]['href']) self.assertEqual('/trac.cgi/dynamic.js', scripts[3]['href']) self.assertEqual('/trac.cgi/chrome/plugin/js/plugin.js', scripts[4]['href']) def test_add_script_data(self): req = Request(href=Href('/trac.cgi')) add_script_data(req, {'var1': 1, 'var2': 'Testing'}) add_script_data(req, var2='More testing', var3=3) self.assertEqual({ 'var1': 1, 'var2': 'More testing', 'var3': 3 }, req.chrome['script_data']) def test_add_stylesheet(self): req = Request(base_path='/trac.cgi', href=Href('/trac.cgi')) add_stylesheet(req, 'common/css/trac.css') add_stylesheet(req, 'common/css/trac.css') add_stylesheet(req, 'https://example.com/trac.css') add_stylesheet(req, '//example.com/trac.css') add_stylesheet(req, '/dynamic.css') add_stylesheet(req, 'plugin/css/plugin.css') links = req.chrome['links']['stylesheet'] self.assertEqual(5, len(links)) self.assertEqual('text/css', links[0]['type']) self.assertEqual('/trac.cgi/chrome/common/css/trac.css', links[0]['href']) self.assertEqual('text/css', links[1]['type']) self.assertEqual('https://example.com/trac.css', links[1]['href']) self.assertEqual('text/css', links[2]['type']) self.assertEqual('//example.com/trac.css', links[2]['href']) self.assertEqual('/trac.cgi/dynamic.css', links[3]['href']) self.assertEqual('/trac.cgi/chrome/plugin/css/plugin.css', links[4]['href']) def test_add_stylesheet_media(self): req = Request(base_path='/trac.cgi', href=Href('/trac.cgi')) add_stylesheet(req, 'foo.css', media='print') links = req.chrome['links']['stylesheet'] self.assertEqual(1, len(links)) self.assertEqual('print', links[0]['media']) def test_add_warning_is_unique(self): req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', add_redirect_listener=lambda listener: None) Chrome(self.env).prepare_request(req) message = random_sentence(5) add_warning(req, message) add_warning(req, message) self.assertEqual(1, len(req.chrome['warnings'])) def test_add_notice_is_unique(self): req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', add_redirect_listener=lambda listener: None) Chrome(self.env).prepare_request(req) message = random_sentence(5) add_notice(req, message) add_notice(req, message) self.assertEqual(1, len(req.chrome['notices'])) def _test_add_message_escapes_markup(self, msgtype, add_fn): req = Request(chrome={msgtype: []}) add_fn(req, 'Message with an "&"') add_fn(req, Exception("Exception message with an &")) add_fn(req, tag("Message with text ", tag.b("& markup"))) add_fn(req, Markup("Markup <strong>message</strong>.")) messages = req.chrome[msgtype] self.assertIn('Message with an "&"', messages) self.assertIn("Exception message with an &", messages) self.assertIn("Message with text <b>& markup</b>", messages) self.assertIn("Markup <strong>message</strong>.", messages) def test_add_warning_escapes_markup(self): """Message text is escaped. Regression test for http://trac.edgewall.org/ticket/12285 """ self._test_add_message_escapes_markup('warnings', add_warning) def test_add_notice_escapes_markup(self): """Message text is escaped. Regression test for http://trac.edgewall.org/ticket/12285 """ self._test_add_message_escapes_markup('notices', add_notice) def test_htdocs_location(self): req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', add_redirect_listener=lambda listener: None) info = Chrome(self.env).prepare_request(req) self.assertEqual('/trac.cgi/chrome/common/', info['htdocs_location']) def test_logo(self): req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', add_redirect_listener=lambda listener: None) # Verify that no logo data is put in the HDF if no logo is configured self.env.config.set('header_logo', 'src', '') info = Chrome(self.env).prepare_request(req) self.assertNotIn('src', info['logo']) self.assertNotIn('src_abs', info['logo']) # Test with a relative path to the logo image self.env.config.set('header_logo', 'src', 'foo.png') info = Chrome(self.env).prepare_request(req) self.assertEqual('/trac.cgi/chrome/common/foo.png', info['logo']['src']) self.assertEqual('http://example.org/trac.cgi/chrome/common/foo.png', info['logo']['src_abs']) # Test with a location in project htdocs self.env.config.set('header_logo', 'src', 'site/foo.png') info = Chrome(self.env).prepare_request(req) self.assertEqual('/trac.cgi/chrome/site/foo.png', info['logo']['src']) self.assertEqual('http://example.org/trac.cgi/chrome/site/foo.png', info['logo']['src_abs']) # Test with a server-relative path to the logo image self.env.config.set('header_logo', 'src', '/img/foo.png') info = Chrome(self.env).prepare_request(req) self.assertEqual('/img/foo.png', info['logo']['src']) self.assertEqual('/img/foo.png', info['logo']['src_abs']) # Test with an absolute path to the logo image self.env.config.set('header_logo', 'src', 'http://www.example.org/foo.png') info = Chrome(self.env).prepare_request(req) self.assertEqual('http://www.example.org/foo.png', info['logo']['src']) self.assertEqual('http://www.example.org/foo.png', info['logo']['src_abs']) def test_default_links(self): req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', add_redirect_listener=lambda listener: None) links = Chrome(self.env).prepare_request(req)['links'] self.assertEqual('/trac.cgi/wiki', links['start'][0]['href']) self.assertEqual('/trac.cgi/search', links['search'][0]['href']) self.assertEqual('/trac.cgi/wiki/TracGuide', links['help'][0]['href']) self.assertEqual('/trac.cgi/chrome/common/css/trac.css', links['stylesheet'][0]['href']) def test_icon_links(self): req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', add_redirect_listener=lambda listener: None) chrome = Chrome(self.env) # No icon set in config, so no icon links self.env.config.set('project', 'icon', '') links = chrome.prepare_request(req)['links'] self.assertNotIn('icon', links) self.assertNotIn('shortcut icon', links) # Relative URL for icon config option self.env.config.set('project', 'icon', 'foo.ico') links = chrome.prepare_request(req)['links'] self.assertEqual('/trac.cgi/chrome/common/foo.ico', links['icon'][0]['href']) self.assertNotIn('shortcut icon', links) # URL relative to the server root for icon config option self.env.config.set('project', 'icon', '/favicon.ico') links = chrome.prepare_request(req)['links'] self.assertEqual('/favicon.ico', links['icon'][0]['href']) self.assertNotIn('shortcut icon', links) # Absolute URL for icon config option self.env.config.set('project', 'icon', 'http://example.com/favicon.ico') links = chrome.prepare_request(req)['links'] self.assertEqual('http://example.com/favicon.ico', links['icon'][0]['href']) self.assertNotIn('shortcut icon', links) def test_nav_contributor(self): class TestNavigationContributor(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'metanav', 'test', 'Test' req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), path_info='/', base_path='/trac.cgi', add_redirect_listener=lambda listener: None) nav = Chrome(self.env).prepare_request(req)['nav'] self.assertEqual({ 'name': 'test', 'label': 'Test', 'active': False }, nav['metanav'][0]) def test_nav_contributor_active(self): class TestNavigationContributor(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return 'test' def get_navigation_items(self, req): yield 'metanav', 'test', 'Test' req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), path_info='/', base_path='/trac.cgi', add_redirect_listener=lambda listener: None) handler = TestNavigationContributor(self.env) nav = Chrome(self.env).prepare_request(req, handler)['nav'] self.assertEqual({ 'name': 'test', 'label': 'Test', 'active': True }, nav['metanav'][0]) def _get_jquery_ui_script_data(self, lc_time): req = Request(href=Href('/trac.cgi'), tz=utc, lc_time=lc_time) Chrome(self.env).add_jquery_ui(req) return req.chrome['script_data']['jquery_ui'] def test_add_jquery_ui_is_iso8601(self): data = self._get_jquery_ui_script_data('iso8601') self.assertIn({'value': -60, 'label': '-01:00'}, data['timezone_list']) self.assertIn({'value': 0, 'label': '+00:00'}, data['timezone_list']) self.assertIn({'value': 60, 'label': '+01:00'}, data['timezone_list']) def test_add_jquery_ui_default_format(self): data = self._get_jquery_ui_script_data(locale_en) self.assertIsNone(data['timezone_list']) def test_invalid_default_dateinfo_format_raises_exception(self): self.env.config.set('trac', 'default_dateinfo_format', u'ābšolute') self.assertEqual( u'ābšolute', self.env.config.get('trac', 'default_dateinfo_format')) self.assertRaises(ConfigurationError, getattr, Chrome(self.env), 'default_dateinfo_format') def test_add_jquery_ui_first_week_day(self): def first_week_day(locale, lc_time, languages): chrome = Chrome(self.env) req = Request(href=Href('/trac.cgi'), locale=locale, lc_time=lc_time, tz=utc, languages=languages) chrome.add_jquery_ui(req) return req.chrome['script_data']['jquery_ui']['first_week_day'] # Babel is unavailable self.assertEqual(0, first_week_day(None, None, None)) self.assertEqual(1, first_week_day(None, 'iso8601', None)) if locale_en: # We expect the following aliases from babel.core import LOCALE_ALIASES, Locale self.assertEqual('ja_JP', LOCALE_ALIASES['ja']) self.assertEqual('de_DE', LOCALE_ALIASES['de']) self.assertEqual('fr_FR', LOCALE_ALIASES['fr']) self.assertEqual(0, first_week_day(locale_en, locale_en, [])) self.assertEqual(1, first_week_day(locale_en, 'iso8601', [])) ja = Locale.parse('ja') self.assertEqual(0, first_week_day(ja, ja, [])) self.assertEqual(0, first_week_day(ja, ja, ['ja', 'ja-jp'])) de = Locale.parse('de') self.assertEqual(1, first_week_day(de, de, [])) self.assertEqual(1, first_week_day(de, de, ['de', 'de-de'])) fr = Locale.parse('fr') self.assertEqual(1, first_week_day(fr, fr, [])) self.assertEqual(1, first_week_day(fr, fr, ['fr', 'fr-fr'])) self.assertEqual(0, first_week_day(fr, fr, ['fr', 'fr-ca'])) # invalid locale identifier (#12408) self.assertEqual(1, first_week_day(fr, fr, ['fr', 'fr-'])) self.assertEqual(0, first_week_day(fr, fr, ['fr', 'fr-', 'fr-ca'])) def test_add_jquery_ui_timezone_list_has_default_timezone(self): chrome = Chrome(self.env) href = Href('/trac.cgi') gmt07b = timezone('GMT -7:00') gmt04a = timezone('GMT +4:00') def verify_tzprops(lc_time, tz, tz_default, tz_label): req = Request(href=href, locale=locale_en, lc_time=lc_time, tz=tz) chrome.add_jquery_ui(req) data = req.chrome['script_data']['jquery_ui'] self.assertEqual(tz_default, data['default_timezone']) if tz_default is None: self.assertIsNone(data['timezone_list']) else: self.assertIn({ 'value': tz_default, 'label': tz_label }, data['timezone_list']) verify_tzprops('iso8601', utc, 0, '+00:00') verify_tzprops(locale_en, utc, None, None) verify_tzprops('iso8601', gmt07b, -420, '-07:00') verify_tzprops(locale_en, gmt07b, None, None) verify_tzprops('iso8601', gmt04a, 240, '+04:00') verify_tzprops(locale_en, gmt04a, None, None) if pytz: # must use timezones which does not use DST guam = timezone('Pacific/Guam') monrovia = timezone('Africa/Monrovia') panama = timezone('America/Panama') verify_tzprops('iso8601', guam, 600, '+10:00') verify_tzprops(locale_en, guam, None, None) verify_tzprops('iso8601', monrovia, 0, '+00:00') verify_tzprops(locale_en, monrovia, None, None) verify_tzprops('iso8601', panama, -300, '-05:00') verify_tzprops(locale_en, panama, None, None) def test_navigation_item_customization(self): class TestNavigationContributor1(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test1', 'Test 1' class TestNavigationContributor2(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test2', 'Test 2' class TestNavigationContributor3(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test3', 'Test 3' req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='/', add_redirect_listener=lambda listener: None) self.env.config.set('mainnav', 'test2.href', 'testtwo') self.env.config.set('mainnav', 'test3.label', 'Test Three') self.env.config.set('mainnav', 'test3.href', 'testthree') chrome = Chrome(self.env) items = chrome.prepare_request(req)['nav']['mainnav'] item = self._get_navigation_item(items, 'test1') self.assertEqual('Test 1', item['label']) item = self._get_navigation_item(items, 'test2') self.assertEqual(str(tag.a('Test 2', href='testtwo')), str(item['label'])) item = self._get_navigation_item(items, 'test3') self.assertEqual(str(tag.a('Test Three', href='testthree')), str(item['label'])) def test_attributes_preserved_in_navigation_item(self): class TestNavigationContributor1(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test1', \ tag.a('Test 1', href='test1', target='blank') class TestNavigationContributor2(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test2', \ tag.a('Test 2', href='test2', target='blank') req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='/', add_redirect_listener=lambda listener: None) self.env.config.set('mainnav', 'test1.label', 'Test One') self.env.config.set('mainnav', 'test2.label', 'Test Two') self.env.config.set('mainnav', 'test2.href', 'testtwo') chrome = Chrome(self.env) items = chrome.prepare_request(req)['nav']['mainnav'] item = self._get_navigation_item(items, 'test1') self.assertEqual(str(tag.a('Test One', href='test1', target='blank')), str(item['label'])) item = self._get_navigation_item(items, 'test2') self.assertEqual( str(tag.a('Test Two', href='testtwo', target='blank')), str(item['label'])) def test_cc_list(self): """Split delimited string to a list of email addresses.""" chrome = Chrome(self.env) cc_field1 = '[email protected],[email protected], [email protected]' cc_field2 = '[email protected];[email protected]; [email protected]' expected = ['*****@*****.**', '*****@*****.**', '*****@*****.**'] self.assertEqual(expected, chrome.cc_list(cc_field1)) self.assertEqual(expected, chrome.cc_list(cc_field2)) def test_cc_list_is_empty(self): """Empty list is returned when input is `None` or empty.""" chrome = Chrome(self.env) self.assertEqual([], chrome.cc_list(None)) self.assertEqual([], chrome.cc_list('')) self.assertEqual([], chrome.cc_list([]))
class NavigationContributorTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.env.clear_component_registry() def tearDown(self): self.env.restore_component_registry() def _get_navigation_item(self, items, name): for item in items: if item['name'] == name: return item return {} def test_nav_contributor(self): class TestNavigationContributor(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'metanav', 'test', 'Test' req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), path_info='/', base_path='/trac.cgi', add_redirect_listener=lambda listener: None) nav = Chrome(self.env).prepare_request(req)['nav'] self.assertEqual({ 'name': 'test', 'label': 'Test', 'active': False }, nav['metanav'][0]) def test_nav_contributor_active(self): class TestNavigationContributor(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return 'test' def get_navigation_items(self, req): yield 'metanav', 'test', 'Test' req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), path_info='/', base_path='/trac.cgi', add_redirect_listener=lambda listener: None) handler = TestNavigationContributor(self.env) nav = Chrome(self.env).prepare_request(req, handler)['nav'] self.assertEqual({ 'name': 'test', 'label': 'Test', 'active': True }, nav['metanav'][0]) def test_navigation_item_customization(self): class TestNavigationContributor1(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test1', 'Test 1' class TestNavigationContributor2(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test2', 'Test 2' class TestNavigationContributor3(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test3', 'Test 3' req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='/', add_redirect_listener=lambda listener: None) self.env.config.set('mainnav', 'test2.href', 'testtwo') self.env.config.set('mainnav', 'test3.label', 'Test Three') self.env.config.set('mainnav', 'test3.href', 'testthree') chrome = Chrome(self.env) items = chrome.prepare_request(req)['nav']['mainnav'] item = self._get_navigation_item(items, 'test1') self.assertEqual('Test 1', item['label']) item = self._get_navigation_item(items, 'test2') self.assertEqual(str(tag.a('Test 2', href='testtwo')), str(item['label'])) item = self._get_navigation_item(items, 'test3') self.assertEqual(str(tag.a('Test Three', href='testthree')), str(item['label'])) def test_attributes_preserved_in_navigation_item(self): class TestNavigationContributor1(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test1', \ tag.a('Test 1', href='test1', target='blank') class TestNavigationContributor2(Component): implements(INavigationContributor) def get_active_navigation_item(self, req): return None def get_navigation_items(self, req): yield 'mainnav', 'test2', \ tag.a('Test 2', href='test2', target='blank') req = Request(abs_href=Href('http://example.org/trac.cgi'), href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='/', add_redirect_listener=lambda listener: None) self.env.config.set('mainnav', 'test1.label', 'Test One') self.env.config.set('mainnav', 'test2.label', 'Test Two') self.env.config.set('mainnav', 'test2.href', 'testtwo') chrome = Chrome(self.env) items = chrome.prepare_request(req)['nav']['mainnav'] item = self._get_navigation_item(items, 'test1') self.assertEqual(str(tag.a('Test One', href='test1', target='blank')), str(item['label'])) item = self._get_navigation_item(items, 'test2') self.assertEqual( str(tag.a('Test Two', href='testtwo', target='blank')), str(item['label']))
class RecursivePolicyTestCase(unittest.TestCase): """Test case for policies that perform recursive permission checks.""" def setUp(self): self.env = EnvironmentStub() self.env.clear_component_registry() decisions = [] self.decisions = decisions class PermissionPolicy1(Component): implements(perm.IPermissionPolicy) def __init__(self): self.call_count = 0 def check_permission(self, action, username, resource, perm): self.call_count += 1 decision = None if 'ACTION_2' in perm(resource): decision = None elif action == 'ACTION_1': decision = username == 'user1' decisions.append(('policy1', action, decision)) return decision class PermissionPolicy2(Component): implements(perm.IPermissionPolicy) def __init__(self): self.call_count = 0 def check_permission(self, action, username, resource, perm): self.call_count += 1 decision = None if action == 'ACTION_2': decision = username == 'user2' decisions.append(('policy2', action, decision)) return decision self.env.enable_component(PermissionPolicy1) self.env.enable_component(PermissionPolicy2) self.env.config.set('trac', 'permission_policies', 'PermissionPolicy1, PermissionPolicy2') self.ps = perm.PermissionSystem(self.env) def tearDown(self): self.env.restore_component_registry() self.env.reset_db() def test_user1_allowed_by_policy1(self): """policy1 consulted for ACTION_1. policy1 and policy2 consulted for ACTION_2. """ perm_cache = perm.PermissionCache(self.env, 'user1') self.assertTrue('ACTION_1' in perm_cache) self.assertEqual(2, self.ps.policies[0].call_count) self.assertEqual(1, self.ps.policies[1].call_count) self.assertEqual([ ('policy1', 'ACTION_2', None), ('policy2', 'ACTION_2', False), ('policy1', 'ACTION_1', True), ], self.decisions) def test_user2_denied_by_no_decision(self): """policy1 and policy2 consulted for ACTION_1. policy1 and policy2 consulted for ACTION_2. """ perm_cache = perm.PermissionCache(self.env, 'user2') self.assertFalse('ACTION_1' in perm_cache) self.assertEqual(2, self.ps.policies[0].call_count) self.assertEqual(2, self.ps.policies[1].call_count) self.assertEqual([ ('policy1', 'ACTION_2', None), ('policy2', 'ACTION_2', True), ('policy1', 'ACTION_1', None), ('policy2', 'ACTION_1', None), ], self.decisions) def test_user1_denied_by_policy2(self): """policy1 consulted for ACTION_2. policy2 consulted for ACTION_2. """ perm_cache = perm.PermissionCache(self.env, 'user1') self.assertFalse('ACTION_2' in perm_cache) self.assertEqual(1, self.ps.policies[0].call_count) self.assertEqual(1, self.ps.policies[1].call_count) self.assertEqual([ ('policy1', 'ACTION_2', None), ('policy2', 'ACTION_2', False), ], self.decisions) def test_user1_allowed_by_policy2(self): """policy1 consulted for ACTION_2. policy2 consulted for ACTION_2. """ perm_cache = perm.PermissionCache(self.env, 'user2') self.assertTrue('ACTION_2' in perm_cache) self.assertEqual(1, self.ps.policies[0].call_count) self.assertEqual(1, self.ps.policies[1].call_count) self.assertEqual([ ('policy1', 'ACTION_2', None), ('policy2', 'ACTION_2', True), ], self.decisions)