Client now launches a new browser session for each test.
Client now launches a new browser session for each test.
new file mode 100644
--- /dev/null
+++ b/client/results.py
@@ -0,0 +1,94 @@
+from collections import defaultdict
+
+class SpeedTestReport(object):
+
+ def __init__(self, results):
+ self.results = results
+ self.highest_scores = defaultdict(lambda: {'score': 0,
+ 'score_str': '',
+ 'browsers': []})
+
+ def record_highest_score(self, test, score, score_str, browser):
+ if self.highest_scores[test]['score'] < score:
+ self.highest_scores[test]['score'] = score
+ self.highest_scores[test]['score_str'] = score_str
+ self.highest_scores[test]['browsers'] = [browser]
+ elif self.highest_scores[test]['score'] == score:
+ self.highest_scores[test]['browsers'].append(browser)
+
+ def report(self):
+ s = 'Results by browser:\n\n'
+ for browser, tests in self.results.iteritems():
+ s += '%s\n%s\n\n' % (browser, '=' * len(browser))
+ for test, results_strs in tests.iteritems():
+ s += ' %s\n %s\n\n' % (test, '-' * len(test))
+
+ if test == 'PsychedelicBrowsing':
+ colorwheel = int(results_strs[0]['colorwheel'])
+ checkerboard = int(results_strs[0]['checkerboard'])
+ s += ' Psychedelic (colorwheel): %d rpm\n' % colorwheel
+ s += ' Hallucinogenic (checkerboard): %d rpm\n\n' % \
+ checkerboard
+ total = colorwheel + checkerboard
+ self.record_highest_score(test, total, '%d/%d rpm' %
+ (colorwheel, checkerboard),
+ browser)
+ continue
+
+ score = 0
+ results = map(lambda x: int(x['fps']), results_strs)
+ if len(results) == 1:
+ score = results[0]
+ score_str = '%d fps' % score
+ s += ' %s\n' % score_str
+ else:
+ if len(results) > 0:
+ s += ' Series:'
+ for r in results:
+ s += ' %3d' % r
+ s += '\n Mean: %.1d\n' % (sum(results) / len(results))
+ sorted_results = results[:]
+ sorted_results.sort()
+ if len(sorted_results) % 2 == 0:
+ median = (sorted_results[len(sorted_results)/2 - 1] + sorted_results[len(sorted_results)/2]) / 2
+ else:
+ median = sorted_results[len(sorted_results)/2]
+ s += ' Median: %d\n' % median
+ score = median
+ score_str = '%d fps' % score
+ else:
+ s += ' No data.\n'
+ if score:
+ self.record_highest_score(test, score, score_str, browser)
+ s += '\n'
+ s += '\n'
+ test_list = self.highest_scores.keys()
+ test_list.sort()
+ s += 'Results by test:\n\n'
+ for test in test_list:
+ s += '%s\n%s\n\n' % (test, '=' * len(test))
+ s += ' Highest median score: %s (%s)\n\n' % \
+ (self.highest_scores[test]['score_str'],
+ ', '.join(self.highest_scores[test]['browsers']))
+ return s
+
+
+def main():
+ results = {
+ 'firefox': {
+ 'fishtank': [{'fps': 34}, {'fps': 36}, {'fps': 40}, {'fps': 44}, {'fps': 42}, {'fps': 43}, {'fps': 44}, {'fps': 43}, {'fps': 42}, {'fps': 44}, {'fps': 43}, {'fps': 42}],
+ 'SantasWorkshop': [{'fps': 10}, {'fps': 7}, {'fps': 4}, {'fps': 3}, {'fps': 3}, {'fps': 3}, {'fps': 3}, {'fps': 3}],
+ 'PsychedelicBrowsing': [{'colorwheel': 1944, 'checkerboard': 966}]
+ },
+ 'safari': {
+ 'fishtank': [{'fps': 10}, {'fps': 9}, {'fps': 8}, {'fps': 7}, {'fps': 6}, {'fps': 6}, {'fps': 6}, {'fps': 6}],
+ 'SantasWorkshop': [{'fps': 3}, {'fps': 3}, {'fps': 3}, {'fps': 3}, {'fps': 3}, {'fps': 3}, {'fps': 3}],
+ 'PsychedelicBrowsing': [{'colorwheel': 1820, 'checkerboard': 840}]
+ }
+ }
+ report = SpeedTestReport(results)
+ print report.report()
+
+if __name__ == '__main__':
+ main()
+
--- a/client/speedtests.py
+++ b/client/speedtests.py
@@ -9,65 +9,77 @@ import os
import platform
import shutil
import socket
import subprocess
import sys
import tempfile
import threading
import time
+import urllib2
import zipfile
if platform.system() == 'Windows':
import _winreg
import ie_reg
import fxinstall
-#import results
+import results
class Config(object):
DEFAULT_CONF_FILE = 'speedtests.conf'
def __init__(self):
self.cfg = None
self.local_port = 8111
- self.test_url = 'http://brasstacks.mozilla.com/speedtestssvr/start/?auto=true'
+ self.server_html_url = 'http://brasstacks.mozilla.com/speedtests'
+ self.server_api_url = 'http://brasstacks.mozilla.com/speedtests/api'
self.cfg = None
+ self.local_test_base_path = '/speedtests'
+
+ @property
+ def local_test_base_url(self):
+ # IE has issues loading pages from localhost, so we'll use the
+ # external IP.
+ return 'http://%s:%d%s' % (self.local_ip, self.local_port,
+ self.local_test_base_path)
def read(self, testmode=False, noresults=False, conf_file=None):
+ self.testmode = testmode
+ self.noresults = noresults
if not conf_file:
conf_file = Config.DEFAULT_CONF_FILE
self.cfg = ConfigParser.ConfigParser()
self.cfg.read(conf_file)
try:
self.local_port = self.cfg.getint('speedtests', 'local_port')
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
pass
try:
- self.test_url = self.cfg.get('speedtests', 'server_url').rstrip('/') + \
- '/start/?auto=true'
+ self.server_html_url = self.cfg.get('speedtests', 'test_base_url').rstrip('/')
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
pass
+ try:
+ self.server_api_url = self.cfg.get('speedtests', 'server_url').rstrip('/')
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ pass
+
+ try:
+ self.server_results_url = self.cfg.get('speedtests', 'server_results_url').rstrip('/')
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ self.server_results_url = self.server_api_url + '/testresults/'
+
# We can also find out the address like this, supposedly more reliable:
#s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#s.connect((<TEST_HOST>, 80))
#local_ip = s.getsockname()
- local_ip = socket.gethostbyname(socket.gethostname())
- if self.test_url.find('?') == -1:
- self.test_url += '?'
- else:
- self.test_url += '&'
- self.test_url += 'ip=%s&port=%d' % (local_ip, self.local_port)
- if testmode:
- self.test_url += '&test=true'
- if noresults:
- self.test_url += '&noresults=true'
+ self.local_ip = socket.gethostbyname(socket.gethostname())
config = Config()
class BrowserController(object):
def __init__(self, os_name, browser_name, profiles, cmd, args_tuple=()):
@@ -85,16 +97,30 @@ class BrowserController(object):
self.args_tuple = args_tuple
self.proc = None
self.launch_time = None
try:
self.cmd = config.cfg.get(os_name, browser_name)
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
pass
+ def set_test_urls(self, tests):
+ self.test_url_iter = iter(tests)
+ self.current_test_url = None
+
+ def next_test(self):
+ try:
+ self.current_test_url = self.test_url_iter.next()
+ except StopIteration:
+ return False
+ if self.running():
+ self.terminate()
+ self.launch(self.current_test_url)
+ return True
+
def init_browser(self):
pass
def cmd_line(self, url):
return (self.cmd,) + self.args_tuple + (url,)
def browser_exists(self):
return os.path.exists(self.cmd)
@@ -112,30 +138,46 @@ class BrowserController(object):
profile_archive = self.get_profile_archive_path(p)
profile_zip = zipfile.ZipFile(profile_archive, 'w')
for (dirpath, dirnames, filenames) in os.walk(p['path']):
for f in filenames:
filepath = os.path.join(dirpath, f)
arcpath = filepath[len(p['path']):]
profile_zip.write(filepath, arcpath)
profile_zip.close()
-
+
+ def retry_file_op(self, func, args):
+ success = False
+ attempts = 0
+ while attempts < 3:
+ attempts += 1
+ try:
+ func(*args)
+ except (IOError, OSError):
+ pass
+ else:
+ success = True
+ break
+ time.sleep(2)
+ return success
+
def copy_profiles(self):
if not self.browser_exists():
return False
for p in self.profiles:
profile_archive = self.get_profile_archive_path(p)
if not os.path.exists(profile_archive):
return
if os.path.exists(p['path']):
t = tempfile.mkdtemp()
- try:
- shutil.move(p['path'], t)
- except (IOError, OSError):
- print 'Failed to copy profile: %s' % sys.exc_info()[1]
+ def f(path, tmp):
+ shutil.rmtree(tmp)
+ shutil.move(path, tmp)
+ if not self.retry_file_op(f, [p['path'], t]):
+ print 'Failed to copy profile 3 times; giving up.'
return False
p['previous_profile'] = os.path.join(t, os.path.basename(p['path']))
else:
p['previous_profile'] = ''
try:
os.mkdir(p['path'])
except OSError:
pass
@@ -144,68 +186,71 @@ class BrowserController(object):
return True
def clean_up(self):
if not self.profiles:
return
for p in self.profiles:
if not p['previous_profile']:
continue
- try:
+ def f(p):
shutil.rmtree(p['path'])
shutil.move(p['previous_profile'], p['path'])
os.rmdir(os.path.dirname(p['previous_profile']))
- except (IOError, OSError):
- print 'Failed to restore profile: %s' % sys.exc_info()[1]
- pass
+
+ if not self.retry_file_op(f, [p]):
+ print 'Failed to restore profile 3 times; giving up.'
def launch(self, url=None):
if not self.copy_profiles():
- print 'failed to copy profiles'
+ print 'Failed to copy profiles'
return False
if not url:
url = config.test_url
cl = self.cmd_line(url)
print 'Launching %s...' % ' '.join(cl)
self.launch_time = datetime.datetime.now()
self.proc = subprocess.Popen(cl)
return True
def running(self):
- running = self.proc and self.proc.poll()
+ if not self.proc:
+ return False
+ running = self.proc.poll()
if running != None:
self.proc = None
return running == None
def execution_time(self):
return datetime.datetime.now() - self.launch_time
def terminate(self):
if self.proc:
- print 'terminating process'
+ print 'Terminating process...'
try:
self.proc.terminate()
except: #FIXME
pass
for i in range(0, 5):
- print 'polling'
+ print 'Polling...'
if self.proc.poll() != None:
self.proc = None
break
time.sleep(2)
if self.proc:
- print 'killing process'
+ print 'Killing process...'
try:
self.proc.kill()
except:
pass
- print 'waiting for process to die'
+ print 'Waiting for process to die...'
self.proc.wait() # or poll and error out if still running?
self.proc = None
- print 'process is dead'
+ print 'Process is dead.'
+ time.sleep(5)
self.clean_up()
class LatestFxBrowserController(BrowserController):
""" Specialization to download latest nightly before launching. """
INSTALL_SUBDIR = 'speedtests_firefox_nightly'
@@ -274,20 +319,20 @@ class IEController(BrowserController):
#print 'setting %s' % str(i)
_winreg.SetValueEx(hdl, i[0], 0, i[2], i[1])
_winreg.CloseKey(hdl)
def terminate(self):
super(IEController, self).terminate()
self.restore_reg()
- def launch(self):
+ def launch(self, url=None):
self.backup_reg()
self.setup_reg()
- return super(IEController, self).launch()
+ return BrowserController.launch(self, url)
class BrowserControllerRedirFile(BrowserController):
def __init__(self, os_name, browser_name, profile_path, cmd, args_tuple=()):
super(BrowserControllerRedirFile, self).__init__(os_name, browser_name, profile_path, cmd, args_tuple)
self.redir_file = None
@@ -372,18 +417,19 @@ class BrowserRunner(object):
while True:
try:
n = self.iter.next()
except StopIteration:
raise
if not self.browser_names or n.browser_name in self.browser_names:
return n
- def __init__(self, evt, browser_names=[]):
+ def __init__(self, evt, browser_names=[], test_urls=[]):
self.evt = evt
+ self.test_urls = test_urls
try:
self.browsers = BrowserRunner.browsers_by_os(platform.system())
except KeyError:
sys.stderr.write('Unknown platform "%s".\n' % platform.system())
sys.exit(errno.EOPNOTSUPP)
self.browser_iter = BrowserRunner.BrowserControllerIter(self.browsers, browser_names)
self.current_controller = None
self.lock = threading.Lock()
@@ -418,97 +464,110 @@ class BrowserRunner(object):
return t
def browser_name(self):
self.lock.acquire()
browser_name = self.current_controller.browser_name
self.lock.release()
return browser_name
+ def next_test(self):
+ self.lock.acquire()
+ need_to_launch = not self.current_controller or not self.current_controller.next_test()
+ self.lock.release()
+ if need_to_launch:
+ self.launch_next_browser()
+
def launch_next_browser(self):
self.lock.acquire()
if self.current_controller:
+ print 'Closing browser...'
self.current_controller.terminate()
- print 'Test running time: %s' % self.current_controller.execution_time()
-
+ print '%s test running time: %s' % (self.current_controller.browser_name, self.current_controller.execution_time())
while True:
try:
self.current_controller = self.browser_iter.next()
except StopIteration:
self.evt.set()
self.lock.release()
return
+ self.current_controller.set_test_urls(self.test_urls)
self.current_controller.init_browser()
if self.current_controller.browser_exists():
- print 'launching %s' % self.current_controller.browser_name
- if self.current_controller.launch():
+ print 'Launching %s...' % self.current_controller.browser_name
+ if self.current_controller.next_test():
break
else:
- print 'failed to launch browser.'
+ print 'Failed to launch browser.'
self.lock.release()
class TestRunnerHTTPServer(BaseHTTPServer.HTTPServer):
def __init__(self, server_address, RequestHandlerClass, browser_runner):
BaseHTTPServer.HTTPServer.__init__(self, server_address, RequestHandlerClass)
self.browser_runner = browser_runner
self.results = collections.defaultdict(lambda: collections.defaultdict(list))
-
+
+ def standard_web_data(self):
+ return {'ip': config.local_ip}
+
class TestRunnerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
- # Indicates that the tests on the current browser have finished.
- print 'got pingback'
- self.server.browser_runner.launch_next_browser()
- text = '<html><body>Done tests; launching next browser...</body></html>'
- try:
- self.send_response(200)
- self.send_header('Content-type', 'text/html')
- self.send_header('Content-Length', str(len(text)))
- self.end_headers()
- self.wfile.write(text)
- except socket.error:
- # Browser was probably closed before we could send the response
- pass
+ if self.path.startswith(config.local_test_base_path):
+ try:
+ url = config.server_html_url + self.path[len(config.local_test_base_path):]
+ u = urllib2.urlopen(url)
+ except urllib2.HTTPError, e:
+ self.send_response(e.getcode())
+ else:
+ data = u.read()
+ self.send_response(200)
+ for header, value in u.info().items():
+ self.send_header(header, value)
+ self.end_headers()
+ self.wfile.write(data)
+ else:
+ self.send_response(404)
def do_POST(self):
- # Parse the form data posted
- form = cgi.FieldStorage(
- fp=self.rfile,
- headers=self.headers,
- environ={'REQUEST_METHOD':'POST',
- 'CONTENT_TYPE':self.headers['Content-Type'],
- })
-
- # record results
- web_data = json.loads(form['body'].value)
+ length = int(self.headers.getheader('content-length'))
+ web_data = json.loads(self.rfile.read(length))
testname = web_data['testname']
- self.server.results[self.server.browser_runner.browser_name()][testname].append(web_data['results'])
+ self.server.results[self.server.browser_runner.browser_name()][testname].extend(web_data['results'])
+ if not config.testmode and not config.noresults:
+ web_data.update(self.server.standard_web_data())
+ raw_data = json.dumps(web_data)
+ req = urllib2.Request(config.server_results_url, raw_data)
+ req.add_header('Content-Type', 'application/json; charset=utf-8')
+ req.add_header('Content-Length', len(raw_data))
+ try:
+ urllib2.urlopen(req)
+ except urllib2.HTTPError, e:
+ print '**ERROR sending results to server: %s' % e
+ print ''
self.send_response(200)
self.end_headers()
self.wfile.write('<html></html>')
+ self.server.browser_runner.next_test()
- def read_data(self):
- data = ''
- while True:
- buf = self.rfile.read()
- if buf == '':
- break
- data += buf
- return data
+ def log_message(self, format, *args):
+ """ Suppress log output. """
+ return
MAX_TEST_TIME = datetime.timedelta(seconds=60*10)
def main():
from optparse import OptionParser
parser = OptionParser()
- parser.add_option('-t', '--test', dest='testmode', action='store_true')
+ parser.add_option('-t', '--test', dest='tests', action='append', default=[])
+ parser.add_option('--testmode', dest='testmode', action='store_true')
parser.add_option('-n', '--noresults', dest='noresults', action='store_true')
(options, args) = parser.parse_args()
config.read(options.testmode, options.noresults)
def get_browser_arg():
try:
browser = args[1]
except IndexError:
@@ -522,33 +581,60 @@ def main():
BrowserRunner(evt).archive_current_profiles(browser)
sys.exit(0)
elif len(args) >= 1 and args[0] == 'load':
browser = get_browser_arg()
BrowserRunner(evt).launch(browser, 'http://google.ca')
sys.exit(0)
# start tests in specified browsers. if none given, run all.
- br = BrowserRunner(evt, args)
+ url_prefix = config.local_test_base_url + '/start.html?ip=%s&port=%d' % (config.local_ip, config.local_port)
+ if config.testmode:
+ url_prefix += '&test=true'
+ url_prefix += '&testUrl='
+ if not options.tests:
+ print 'Getting test list from server...'
+ try:
+ tests_url = config.server_api_url + '/tests/'
+ print 'Getting test list from %s...' % tests_url
+ options.tests = json.loads(urllib2.urlopen(tests_url).read())
+ except urllib2.HTTPError, e:
+ sys.stderr.write('Could not get test list: %s\n' % e)
+ sys.exit(errno.EPERM)
+ except urllib2.URLError, e:
+ sys.stderr.write('Could not get test list: %s\n' % e.reason)
+ sys.exit(e.reason.errno)
+
+ test_urls = map(lambda x: url_prefix + x, options.tests)
+ br = BrowserRunner(evt, args, test_urls)
trs = TestRunnerHTTPServer(('', config.local_port), TestRunnerRequestHandler, br)
server_thread = threading.Thread(target=trs.serve_forever)
server_thread.start()
+ start = datetime.datetime.now()
br.launch_next_browser()
while not evt.is_set():
if br.browser_running():
+ if evt.is_set():
+ # evt may have been set while we were waiting for the lock in browser_running().
+ break
if br.execution_time() > MAX_TEST_TIME:
- print 'test has taken too long; starting next browser'
+ print 'Test has taken too long; starting next browser'
br.launch_next_browser()
else:
- print 'browser isn\'t running!'
+ print 'Browser isn\'t running!'
br.launch_next_browser()
evt.wait(5)
trs.shutdown()
server_thread.join()
+ end = datetime.datetime.now()
+ print ''
print 'Done!'
- #report = results.SpeedTestReport(trs.results)
- #print 'Test results:'
- #print ''
- #print report.report()
+ report = results.SpeedTestReport(trs.results)
+ print
+ print 'Start: %s' % start
+ print 'Duration: %s' % (end - start)
+ print 'Client: %s' % config.local_ip
+ print
+ print report.report()
if __name__ == '__main__':
main()
--- a/html/js/speedtests.js
+++ b/html/js/speedtests.js
@@ -1,10 +1,8 @@
-DYNAMIC_SERVER_URL = "http://" + window.location.hostname + '/speedtestssvr';
-
var SpeedTests = function() {
var loadingNextTest = false;
var all_results = [];
var startTime = null;
var lastReportTime = null;
var isoDateTime = function (d) {
@@ -19,51 +17,36 @@ var SpeedTests = function() {
var recordResults = function (testname, results) {
results.browser_width = window.innerWidth;
results.browser_height = window.innerHeight;
results.teststart = isoDateTime(startTime);
all_results.push(results);
};
-// var crossDomainPost = function NetUtils_crossDomainPost(url, values, callback) {
-// if (!arguments.callee.c)
-// arguments.callee.c = 1;
-// var iframeName = "iframe" + arguments.callee.c++;
-// var iframe = $("<iframe></iframe>").hide().attr("name", iframeName).appendTo("body");
-// var form = $("<form></form>").hide().attr({ action: url, method: "post", target: iframeName }).appendTo("body");
-// for (var i in values) {
-// $("<input type='hidden'>").attr({ name: i, value: values[i]}).appendTo(form);
-// }
-// form.get(0).submit();
-// form.remove();
-// iframe.get(0).onload = function crossDomainIframeLoaded() {
-// callback();
-// setTimeout(function () { iframe.remove(); }, 0);
-// }
-// };
-
var getSearchParams = function() {
var params = document.location.search.slice(1).split("&");
var args = new Object();
- var l;
- for (var i = 0; i < params.length; i++) {
- l = params[i].split("=");
- if (l.length != 2) {
+ for (p in params) {
+ var l = params[p].split("=");
+ for (var i = 0; i < l.length; i++) {
+ l[i] = decodeURIComponent(l[i]);
+ }
+ if (l.length != 2)
continue;
- }
- args[decodeURIComponent(l[0])] = decodeURIComponent(l[1]);
+ args[l[0]] = l[1];
}
return args;
};
return {
init: function() {
startTime = new Date();
},
+ getSearchParams: getSearchParams,
isoDateTime: isoDateTime,
recordResults: recordResults,
periodicRecordResults: function (testname, resultFunc) {
var now = new Date();
var etms = now - startTime;
if (lastReportTime == null || now - lastReportTime > 5000) {
lastReportTime = now;
var results = resultFunc();
@@ -73,39 +56,28 @@ var SpeedTests = function() {
return etms;
},
nextTest: function (testname) {
if (loadingNextTest) {
return;
}
loadingNextTest = true;
var searchParams = getSearchParams();
- if (searchParams.noresults === undefined) {
- var results = {
- testname: testname,
- ip: searchParams.ip,
- results: all_results,
- ua: navigator.userAgent
- };
- if (searchParams.test !== undefined) {
- results.test = true;
- }
- var body = JSON.stringify(results);
- var req = new XMLHttpRequest();
- req.open("POST", DYNAMIC_SERVER_URL + "/testresults/", false);
- req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
- req.setRequestHeader("Content-length", body.length);
- req.setRequestHeader("Connection", "close");
- req.send(body);
+ if (!searchParams.ip) {
+ alert("Can't submit test results: no local IP provided.");
+ return;
+ }
+ if (!searchParams.port) {
+ alert("Can't submit test results: no local port provided.");
+ return;
}
-
- var url = DYNAMIC_SERVER_URL + "/nexttest/" + testname + "/" +
- document.location.search;
- window.location.assign(url);
-// var local_url = 'http://' + searchParams.ip + ':' + searchParams.port + '/';
-// crossDomainPost(local_url, {body: body}, function () {
-// var url = DYNAMIC_SERVER_URL + "/nexttest/" + testname + "/" +
-// document.location.search;
-// window.location.assign(url);
-// });
+ var body = JSON.stringify({ testname: testname, ip: searchParams.ip,
+ results: all_results,
+ ua: navigator.userAgent });
+ var req = new XMLHttpRequest();
+ req.open("POST", "http://" + searchParams.ip + ":" + searchParams.port + "/", false);
+ req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+ req.setRequestHeader("Content-length", body.length);
+ req.setRequestHeader("Connection", "close");
+ req.send(body);
}
};
}();
--- a/server/speedtests_server.py
+++ b/server/speedtests_server.py
@@ -1,184 +1,13 @@
#!/usr/bin/env python2.6
-import ConfigParser
-import json
-import os
-import re
+import templeton.handlers
+import templeton.middleware
+import handlers
import web
-import speedtests
-import urllib2
-
-TESTS_DIR = 'speedtests'
-
-DEFAULT_CONF_FILE = 'speedtests_server.conf'
-cfg = ConfigParser.ConfigParser()
-cfg.read(DEFAULT_CONF_FILE)
-try:
- HTML_URL = cfg.get('speedtests', 'html_url')
-except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- HTML_URL = 'http://192.168.1.101/speedtests'
-try:
- HTML_DIR = cfg.get('speedtests', 'html_dir')
-except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- HTML_DIR = os.path.join('..', 'html')
-try:
- SERVER_URL = cfg.get('speedtests', 'server_url')
-except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- SERVER_URL = 'http://192.168.1.101/speedtestssvr'
-try:
- PROXY_TO = cfg.get('speedtests', 'proxy')
-except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- PROXY_TO = None
-try:
- RESULTS_ONLY = cfg.get('speedtests', 'results only')
-except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- RESULTS_ONLY = False
-
-urls = ['/testresults/', 'TestResults']
-if not RESULTS_ONLY:
- urls.extend([
- '/nexttest/(.*)', 'NextTest',
- '/start/', 'StartTests',
- '/done/', 'DoneTests'
- ])
-
-
-def query_params():
- params = {}
- if web.ctx.query:
- for q in web.ctx.query[1:].split('&'):
- name, equals, value = q.partition('=')
- if equals:
- params[name] = value
- return params
-
-
-class NextTest(object):
-
- def GET(self, current_testname):
- params = query_params()
- # The start page is new and launches the tests in a new window with a
- # set size. For anyone going straight to /nexttest/, we'll redirect
- # them to the start page. The start page will include the search
- # string 'runtests=true' to actually load the next test.
- if not params.get('runtests', False):
- raise web.seeother('%s/start/' % SERVER_URL)
-
- tests = filter(lambda x: os.path.exists(os.path.join(HTML_DIR, x, 'Default.html')), os.listdir(HTML_DIR))
- tests.sort()
- for t in tests:
- if t > current_testname:
- if params.get('test', False):
- testpage = web.template.frender('templates/test.html')
- return testpage(t, HTML_URL)
- else:
- raise web.seeother('%s/%s/Default.html%s' % (HTML_URL, t, web.ctx.query))
- if params.get('auto', False):
- # Redirect to the local server to start the next browser.
- # We can't use localhost here because IE has issues connecting to the server via
- # localhost.
- raise web.seeother('http://%s:%s/' % (params['ip'], params['port']))
- raise web.seeother('%s/done/' % SERVER_URL)
-
-def get_browser_id(ua):
- ua = ua.lower()
- platform = 'unknown'
- geckover = 'n/a'
- buildid = 'unknown'
- browserid = 0
-
- if 'firefox' in ua:
- bname = 'Firefox'
- m = re.match('[^\(]*\((.*) rv:([^\)]*)\) gecko/([^ ]+) firefox/(.*)',
- ua)
- platform = m.group(1).replace(';', '').strip()
- geckover = m.group(2)
- buildid = m.group(3)
- bver = m.group(4)
- elif 'msie' in ua:
- bname = 'Internet Explorer'
- m = re.search('msie ([^;]*);([^\)]*)\)', ua)
- bver = m.group(1)
- platform = m.group(2).replace(';', '').strip()
- elif 'chrome' in ua:
- bname = 'Chrome'
- m = re.match('mozilla/[^ ]* \(([^\)]*)\).*chrome/([^ ]*)', ua)
- platform = m.group(1).strip()
- bver = m.group(2)
- elif 'safari' in ua:
- bname = 'Safari'
- m = re.match('[^\(]*\(([^\)]*)\).*safari/(.*)', ua)
- platform = m.group(1)
- # 64-bit builds have an extra part separated by a semicolon.
- # Strip it off here rather than making the re much more complicated.
- delim = platform.find(';')
- if delim != -1:
- platform = platform[:delim]
- bver = m.group(2)
- elif 'opera' in ua:
- bname = 'Opera'
- m = re.match('[^\(]*\(([^;]*);[^\)]*\).*version/(.*)', ua)
- platform = m.group(1).strip()
- if platform == 'x11':
- platform = 'linux'
- bver = m.group(2).strip()
-
- wheredict = {
- 'browsername': bname,
- 'browserversion': bver,
- 'platform': platform,
- 'geckoversion': geckover,
- 'buildid': buildid
- }
- browser = db.select('browser', where=web.db.sqlwhere(wheredict))
- if not browser:
- db.insert('browser', **wheredict)
- browser = db.select('browser', where=web.db.sqlwhere(wheredict))
- return browser[0].id
-
+urls = templeton.handlers.load_urls(handlers.urls)
-class TestResults(object):
-
- def POST(self):
- if PROXY_TO:
- headers = {
- 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
- 'Accept-Encoding': 'gzip, deflate'
- }
- request = urllib2.Request(PROXY_TO, web.data(), headers)
- response = urllib2.urlopen(request, timeout=120).read()
- return
- web_data = json.loads(web.data())
- machine_ip = web_data['ip']
- testname = web_data['testname']
- browser_id = get_browser_id(web_data['ua'])
- for results in web_data['results']:
- results['browser_id'] = browser_id
- results['ip'] = machine_ip
- cols = {}
- for k, v in results.iteritems():
- cols[k.encode('ascii')] = v
- db.insert(testname, **cols)
+app = web.application(urls, handlers.__dict__)
-class StartTests(object):
-
- def GET(self):
- start = web.template.frender('templates/start.html')
- return start(SERVER_URL, HTML_URL)
-
-
-class DoneTests(object):
-
- def GET(self):
- done = web.template.frender('templates/done.html')
- return done(SERVER_URL, HTML_URL)
-
-
-db = web.database(dbn='mysql', db='speedtests', user='speedtests',
- pw='speedtests')
-app = web.application(urls, globals())
-
if __name__ == '__main__':
app.run()
deleted file mode 100644
--- a/server/templates/done.html
+++ /dev/null
@@ -1,13 +0,0 @@
-$def with (svrurl, htmldir)
-<html>
-<head>
- <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
- <title>All tests complete!</title>
-</head>
-<body>
-<p>
-All tests have been completed and the results recorded.
-</p>
-<script>window.close();</script>
-</body>
-</html>
deleted file mode 100644
--- a/server/templates/start.html
+++ /dev/null
@@ -1,35 +0,0 @@
-$def with (svrurl, htmldir)
-<html>
-<head>
- <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
- <title>Mozilla SpeedTest Runner</title>
- <script type="text/javascript" src="$htmldir/js/jquery.min.js"></script>
-</head>
-<body>
-<div id="main">
-<p>
-SpeedTests go!
-</p>
-</div>
-<script>
-$$(document).ready(function() {
-
- var search = '';
- if (document.location.search) {
- search = '&' + document.location.search.slice(1);
- }
-
- var w = window.open('$svrurl/nexttest/?runtests=true' + search, 'testWindow',
- 'resizable=no,status=no,top=0,left=0,height=768,width=1024,menubar=no,toolbar=no,location=no,personalbar=no');
-
- var iId = setInterval(function() {
- if (w.closed) {
- clearInterval(iId);
- $$("#main").html('<p>SpeedTests are done!</p><p><a href="$svrurl/start/">Run them again</a>.</p>');
- }
- }, 1000);
-
-});
-</script>
-</body>
-</html>
--- a/server/templates/test.html
+++ b/server/templates/test.html
@@ -1,22 +1,22 @@
-$def with (testname, htmlurl)
+$def with (testname)
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title>TEST $testname</title>
</head>
<body>
<div id="main">
<p>TEST $testname</p>
</div>
-<script type="text/javascript" src="$htmlurl/js/jquery.min.js"></script>
-<script type="text/javascript" src="$htmlurl/js/json2.js"></script>
-<script type="text/javascript" src="$htmlurl/js/speedtests.js"></script>
+<script type="text/javascript" src="../../js/jquery.min.js"></script>
+<script type="text/javascript" src="../../js/json2.js"></script>
+<script type="text/javascript" src="../../js/speedtests.js"></script>
<script>
$$(document).ready(function() {
window.setTimeout(function() {
$$("#main").append("<p>TEST Submitting results and loading next test...</p>");
SpeedTests.nextTest("$testname");
}, 2000);
});
</script>