1b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#!/usr/bin/env python
2b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
3b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
4b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# found in the LICENSE file.
5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
6b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)import unittest
7b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)from extensions_paths import EXAMPLES, PUBLIC_TEMPLATES, STATIC_DOCS
9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from local_file_system import LocalFileSystem
10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from render_servlet import RenderServlet
11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from server_instance import ServerInstance
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochfrom servlet import Request, Response
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from test_util import ReadFile
14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class _RenderServletDelegate(RenderServlet.Delegate):
17ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  def CreateServerInstance(self):
18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return ServerInstance.ForTest(LocalFileSystem.Create())
19b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
21b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class RenderServletTest(unittest.TestCase):
2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  def _Render(self, path, headers=None, host=None):
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return RenderServlet(Request.ForTest(path, headers=headers, host=host),
240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                         _RenderServletDelegate()).Get()
250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
26b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def testExtensionAppRedirect(self):
27ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    self.assertEqual(
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Response.Redirect('/apps/storage', permanent=False),
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self._Render('storage'))
30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
31ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  def testChannelRedirect(self):
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for channel in ('stable', 'beta', 'dev', 'master'):
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.assertEqual(
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          Response.Redirect('/extensions/storage', permanent=True),
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          self._Render('%s/extensions/storage' % channel))
36b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  def testOldHostsRedirect(self):
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    self.assertEqual(
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        Response.Redirect('https://developer.chrome.com/extensions',
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            permanent=False),
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        self._Render('/chrome/extensions', host='http://code.google.com'))
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    self.assertEqual(
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        Response.Redirect('https://developer.chrome.com/extensions',
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            permanent=False),
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        self._Render('/chrome/extensions', host='https://code.google.com'))
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
47b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def testNotFound(self):
480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    def create_404_response(real_path):
490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      real_404 = self._Render(real_path)
500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      self.assertEqual(200, real_404.status)
510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      real_404.status = 404
520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return real_404
530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    root_404 = create_404_response('404')
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    extensions_404 = create_404_response('extensions/404')
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    apps_404 = create_404_response('apps/404')
570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual(root_404, self._Render('not_found'))
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual(root_404, self._Render('not_found/not_found'))
600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual(extensions_404, self._Render('extensions/not_found'))
620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    self.assertEqual(
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        extensions_404, self._Render('extensions/manifest/not_found'))
640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    self.assertEqual(
650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        extensions_404,
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self._Render('extensions/manifest/not_found/not_found'))
670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual(apps_404, self._Render('apps/not_found'))
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual(apps_404, self._Render('apps/manifest/not_found'))
700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    self.assertEqual(
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        apps_404, self._Render('apps/manifest/not_found/not_found'))
72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def testSampleFile(self):
74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    sample_file = 'extensions/talking_alarm_clock/background.js'
750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    response = self._Render('extensions/examples/%s' % sample_file)
76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    self.assertEqual(200, response.status)
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.assertTrue(response.headers['Content-Type'] in (
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        'application/javascript; charset=utf-8',
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        'application/x-javascript; charset=utf-8'))
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual(ReadFile('%s%s' % (EXAMPLES, sample_file)),
81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                     response.content.ToString())
82b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def testSampleZip(self):
84b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    sample_dir = 'extensions/talking_alarm_clock'
850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    response = self._Render('extensions/examples/%s.zip' % sample_dir)
86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    self.assertEqual(200, response.status)
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.assertEqual('application/zip', response.headers['Content-Type'])
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def testStaticFile(self):
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    static_file = 'css/out/site.css'
910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    response = self._Render('static/%s' % static_file)
92b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    self.assertEqual(200, response.status)
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.assertEqual('text/css; charset=utf-8',
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                     response.headers['Content-Type'])
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual(ReadFile('%s%s' % (STATIC_DOCS, static_file)),
96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                     response.content.ToString())
97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
98b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def testHtmlTemplate(self):
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    html_file = 'extensions/storage'
1000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    response = self._Render(html_file)
101b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    self.assertEqual(200, response.status)
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self.assertEqual('text/html; charset=utf-8',
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                     response.headers.get('Content-Type'))
104b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # Can't really test rendering all that well.
105b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    self.assertTrue(len(response.content) >
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    len(ReadFile('%s%s.html' % (PUBLIC_TEMPLATES, html_file))))
107b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  def testIndexRender(self):
1090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    response = self._Render('extensions')
1100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    self.assertEqual(200, response.status)
1110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    self.assertEqual(self._Render('extensions/index').content.ToString(),
1120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     response.content.ToString())
1130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  def testOtherRedirectsJsonRedirect(self):
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    response = self._Render('apps/webview_tag')
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual(('/apps/tags/webview', False),
1170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                     response.GetRedirect())
1180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testDirectories(self):
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # Directories should be redirected to a URL that doesn't end in a '/'
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # whether or not that exists.
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertEqual(('/dir', False), self._Render('dir/').GetRedirect())
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
124e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  def testEtags(self):
125e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    def test_path(path, content_type):
126e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      # Render without etag.
127e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      response = self._Render(path)
128e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      self.assertEqual(200, response.status)
129e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      etag = response.headers.get('ETag')
130e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      self.assertTrue(etag is not None)
131e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
132e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      # Render with an If-None-Match which doesn't match.
133e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      response = self._Render(path, headers={
134e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        'If-None-Match': '"fake etag"',
135e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      })
136e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      self.assertEqual(200, response.status)
137e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      self.assertEqual(content_type, response.headers.get('Content-Type'))
138e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      self.assertEqual(etag, response.headers.get('ETag'))
139e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
140e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      # Render with the correct matching If-None-Match.
141e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      response = self._Render(path, headers={
142e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        'If-None-Match': etag,
143e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      })
144e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      self.assertEqual(304, response.status)
145e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      self.assertEqual('Not Modified', response.content.ToString())
146e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      self.assertEqual(content_type, response.headers.get('Content-Type'))
147e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      self.assertEqual(etag, response.headers.get('ETag'))
148e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
149e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    # Test with a static path and a dynamic path.
150e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    test_path('static/css/out/site.css', 'text/css; charset=utf-8')
151e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    test_path('extensions/storage', 'text/html; charset=utf-8')
152e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
1530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)if __name__ == '__main__':
155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  unittest.main()
156