Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / common / extensions / docs / server2 / patch_servlet_test.py
blob022b150798f6c0a0aa01abf53defbe7a6666ba3f
1 #!/usr/bin/env python
2 # Copyright 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 from HTMLParser import HTMLParser
7 import unittest
9 from fake_fetchers import ConfigureFakeFetchers
10 from github_file_system_provider import GithubFileSystemProvider
11 from host_file_system_provider import HostFileSystemProvider
12 from patch_servlet import PatchServlet
13 from render_servlet import RenderServlet
14 from server_instance import ServerInstance
15 from servlet import Request
16 from test_branch_utility import TestBranchUtility
17 from test_util import DisableLogging
21 _ALLOWED_HOST = 'https://chrome-apps-doc.appspot.com'
24 def _CheckURLsArePatched(content, patch_servlet_path):
25 errors = []
26 class LinkChecker(HTMLParser):
27 def handle_starttag(self, tag, attrs):
28 if tag != 'a':
29 return
30 tag_description = '<a %s .../>' % ' '.join('%s="%s"' % (key, val)
31 for key, val in attrs)
32 attrs = dict(attrs)
33 if ('href' in attrs and
34 attrs['href'].startswith('/') and
35 not attrs['href'].startswith('/%s/' % patch_servlet_path)):
36 errors.append('%s has an unqualified href' % tag_description)
37 LinkChecker().feed(content)
38 return errors
41 class _RenderServletDelegate(RenderServlet.Delegate):
42 def CreateServerInstance(self):
43 return ServerInstance.ForLocal()
45 class _PatchServletDelegate(RenderServlet.Delegate):
46 def CreateBranchUtility(self, object_store_creator):
47 return TestBranchUtility.CreateWithCannedData()
49 def CreateHostFileSystemProvider(self, object_store_creator, **optargs):
50 return HostFileSystemProvider.ForLocal(object_store_creator, **optargs)
52 def CreateGithubFileSystemProvider(self, object_store_creator):
53 return GithubFileSystemProvider.ForEmpty()
56 class PatchServletTest(unittest.TestCase):
57 def setUp(self):
58 ConfigureFakeFetchers()
60 def _RenderWithPatch(self, path, issue):
61 path_with_issue = '%s/%s' % (issue, path)
62 return PatchServlet(Request.ForTest(path_with_issue, host=_ALLOWED_HOST),
63 _PatchServletDelegate()).Get()
65 def _RenderWithoutPatch(self, path):
66 return RenderServlet(Request.ForTest(path, host=_ALLOWED_HOST),
67 _RenderServletDelegate()).Get()
69 def _RenderAndCheck(self, path, issue, expected_equal):
70 '''Renders |path| with |issue| patched in and asserts that the result is
71 the same as |expected_equal| modulo any links that get rewritten to
72 "_patch/issue".
73 '''
74 patched_response = self._RenderWithPatch(path, issue)
75 unpatched_response = self._RenderWithoutPatch(path)
76 patched_response.headers.pop('cache-control', None)
77 unpatched_response.headers.pop('cache-control', None)
78 unpatched_content = unpatched_response.content.ToString()
80 # Check that all links in the patched content are qualified with
81 # the patch URL, then strip them out for checking (in)equality.
82 patched_content = patched_response.content.ToString()
83 patch_servlet_path = '_patch/%s' % issue
84 errors = _CheckURLsArePatched(patched_content, patch_servlet_path)
85 self.assertFalse(errors,
86 '%s\nFound errors:\n * %s' % (patched_content, '\n * '.join(errors)))
87 patched_content = patched_content.replace('/%s' % patch_servlet_path, '')
89 self.assertEqual(patched_response.status, unpatched_response.status)
90 self.assertEqual(patched_response.headers, unpatched_response.headers)
91 if expected_equal:
92 self.assertEqual(patched_content, unpatched_content)
93 else:
94 self.assertNotEqual(patched_content, unpatched_content)
96 def _RenderAndAssertEqual(self, path, issue):
97 self._RenderAndCheck(path, issue, True)
99 def _RenderAndAssertNotEqual(self, path, issue):
100 self._RenderAndCheck(path, issue, False)
102 @DisableLogging('warning')
103 def _AssertNotFound(self, path, issue):
104 response = self._RenderWithPatch(path, issue)
105 self.assertEqual(response.status, 404,
106 'Path %s with issue %s should have been removed for %s.' % (
107 path, issue, response))
109 def _AssertOk(self, path, issue):
110 response = self._RenderWithPatch(path, issue)
111 self.assertEqual(response.status, 200,
112 'Failed to render path %s with issue %s.' % (path, issue))
113 self.assertTrue(len(response.content.ToString()) > 0,
114 'Rendered result for path %s with issue %s should not be empty.' %
115 (path, issue))
117 def _AssertRedirect(self, path, issue, redirect_path):
118 response = self._RenderWithPatch(path, issue)
119 self.assertEqual(302, response.status)
120 self.assertEqual('/_patch/%s/%s' % (issue, redirect_path),
121 response.headers['Location'])
123 def testRender(self):
124 # '_patch' is not included in paths below because it's stripped by Handler.
125 issue = '14096030'
127 # TODO(kalman): Test with chrome_sidenav.json once the sidenav logic has
128 # stabilised.
130 # extensions/runtime.html is removed in the patch, should redirect to the
131 # apps version.
132 self._AssertRedirect('extensions/runtime.html', issue,
133 'apps/runtime.html')
135 # apps/runtime.html is not removed.
136 self._RenderAndAssertEqual('apps/runtime.html', issue)
138 # test_foo.html is added in the patch.
139 self._AssertOk('extensions/test_foo.html', issue)
141 # Invalid issue number results in a 404.
142 self._AssertNotFound('extensions/index.html', '11111')
144 def testXssRedirect(self):
145 def is_redirect(from_host, from_path, to_url):
146 response = PatchServlet(Request.ForTest(from_path, host=from_host),
147 _PatchServletDelegate()).Get()
148 redirect_url, _ = response.GetRedirect()
149 if redirect_url is None:
150 return (False, '%s/%s did not cause a redirect' % (
151 from_host, from_path))
152 if redirect_url != to_url:
153 return (False, '%s/%s redirected to %s not %s' % (
154 from_host, from_path, redirect_url, to_url))
155 return (True, '%s/%s redirected to %s' % (
156 from_host, from_path, redirect_url))
157 self.assertTrue(*is_redirect('http://developer.chrome.com', '12345',
158 '%s/_patch/12345' % _ALLOWED_HOST))
159 self.assertTrue(*is_redirect('http://developers.google.com', '12345',
160 '%s/_patch/12345' % _ALLOWED_HOST))
161 self.assertFalse(*is_redirect('http://chrome-apps-doc.appspot.com', '12345',
162 None))
163 self.assertFalse(*is_redirect('http://some-other-app.appspot.com', '12345',
164 None))
166 if __name__ == '__main__':
167 unittest.main()