integration_test.py revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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. 5 6# Run build_server so that files needed by tests are copied to the local 7# third_party directory. 8import build_server 9build_server.main() 10 11from itertools import groupby 12from operator import itemgetter 13import optparse 14import os 15import posixpath 16import sys 17import time 18import unittest 19 20from branch_utility import BranchUtility 21from link_error_detector import LinkErrorDetector 22from local_file_system import LocalFileSystem 23from local_renderer import LocalRenderer 24from fake_fetchers import ConfigureFakeFetchers 25from handler import Handler 26from servlet import Request 27from test_util import EnableLogging, DisableLogging 28 29# Arguments set up if __main__ specifies them. 30_EXPLICIT_TEST_FILES = None 31 32def _ToPosixPath(os_path): 33 return os_path.replace(os.sep, '/') 34 35def _GetPublicFiles(): 36 '''Gets all public files mapped to their contents. 37 ''' 38 public_path = os.path.join(sys.path[0], os.pardir, 'templates', 'public') 39 public_files = {} 40 for path, dirs, files in os.walk(public_path, topdown=True): 41 dirs[:] = [d for d in dirs if d != '.svn'] 42 relative_posix_path = _ToPosixPath(path[len(public_path):]) 43 for filename in files: 44 with open(os.path.join(path, filename), 'r') as f: 45 public_files['/'.join((relative_posix_path, filename))] = f.read() 46 return public_files 47 48def _PrintBrokenLinks(broken_links): 49 '''Prints out broken links in a more readable format. 50 ''' 51 col_width = max(len(link[0]) for link in broken_links) 52 getter = itemgetter(1) 53 54 def pretty_print(prefix, message): 55 print("%s%s -> %s" % (prefix, (col_width - len(prefix)) * ' ', message)) 56 57 for target, links in groupby(sorted(broken_links, key=getter), getter): 58 links = [l[0] for l in links] 59 if len(links) > 50: 60 out = "%s and %d others" % (links[0], len(links) - 1) 61 pretty_print(out, target) 62 else: 63 for link in links: 64 pretty_print(link, target) 65 66class IntegrationTest(unittest.TestCase): 67 def setUp(self): 68 ConfigureFakeFetchers() 69 70 @EnableLogging('info') 71 def testCronAndPublicFiles(self): 72 '''Runs cron then requests every public file. Cron needs to be run first 73 because the public file requests are offline. 74 ''' 75 if _EXPLICIT_TEST_FILES is not None: 76 return 77 78 print('Running cron...') 79 start_time = time.time() 80 try: 81 response = Handler(Request.ForTest('/_cron/stable')).Get() 82 self.assertEqual(200, response.status) 83 self.assertEqual('Success', response.content.ToString()) 84 finally: 85 print('Took %s seconds' % (time.time() - start_time)) 86 87 print("Checking for broken links...") 88 start_time = time.time() 89 link_error_detector = LinkErrorDetector( 90 LocalFileSystem(os.path.join(sys.path[0], os.pardir, os.pardir)), 91 lambda path: Handler(Request.ForTest(path)).Get(), 92 'templates/public', 93 ('extensions/index.html', 'apps/about_apps.html')) 94 95 broken_links, broken_anchors = link_error_detector.GetBrokenLinks() 96 if broken_links or broken_anchors: 97 # TODO(jshumway): Test should fail when broken links are detected. 98 print('Warning: Found %d broken links:' % ( 99 len(broken_links + broken_anchors))) 100 _PrintBrokenLinks(broken_links + broken_anchors) 101 102 print('Took %s seconds.' % (time.time() - start_time)) 103 104 print('Searching for orphaned pages...') 105 start_time = time.time() 106 orphaned_pages = link_error_detector.GetOrphanedPages() 107 if orphaned_pages: 108 # TODO(jshumway): Test should fail when orphaned pages are detected. 109 print('Warning: Found %d orphaned pages:' % len(orphaned_pages)) 110 for page in orphaned_pages: 111 print(page) 112 print('Took %s seconds.' % (time.time() - start_time)) 113 114 public_files = _GetPublicFiles() 115 116 print('Rendering %s public files...' % len(public_files.keys())) 117 start_time = time.time() 118 try: 119 for path, content in public_files.iteritems(): 120 if path.endswith('redirects.json'): 121 continue 122 def check_result(response): 123 self.assertEqual(200, response.status, 124 'Got %s when rendering %s' % (response.status, path)) 125 # This is reaaaaally rough since usually these will be tiny templates 126 # that render large files. At least it'll catch zero-length responses. 127 self.assertTrue(len(response.content) >= len(content), 128 'Content was "%s" when rendering %s' % (response.content, path)) 129 130 check_result(Handler(Request.ForTest(path)).Get()) 131 132 # Make sure that leaving out the .html will temporarily redirect to the 133 # path with the .html. 134 if path != '/404.html': 135 redirect_result = Handler( 136 Request.ForTest(posixpath.splitext(path)[0])).Get() 137 self.assertEqual((path, False), redirect_result.GetRedirect()) 138 139 # Make sure including a channel will permanently redirect to the same 140 # path without a channel. 141 for channel in BranchUtility.GetAllChannelNames(): 142 redirect_result = Handler( 143 Request.ForTest('%s/%s' % (channel, path))).Get() 144 self.assertEqual((path, True), redirect_result.GetRedirect()) 145 146 # Samples are internationalized, test some locales. 147 if path.endswith('/samples.html'): 148 for lang in ['en-US', 'es', 'ar']: 149 check_result(Handler(Request.ForTest( 150 path, 151 headers={'Accept-Language': '%s;q=0.8' % lang})).Get()) 152 finally: 153 print('Took %s seconds' % (time.time() - start_time)) 154 155 # TODO(kalman): Move this test elsewhere, it's not an integration test. 156 # Perhaps like "presubmit_tests" or something. 157 def testExplicitFiles(self): 158 '''Tests just the files in _EXPLICIT_TEST_FILES. 159 ''' 160 if _EXPLICIT_TEST_FILES is None: 161 return 162 for filename in _EXPLICIT_TEST_FILES: 163 print('Rendering %s...' % filename) 164 start_time = time.time() 165 try: 166 response = LocalRenderer.Render(_ToPosixPath(filename)) 167 self.assertEqual(200, response.status) 168 self.assertTrue(response.content != '') 169 finally: 170 print('Took %s seconds' % (time.time() - start_time)) 171 172 # TODO(jshumway): Check page for broken links (currently prohibited by the 173 # time it takes to render the pages). 174 175 @DisableLogging('warning') 176 def testFileNotFound(self): 177 response = Handler(Request.ForTest('/extensions/notfound.html')).Get() 178 self.assertEqual(404, response.status) 179 180if __name__ == '__main__': 181 parser = optparse.OptionParser() 182 parser.add_option('-a', '--all', action='store_true', default=False) 183 (opts, args) = parser.parse_args() 184 if not opts.all: 185 _EXPLICIT_TEST_FILES = args 186 # Kill sys.argv because we have our own flags. 187 sys.argv = [sys.argv[0]] 188 unittest.main() 189