100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com#!/usr/bin/env python
28015dd83ae37147bb630d4751030868051ad0caereed@android.com# Copyright 2013 The Chromium Authors. All rights reserved.
38015dd83ae37147bb630d4751030868051ad0caereed@android.com# Use of this source code is governed by a BSD-style license that can be
48015dd83ae37147bb630d4751030868051ad0caereed@android.com# found in the LICENSE file.
500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
600dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comimport unittest
700dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
800dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comfrom extensions_paths import EXAMPLES, PUBLIC_TEMPLATES, STATIC_DOCS
900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comfrom local_file_system import LocalFileSystem
1000dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comfrom render_servlet import RenderServlet
1100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comfrom server_instance import ServerInstance
1200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comfrom servlet import Request, Response
1300dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comfrom test_util import ReadFile
14dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com
1500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
1600dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comclass _RenderServletDelegate(RenderServlet.Delegate):
17dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com  def CreateServerInstance(self):
1800dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    return ServerInstance.ForTest(LocalFileSystem.Create())
19dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com
2000dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
21dd0ac281e920b01a63789893cc3e7422789658ddreed@android.comclass RenderServletTest(unittest.TestCase):
2200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com  def _Render(self, path, headers=None, host=None):
2300dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    return RenderServlet(Request.ForTest(path, headers=headers, host=host),
2400dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com                         _RenderServletDelegate()).Get()
2500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
2600dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com  def testExtensionAppRedirect(self):
27dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com    self.assertEqual(
2800dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com        Response.Redirect('/apps/storage', permanent=False),
2900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com        self._Render('storage'))
3000dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
3100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com  def testChannelRedirect(self):
3200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    for channel in ('stable', 'beta', 'dev', 'master'):
3300dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com      self.assertEqual(
3400dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com          Response.Redirect('/extensions/storage', permanent=True),
3500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com          self._Render('%s/extensions/storage' % channel))
3600dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
3700dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com  def testOldHostsRedirect(self):
3800dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(
3900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com        Response.Redirect('https://developer.chrome.com/extensions',
408015dd83ae37147bb630d4751030868051ad0caereed@android.com            permanent=False),
418015dd83ae37147bb630d4751030868051ad0caereed@android.com        self._Render('/chrome/extensions', host='http://code.google.com'))
428015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual(
438015dd83ae37147bb630d4751030868051ad0caereed@android.com        Response.Redirect('https://developer.chrome.com/extensions',
448015dd83ae37147bb630d4751030868051ad0caereed@android.com            permanent=False),
458015dd83ae37147bb630d4751030868051ad0caereed@android.com        self._Render('/chrome/extensions', host='https://code.google.com'))
468015dd83ae37147bb630d4751030868051ad0caereed@android.com
478015dd83ae37147bb630d4751030868051ad0caereed@android.com  def testNotFound(self):
488015dd83ae37147bb630d4751030868051ad0caereed@android.com    def create_404_response(real_path):
498015dd83ae37147bb630d4751030868051ad0caereed@android.com      real_404 = self._Render(real_path)
5000dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com      self.assertEqual(200, real_404.status)
518015dd83ae37147bb630d4751030868051ad0caereed@android.com      real_404.status = 404
528015dd83ae37147bb630d4751030868051ad0caereed@android.com      return real_404
538015dd83ae37147bb630d4751030868051ad0caereed@android.com
548015dd83ae37147bb630d4751030868051ad0caereed@android.com    root_404 = create_404_response('404')
558015dd83ae37147bb630d4751030868051ad0caereed@android.com    extensions_404 = create_404_response('extensions/404')
568015dd83ae37147bb630d4751030868051ad0caereed@android.com    apps_404 = create_404_response('apps/404')
578015dd83ae37147bb630d4751030868051ad0caereed@android.com
5800dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(root_404, self._Render('not_found'))
5900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(root_404, self._Render('not_found/not_found'))
6000dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
6100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(extensions_404, self._Render('extensions/not_found'))
6200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(
6300dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com        extensions_404, self._Render('extensions/manifest/not_found'))
6400dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(
6500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com        extensions_404,
6600dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com        self._Render('extensions/manifest/not_found/not_found'))
6700dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
6800dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(apps_404, self._Render('apps/not_found'))
6900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(apps_404, self._Render('apps/manifest/not_found'))
7000dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(
7100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com        apps_404, self._Render('apps/manifest/not_found/not_found'))
7200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
738015dd83ae37147bb630d4751030868051ad0caereed@android.com  def testSampleFile(self):
748015dd83ae37147bb630d4751030868051ad0caereed@android.com    sample_file = 'extensions/talking_alarm_clock/background.js'
758015dd83ae37147bb630d4751030868051ad0caereed@android.com    response = self._Render('extensions/examples/%s' % sample_file)
768015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual(200, response.status)
778015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertTrue(response.headers['Content-Type'] in (
788015dd83ae37147bb630d4751030868051ad0caereed@android.com        'application/javascript; charset=utf-8',
798015dd83ae37147bb630d4751030868051ad0caereed@android.com        'application/x-javascript; charset=utf-8'))
808015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual(ReadFile('%s%s' % (EXAMPLES, sample_file)),
818015dd83ae37147bb630d4751030868051ad0caereed@android.com                     response.content.ToString())
828015dd83ae37147bb630d4751030868051ad0caereed@android.com
838015dd83ae37147bb630d4751030868051ad0caereed@android.com  def testSampleZip(self):
848015dd83ae37147bb630d4751030868051ad0caereed@android.com    sample_dir = 'extensions/talking_alarm_clock'
858015dd83ae37147bb630d4751030868051ad0caereed@android.com    response = self._Render('extensions/examples/%s.zip' % sample_dir)
868015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual(200, response.status)
878015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual('application/zip', response.headers['Content-Type'])
888015dd83ae37147bb630d4751030868051ad0caereed@android.com
898015dd83ae37147bb630d4751030868051ad0caereed@android.com  def testStaticFile(self):
908015dd83ae37147bb630d4751030868051ad0caereed@android.com    static_file = 'css/out/site.css'
9100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    response = self._Render('static/%s' % static_file)
9200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(200, response.status)
938015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual('text/css; charset=utf-8',
9400dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com                     response.headers['Content-Type'])
9500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(ReadFile('%s%s' % (STATIC_DOCS, static_file)),
968015dd83ae37147bb630d4751030868051ad0caereed@android.com                     response.content.ToString())
978015dd83ae37147bb630d4751030868051ad0caereed@android.com
988015dd83ae37147bb630d4751030868051ad0caereed@android.com  def testHtmlTemplate(self):
9900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    html_file = 'extensions/storage'
100dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com    response = self._Render(html_file)
10100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual(200, response.status)
10200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertEqual('text/html; charset=utf-8',
10300dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com                     response.headers.get('Content-Type'))
10400dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    # Can't really test rendering all that well.
10500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com    self.assertTrue(len(response.content) >
10600dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com                    len(ReadFile('%s%s.html' % (PUBLIC_TEMPLATES, html_file))))
1078015dd83ae37147bb630d4751030868051ad0caereed@android.com
1088015dd83ae37147bb630d4751030868051ad0caereed@android.com  def testIndexRender(self):
1098015dd83ae37147bb630d4751030868051ad0caereed@android.com    response = self._Render('extensions')
1108015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual(200, response.status)
1118015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual(self._Render('extensions/index').content.ToString(),
1128015dd83ae37147bb630d4751030868051ad0caereed@android.com                     response.content.ToString())
1138015dd83ae37147bb630d4751030868051ad0caereed@android.com
1148015dd83ae37147bb630d4751030868051ad0caereed@android.com  def testOtherRedirectsJsonRedirect(self):
1158015dd83ae37147bb630d4751030868051ad0caereed@android.com    response = self._Render('apps/webview_tag')
1168015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual(('/apps/tags/webview', False),
1178015dd83ae37147bb630d4751030868051ad0caereed@android.com                     response.GetRedirect())
1188015dd83ae37147bb630d4751030868051ad0caereed@android.com
1198015dd83ae37147bb630d4751030868051ad0caereed@android.com  def testDirectories(self):
1208015dd83ae37147bb630d4751030868051ad0caereed@android.com    # Directories should be redirected to a URL that doesn't end in a '/'
1218015dd83ae37147bb630d4751030868051ad0caereed@android.com    # whether or not that exists.
1228015dd83ae37147bb630d4751030868051ad0caereed@android.com    self.assertEqual(('/dir', False), self._Render('dir/').GetRedirect())
1238015dd83ae37147bb630d4751030868051ad0caereed@android.com
1248015dd83ae37147bb630d4751030868051ad0caereed@android.com  def testEtags(self):
1258015dd83ae37147bb630d4751030868051ad0caereed@android.com    def test_path(path, content_type):
1268015dd83ae37147bb630d4751030868051ad0caereed@android.com      # Render without etag.
1278015dd83ae37147bb630d4751030868051ad0caereed@android.com      response = self._Render(path)
1288015dd83ae37147bb630d4751030868051ad0caereed@android.com      self.assertEqual(200, response.status)
12900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com      etag = response.headers.get('ETag')
13000dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com      self.assertTrue(etag is not None)
13100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com
13200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com      # Render with an If-None-Match which doesn't match.
13300dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com      response = self._Render(path, headers={
134dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com        'If-None-Match': '"fake etag"',
135dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      })
136dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      self.assertEqual(200, response.status)
137dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      self.assertEqual(content_type, response.headers.get('Content-Type'))
138dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      self.assertEqual(etag, response.headers.get('ETag'))
139dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com
140dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      # Render with the correct matching If-None-Match.
141dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      response = self._Render(path, headers={
142dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com        'If-None-Match': etag,
143dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      })
144dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      self.assertEqual(304, response.status)
145dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      self.assertEqual('Not Modified', response.content.ToString())
146dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com      self.assertEqual(content_type, response.headers.get('Content-Type'))
147      self.assertEqual(etag, response.headers.get('ETag'))
148
149    # Test with a static path and a dynamic path.
150    test_path('static/css/out/site.css', 'text/css; charset=utf-8')
151    test_path('extensions/storage', 'text/html; charset=utf-8')
152
153
154if __name__ == '__main__':
155  unittest.main()
156