Index: tools/playback_benchmark/playback_driver.py |
=================================================================== |
--- tools/playback_benchmark/playback_driver.py (revision 0) |
+++ tools/playback_benchmark/playback_driver.py (revision 0) |
@@ -0,0 +1,196 @@ |
+#!/usr/bin/env python |
+# |
+# Copyright 2010 Google Inc. All Rights Reserved. |
+ |
+"""Playback driver.""" |
+ |
+import cgi |
+import simplejson as json |
+import os |
+import string |
+import sys |
+import threading |
+import urlparse |
+ |
+START_PAGE = """<html> |
+ <script type="text/javascript"> |
+var runCount = $run_count; |
+var results = []; |
+ |
+function run() { |
+ var wnd = window.open('?resource=start_page_popup', '', |
+ 'width=$width, height=$height'); |
+ var timerId = setInterval(function() { |
+ wnd.postMessage('ping', '$target_origin'); |
+ }, 300); |
+ var handleMessage = function(event) { |
+ clearInterval(timerId); |
+ wnd.close(); |
+ document.writeln('<div>' + event.data + '</div>'); |
+ results.push(event.data); |
+ runCount -= 1; |
+ window.removeEventListener('message', handleMessage); |
+ if (runCount > 0) { |
+ run(); |
+ } else { |
+ var xmlHttpRequest = new XMLHttpRequest(); |
+ xmlHttpRequest.open("POST", '/benchmark/', true); |
+ xmlHttpRequest.setRequestHeader("Content-type", "application/json"); |
+ xmlHttpRequest.send(JSON.stringify({results: results})); |
+ } |
+ } |
+ window.addEventListener('message', handleMessage, false); |
+} |
+ |
+run(); |
+ </script> |
+</html> |
+""" |
+ |
+START_PAGE_POPUP = """<html> |
+ <script type="text/javascript"> |
+window.setTimeout(function() { |
+ console.log(window.innerWidth, window.innerHeight); |
+ if (window.innerWidth == $width && window.innerHeight == $height) { |
+ window.location = '$start_url'; |
+ } else { |
+ window.resizeBy($width - window.innerWidth, $height - window.innerHeight); |
+ window.location = window.location; |
+ } |
+}, 200); |
+ </script> |
+</html> |
+""" |
+ |
+DATA_JS = 'Benchmark.data = $data;' |
+ |
+ |
+def ReadFile(file_name, mode='r'): |
+ f = open(file_name, mode) |
+ data = f.read() |
+ f.close() |
+ return data |
+ |
+ |
+def ReadJSON(file_name): |
+ f = open(file_name, 'r') |
+ data = json.load(f) |
+ f.close() |
+ return data |
+ |
+ |
+class PlaybackRequestHandler(object): |
+ """This class is used to process HTTP requests during test playback. |
+ |
+ Attributes: |
+ test_dir: directory containing test files. |
+ test_callback: function to be called when the test is finished. |
+ script_dir: directory where javascript files are located. |
+ """ |
+ |
+ def __init__(self, test_dir, test_callback=None, script_dir=os.getcwd()): |
+ self.test_dir = test_dir |
+ self.test_callback = test_callback |
+ self.script_dir = script_dir |
+ |
+ def ProcessRequest(self, handler): |
+ "Processes single HTTP request." |
+ |
+ parse_result = urlparse.urlparse(handler.path) |
+ if parse_result.path.endswith('/benchmark/'): |
+ query = cgi.parse_qs(parse_result.query) |
+ if 'run_test' in query: |
+ run_count = 1 |
+ if 'run_count' in query: |
+ run_count = query['run_count'][0] |
+ self._StartTest(handler, self.test_dir, run_count) |
+ elif 'resource' in query: |
+ self._GetBenchmarkResource(query['resource'][0], handler) |
+ else: |
+ self._ProcessBenchmarkReport(handler.body, handler) |
+ else: |
+ self._GetApplicationResource(handler) |
+ |
+ def _StartTest(self, handler, test_dir, run_count): |
+ "Sends test start page to browser." |
+ |
+ cache_data = ReadJSON(os.path.join(test_dir, 'cache.json')) |
+ |
+ # Load cached responses. |
+ self.cache = {} |
+ responses_dir = os.path.join(test_dir, 'responses') |
+ for request in cache_data['requests']: |
+ response_file = os.path.join(responses_dir, request['response_file']) |
+ response = ReadFile(response_file, 'rb') |
+ key = (request['method'], request['path']) |
+ self.cache[key] = {'response': response, 'headers': request['headers']} |
+ |
+ # Load benchmark scripts. |
+ self.benchmark_resources = {} |
+ data = ReadFile(os.path.join(test_dir, 'data.json')) |
+ data = string.Template(DATA_JS).substitute(data=data) |
+ self.benchmark_resources['data.js'] = {'data': data, |
+ 'type': 'application/javascript'} |
+ for resource in ('common.js', 'playback.js'): |
+ resource_file = os.path.join(self.script_dir, resource) |
+ self.benchmark_resources[resource] = {'data': ReadFile(resource_file), |
+ 'type': 'application/javascript'} |
+ |
+ # Format start page. |
+ parse_result = urlparse.urlparse(cache_data['start_url']) |
+ target_origin = '%s://%s' % (parse_result.scheme, parse_result.netloc) |
+ start_page = string.Template(START_PAGE).substitute( |
+ run_count=run_count, target_origin=target_origin, |
+ width=cache_data['width'], height=cache_data['height']) |
+ self.benchmark_resources['start_page'] = { |
+ 'data': start_page, |
+ 'type': 'text/html; charset=UTF-8' |
+ } |
+ |
+ start_page_popup = string.Template(START_PAGE_POPUP).substitute( |
+ start_url=cache_data['start_url'], |
+ width=cache_data['width'], height=cache_data['height']) |
+ self.benchmark_resources['start_page_popup'] = { |
+ 'data': start_page_popup, |
+ 'type': 'text/html; charset=UTF-8' |
+ } |
+ |
+ self._GetBenchmarkResource('start_page', handler) |
+ |
+ def _GetBenchmarkResource(self, resource, handler): |
+ "Sends requested resource to browser." |
+ |
+ if resource in self.benchmark_resources: |
+ resource = self.benchmark_resources[resource] |
+ handler.send_response(200) |
+ handler.send_header('content-length', len(resource['data'])) |
+ handler.send_header('content-type', resource['type']) |
+ handler.end_headers() |
+ handler.wfile.write(resource['data']) |
+ else: |
+ handler.send_response(404) |
+ handler.end_headers() |
+ |
+ def _ProcessBenchmarkReport(self, content, handler): |
+ "Reads benchmark score from report content and invokes callback." |
+ |
+ handler.send_response(204) |
+ handler.end_headers() |
+ content = json.loads(content) |
+ if 'results' in content: |
+ results = content['results'] |
+ sys.stdout.write('Results: %s\n' % results) |
+ if self.test_callback: self.test_callback(results) |
+ elif 'error' in content: |
+ sys.stderr.write('Error: %s\n' % content['error']) |
+ |
+ def _GetApplicationResource(self, handler): |
+ "Searches for response in cache. If not found, responds with 204." |
+ key = (handler.command, handler.path) |
+ if key in self.cache: |
+ sys.stdout.write('%s %s -> found\n' % key) |
+ handler.wfile.write(self.cache[key]['response']) |
+ else: |
+ sys.stderr.write('%s %s -> not found\n' % key) |
+ handler.send_response(204, "not in cache") |
+ handler.end_headers() |