Home | History | Annotate | Download | only in playback_benchmark
      1 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 """Playback driver."""
      5 
      6 import cgi
      7 import simplejson as json
      8 import os
      9 import string
     10 import sys
     11 import threading
     12 import urlparse
     13 
     14 START_PAGE = """<html>
     15   <script type="text/javascript">
     16 var runCount = $run_count;
     17 var results = [];
     18 
     19 function run() {
     20   var wnd = window.open('?resource=start_page_popup', '',
     21                         'width=$width, height=$height');
     22   var timerId = setInterval(function() {
     23     wnd.postMessage('ping', '$target_origin');
     24   }, 300);
     25   var handleMessage = function(event) {
     26     clearInterval(timerId);
     27     wnd.close();
     28     document.writeln('<div>' + event.data + '</div>');
     29     results.push(event.data);
     30     runCount -= 1;
     31     window.removeEventListener('message', handleMessage);
     32     if (runCount > 0) {
     33       run();
     34     } else {
     35       var xmlHttpRequest = new XMLHttpRequest();
     36       xmlHttpRequest.open("POST", '/benchmark/', true);
     37       xmlHttpRequest.setRequestHeader("Content-type", "application/json");
     38       xmlHttpRequest.send(JSON.stringify({results: results}));
     39     }
     40   }
     41   window.addEventListener('message', handleMessage, false);
     42 }
     43 
     44 run();
     45   </script>
     46 </html>
     47 """
     48 
     49 START_PAGE_POPUP = """<html>
     50   <script type="text/javascript">
     51 window.setTimeout(function() {
     52   console.log(window.innerWidth, window.innerHeight);
     53   if (window.innerWidth == $width && window.innerHeight == $height) {
     54     window.location = '$start_url';
     55   } else {
     56     window.resizeBy($width - window.innerWidth, $height - window.innerHeight);
     57     window.location = window.location;
     58   }
     59 }, 200);
     60   </script>
     61 </html>
     62 """
     63 
     64 DATA_JS = 'Benchmark.data = $data;'
     65 
     66 
     67 def ReadFile(file_name, mode='r'):
     68   f = open(file_name, mode)
     69   data = f.read()
     70   f.close()
     71   return data
     72 
     73 
     74 def ReadJSON(file_name):
     75   f = open(file_name, 'r')
     76   data = json.load(f)
     77   f.close()
     78   return data
     79 
     80 
     81 class PlaybackRequestHandler(object):
     82   """This class is used to process HTTP requests during test playback.
     83 
     84   Attributes:
     85     test_dir: directory containing test files.
     86     test_callback: function to be called when the test is finished.
     87     script_dir: directory where javascript files are located.
     88   """
     89 
     90   def __init__(self, test_dir, test_callback=None, script_dir=os.getcwd()):
     91     self.test_dir = test_dir
     92     self.test_callback = test_callback
     93     self.script_dir = script_dir
     94 
     95   def ProcessRequest(self, handler):
     96     "Processes single HTTP request."
     97 
     98     parse_result = urlparse.urlparse(handler.path)
     99     if parse_result.path.endswith('/benchmark/'):
    100       query = cgi.parse_qs(parse_result.query)
    101       if 'run_test' in query:
    102         run_count = 1
    103         if 'run_count' in query:
    104           run_count = query['run_count'][0]
    105         self._StartTest(handler, self.test_dir, run_count)
    106       elif 'resource' in query:
    107         self._GetBenchmarkResource(query['resource'][0], handler)
    108       else:
    109         self._ProcessBenchmarkReport(handler.body, handler)
    110     else:
    111       self._GetApplicationResource(handler)
    112 
    113   def _StartTest(self, handler, test_dir, run_count):
    114     "Sends test start page to browser."
    115 
    116     cache_data = ReadJSON(os.path.join(test_dir, 'cache.json'))
    117 
    118     # Load cached responses.
    119     self.cache = {}
    120     responses_dir = os.path.join(test_dir, 'responses')
    121     for request in cache_data['requests']:
    122       response_file = os.path.join(responses_dir, request['response_file'])
    123       response = ReadFile(response_file, 'rb')
    124       key = (request['method'], request['path'])
    125       self.cache[key] = {'response': response, 'headers': request['headers']}
    126 
    127     # Load benchmark scripts.
    128     self.benchmark_resources = {}
    129     data = ReadFile(os.path.join(test_dir, 'data.json'))
    130     data = string.Template(DATA_JS).substitute(data=data)
    131     self.benchmark_resources['data.js'] = {'data': data,
    132                                            'type': 'application/javascript'}
    133     for resource in ('common.js', 'playback.js'):
    134       resource_file = os.path.join(self.script_dir, resource)
    135       self.benchmark_resources[resource] = {'data': ReadFile(resource_file),
    136                                             'type': 'application/javascript'}
    137 
    138     # Format start page.
    139     parse_result = urlparse.urlparse(cache_data['start_url'])
    140     target_origin = '%s://%s' % (parse_result.scheme, parse_result.netloc)
    141     start_page = string.Template(START_PAGE).substitute(
    142         run_count=run_count, target_origin=target_origin,
    143         width=cache_data['width'], height=cache_data['height'])
    144     self.benchmark_resources['start_page'] = {
    145       'data': start_page,
    146       'type': 'text/html; charset=UTF-8'
    147     }
    148 
    149     start_page_popup = string.Template(START_PAGE_POPUP).substitute(
    150         start_url=cache_data['start_url'],
    151         width=cache_data['width'], height=cache_data['height'])
    152     self.benchmark_resources['start_page_popup'] = {
    153       'data': start_page_popup,
    154       'type': 'text/html; charset=UTF-8'
    155     }
    156 
    157     self._GetBenchmarkResource('start_page', handler)
    158 
    159   def _GetBenchmarkResource(self, resource, handler):
    160     "Sends requested resource to browser."
    161 
    162     if resource in self.benchmark_resources:
    163       resource = self.benchmark_resources[resource]
    164       handler.send_response(200)
    165       handler.send_header('content-length', len(resource['data']))
    166       handler.send_header('content-type', resource['type'])
    167       handler.end_headers()
    168       handler.wfile.write(resource['data'])
    169     else:
    170       handler.send_response(404)
    171       handler.end_headers()
    172 
    173   def _ProcessBenchmarkReport(self, content, handler):
    174     "Reads benchmark score from report content and invokes callback."
    175 
    176     handler.send_response(204)
    177     handler.end_headers()
    178     content = json.loads(content)
    179     if 'results' in content:
    180       results = content['results']
    181       sys.stdout.write('Results: %s\n' % results)
    182       if self.test_callback: self.test_callback(results)
    183     elif 'error' in content:
    184       sys.stderr.write('Error: %s\n' % content['error'])
    185 
    186   def _GetApplicationResource(self, handler):
    187     "Searches for response in cache. If not found, responds with 204."
    188     key = (handler.command, handler.path)
    189     if key in self.cache:
    190       sys.stdout.write('%s %s -> found\n' % key)
    191       handler.wfile.write(self.cache[key]['response'])
    192     else:
    193       sys.stderr.write('%s %s -> not found\n' % key)
    194       handler.send_response(204, "not in cache")
    195       handler.end_headers()
    196