Delete webkit-perf.appspot.com code from WebKit repository
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 20 Jan 2013 05:04:30 +0000 (05:04 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 20 Jan 2013 05:04:30 +0000 (05:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=107390

Reviewed by Adam Barth.

Delete webkit-perf.appspot.com code from WebKit repository since I maintain
and push the code via https://github.com/rniwa/webkit-perf now.

* Websites/webkit-perf.appspot.com: Removed.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@140266 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
ChangeLog
Websites/webkit-perf.appspot.com/admin.html [deleted file]
Websites/webkit-perf.appspot.com/admin_handlers.py [deleted file]
Websites/webkit-perf.appspot.com/app.yaml [deleted file]
Websites/webkit-perf.appspot.com/backends.yaml [deleted file]
Websites/webkit-perf.appspot.com/controller.py [deleted file]
Websites/webkit-perf.appspot.com/create_handler.py [deleted file]
Websites/webkit-perf.appspot.com/css/admin.css [deleted file]
Websites/webkit-perf.appspot.com/css/title.png [deleted file]
Websites/webkit-perf.appspot.com/index.yaml [deleted file]
Websites/webkit-perf.appspot.com/js/admin.js [deleted file]
Websites/webkit-perf.appspot.com/js/config.js [deleted file]
Websites/webkit-perf.appspot.com/json_generators.py [deleted file]
Websites/webkit-perf.appspot.com/json_generators_unittest.py [deleted file]
Websites/webkit-perf.appspot.com/main.py [deleted file]
Websites/webkit-perf.appspot.com/models.py [deleted file]
Websites/webkit-perf.appspot.com/models_unittest.py [deleted file]
Websites/webkit-perf.appspot.com/report_handler.py [deleted file]
Websites/webkit-perf.appspot.com/report_logs.html [deleted file]
Websites/webkit-perf.appspot.com/report_logs_handler.py [deleted file]
Websites/webkit-perf.appspot.com/report_process_handler.py [deleted file]

index aee606e95cfe554cce1dbce5904fb776ee4952ba..700696b5c89100dc79cb520fe95c5bb844673a85 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2013-01-19  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Delete webkit-perf.appspot.com code from WebKit repository
+        https://bugs.webkit.org/show_bug.cgi?id=107390
+
+        Reviewed by Adam Barth.
+
+        Delete webkit-perf.appspot.com code from WebKit repository since I maintain
+        and push the code via https://github.com/rniwa/webkit-perf now.
+
+        * Websites/webkit-perf.appspot.com: Removed.
+
 2013-01-19  Philip Rogers  <pdr@google.com>
 
         Merge SVGStylable into SVGStyledElement
diff --git a/Websites/webkit-perf.appspot.com/admin.html b/Websites/webkit-perf.appspot.com/admin.html
deleted file mode 100644 (file)
index 4d90ea3..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-<!DOCTYPE html>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this file,
-   - You can obtain one at http://mozilla.org/MPL/2.0/.  -->
-<html>
-<head>
-    <title>Admin - Perf-o-Matic</title>
-    <link rel="stylesheet" href="../css/reset.min.css" type="text/css" />
-    <link rel="stylesheet" href="../css/common.css" type="text/css" />
-    <link rel="stylesheet" href="../css/admin.css" type="text/css" />
-</head>
-<body>
-    
-<header id="header">
-    <h1>
-        <a href="/"><span id="logo">Perf-O-Matic</span></a>
-    </h1>
-    <nav>
-        <a href="/">Dashboard</a>
-        <a href="/graph.html">Custom Chart</a>
-    </nav>
-</header>
-
-<div id="summary">
-
-<section>
-<h2>Report logs</h2>
-<dl class="counts">
-    <dt>Total</dt>
-    <dd>{{ report_log_total }}</dd>
-    <dt>Committed</dt>
-    <dd>{{ report_log_committed }}</dd>
-</dl>
-
-<!-- FIXME: Merge /admin/report-logs here -->
-<p><a href="/admin/report-logs">Manage report logs</a></p>
-</section>
-
-<section id="branches">
-<h2>Branches</h2>
-<ul>
-    <li class="form">
-        <form method="POST" action="create/branch">
-        <dl>
-        <dt><label for="branch-key">Key</label></dt><dd><input type="text" id="branch-key" name="key"></dd>
-        <dt><label for="branch-name">Name</label></dt><dd><input type="text" id="branch-name" name="name"></dd>
-        </dl>
-        <button type="submit">Create</button>
-        </form>
-    </li>
-</ul>
-</section>
-
-<section id="platforms">
-<h2>Platforms</h2>
-<ul>
-    <li class="form">
-        <form method="POST" action="create/platform">
-        <dl>
-        <dt><label for="platform-key">Key</label></dt><dd><input type="text" id="platform-key" name="key"></dd>
-        <dt><label for="platform-name">Name</label></dt><dd><input type="text" id="platform-name" name="name"></dd>
-        </dl>
-        <button type="submit">Create</button>
-        </form>
-    </li>
-</ul>
-</section>
-
-<section id="builders">
-<h2>Builders</h2>
-<ul>
-    <li class="form">
-        <form method="POST" action="create/builder">
-        <dl>
-        <dt><label for="builder-name">Name</label></dt><dd><input type="text" id="builder-name" name="name"></dd>
-        <dt><label for="builder-password">Password</label></dt><dd><input type="password" id="builder-password" name="password"></dd>
-        </dl>
-        <button type="submit">Create</button>
-        </form>
-    </li>
-</ul>
-</section>
-
-<section id="tests">
-<h2>Tests</h2>
-<ul>
-    <li class="form">
-        <form method="POST" action="merge-tests">
-        <button type="submit">Merge</button>
-        <select name="merge"></select> into
-        <select name="into"></select>
-        </form>
-    </li>
-</ul>
-</section>
-</div>
-
-<div id="manual-submission">
-<section>
-<h2>Manual submission</h2>
-<form method="POST" action="/admin/report/">
-<textarea name="payload" rows="20" cols="100">
-</textarea><br>
-<button type="submit">Submit</button>
-</form>
-</section>
-<!-- FIXME: Merge admin/manual-submit.html here -->
-</div>
-
-<div id="errors">
-</div>
-
-<div id="footer">
-<a href="https://appengine.google.com/dashboard?app_id=webkit-perf">App Engine dashboard</a>
-</div>
-
-<script type="text/javascript" src="../jq/jquery-1.4.4.min.js"></script>
-<script type="text/javascript" src="../js/config.js"></script>
-<script type="text/javascript" src="../js/common.js"></script>
-<script type="text/javascript" src="../js/admin.js"></script>
-
-</body>
-</html>
diff --git a/Websites/webkit-perf.appspot.com/admin_handlers.py b/Websites/webkit-perf.appspot.com/admin_handlers.py
deleted file mode 100644 (file)
index 38740b6..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import webapp2
-import json
-
-from google.appengine.api import taskqueue
-from google.appengine.api import users
-from google.appengine.ext.db import GqlQuery
-from google.appengine.ext.webapp import template
-
-from controller import schedule_runs_update
-from controller import schedule_dashboard_update
-from controller import schedule_manifest_update
-from models import Branch
-from models import Builder
-from models import Platform
-from models import ReportLog
-from models import Test
-
-
-class IsAdminHandler(webapp2.RequestHandler):
-    def get(self):
-        self.response.headers['Content-Type'] = 'application/json'
-        self.response.out.write('true' if users.is_current_user_admin() else 'false')
-
-
-class AdminDashboardHandler(webapp2.RequestHandler):
-    def get(self, task):
-        task_method_name = 'get_' + task
-        if task_method_name in dir(self) and task_method_name not in dir(super):
-            method = getattr(self, task_method_name)
-            return method()
-
-        report_log_total = GqlQuery("SELECT __key__ FROM ReportLog").count()
-        report_log_committed = GqlQuery("SELECT __key__ FROM ReportLog WHERE commit = True").count()
-
-        self.response.out.write(template.render('admin.html',
-            {'report_log_total': report_log_total, 'report_log_committed': report_log_committed}))
-
-    def get_branches(self):
-        self.response.headers['Content-Type'] = 'application/json'
-        result = {}
-        for branch in Branch.all():
-            result[branch.key().name()] = {'name': branch.name}
-        self.response.out.write(json.dumps(result))
-
-    def get_platforms(self):
-        self.response.headers['Content-Type'] = 'application/json'
-        result = {}
-        for platform in Platform.all():
-            result[platform.key().name()] = {'name': platform.name, 'hidden': platform.hidden}
-        self.response.out.write(json.dumps(result))
-
-    def get_builders(self):
-        self.response.headers['Content-Type'] = 'application/json'
-        self.response.out.write(json.dumps([builder.name for builder in Builder.all()]))
-
-    def get_tests(self):
-        self.response.headers['Content-Type'] = 'application/json'
-        result = {}
-        for test in Test.all():
-            result[test.key().name()] = {'name': test.name, 'hidden': test.hidden}
-        self.response.out.write(json.dumps(result))
-
-
-class ChangeVisibilityHandler(webapp2.RequestHandler):
-    def post(self):
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-
-        try:
-            payload = json.loads(self.request.body)
-            hide = payload['hide']
-        except:
-            self.response.out.write("Failed to parse the payload: %s" % self.request.body)
-            return
-
-        if 'platform' in payload:
-            model = Platform.get_by_key_name(payload['platform'])
-        elif 'test' in payload:
-            model = Test.get_by_key_name(payload['test'])
-        else:
-            self.response.out.write('Not supported')
-            return
-
-        if not model:
-            self.response.out.write('Could not find the model')
-            return
-
-        model.hidden = hide
-        model.put()
-        schedule_dashboard_update()
-        schedule_manifest_update()
-
-        self.response.out.write('OK')
-
-
-class MergeTestsHandler(webapp2.RequestHandler):
-    def post(self, task):
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-
-        if task != 'run':
-            try:
-                payload = json.loads(self.request.body)
-                merge = payload.get('merge', '')
-                into = payload.get('into', '')
-            except:
-                self.response.out.write("Failed to parse the payload: %s" % self.request.body)
-                return
-
-            if merge == into or not Test.get_by_key_name(merge) or not Test.get_by_key_name(into):
-                self.response.out.write('Invalid test names')
-                return
-
-            taskqueue.add(url='/admin/merge-tests/run', params={'merge': merge, 'into': into}, target='model-manipulator')
-            self.response.out.write('OK')
-            return
-
-        merge = Test.get_by_key_name(self.request.get('merge'))
-        into = Test.get_by_key_name(self.request.get('into'))
-
-        branches_and_platforms_to_update = into.merge(merge)
-        if branches_and_platforms_to_update == None:
-            # FIXME: This message is invisible. Need to store this somewhere and let the admin page pull it.
-            self.response.out.write('Cannot merge %s into %s. There are conflicting results.' % (merge.name, into.name))
-            return
-
-        for branch_id, platform_id in branches_and_platforms_to_update:
-            schedule_runs_update(into.id, branch_id, platform_id)
-
-        schedule_dashboard_update()
-        schedule_manifest_update()
-
-        self.response.out.write('OK')
diff --git a/Websites/webkit-perf.appspot.com/app.yaml b/Websites/webkit-perf.appspot.com/app.yaml
deleted file mode 100644 (file)
index 9c4280b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-application: webkit-perf
-version: 20
-runtime: python27
-api_version: 1
-threadsafe: false
-
-handlers:
-- url: /favicon\.ico
-  static_files: favicon.ico
-  upload: favicon\.ico
-
-- url: /
-  static_files: index.html
-  upload: index.html
-
-- url: /((index|embed|graph)\.html)
-  static_files: \1
-  upload: ((index|embed|graph)\.html)
-
-- url: /css
-  static_dir: css
-
-- url: /js
-  static_dir: js
-
-- url: /jq
-  static_dir: jq
-
-- url: /api/test/report
-  script: main.py
-  secure: always
-
-- url: /admin/.*
-  script: main.py
-  secure: always
-  login: admin
-
-- url: .*
-  script: main.py
diff --git a/Websites/webkit-perf.appspot.com/backends.yaml b/Websites/webkit-perf.appspot.com/backends.yaml
deleted file mode 100644 (file)
index 8aad895..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-backends:
-- model-manipulator
-  options: dynamic
diff --git a/Websites/webkit-perf.appspot.com/controller.py b/Websites/webkit-perf.appspot.com/controller.py
deleted file mode 100644 (file)
index d3d3aa1..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import urllib
-import webapp2
-from google.appengine.api import taskqueue
-from google.appengine.ext import db
-
-from json_generators import DashboardJSONGenerator
-from json_generators import ManifestJSONGenerator
-from models import Branch
-from models import DashboardImage
-from models import PersistentCache
-from models import Platform
-from models import Runs
-from models import Test
-from models import model_from_numeric_id
-
-
-def schedule_manifest_update():
-    taskqueue.add(url='/api/test/update')
-
-
-class ManifestUpdateHandler(webapp2.RequestHandler):
-    def post(self):
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-        PersistentCache.set_cache('manifest', ManifestJSONGenerator().to_json())
-        self.response.out.write('OK')
-
-
-class CachedManifestHandler(webapp2.RequestHandler):
-    def get(self):
-        self.response.headers['Content-Type'] = 'application/json'
-        manifest = PersistentCache.get_cache('manifest')
-        if manifest:
-            self.response.out.write(manifest)
-        else:
-            schedule_manifest_update()
-
-
-def schedule_dashboard_update():
-    taskqueue.add(url='/api/test/dashboard/update')
-
-
-class DashboardUpdateHandler(webapp2.RequestHandler):
-    def post(self):
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-        PersistentCache.set_cache('dashboard', DashboardJSONGenerator().to_json())
-        self.response.out.write('OK')
-
-
-class CachedDashboardHandler(webapp2.RequestHandler):
-    def get(self):
-        self.response.headers['Content-Type'] = 'application/json'
-        dashboard = PersistentCache.get_cache('dashboard')
-        if dashboard:
-            self.response.out.write(dashboard)
-        else:
-            schedule_dashboard_update()
-
-
-def schedule_runs_update(test_id, branch_id, platform_id, regenerate_runs=True):
-    if regenerate_runs:
-        taskqueue.add(url='/api/test/runs/update', params={'id': test_id, 'branchid': branch_id, 'platformid': platform_id})
-    taskqueue.add(url='/api/test/runs/chart', params={'id': test_id, 'branchid': branch_id, 'platformid': platform_id,
-        'displayDays': 7})
-
-
-def _get_test_branch_platform_ids(handler):
-    try:
-        test_id = int(handler.request.get('id', 0))
-        branch_id = int(handler.request.get('branchid', 0))
-        platform_id = int(handler.request.get('platformid', 0))
-        return test_id, branch_id, platform_id
-    except TypeError:
-        # FIXME: Output an error here
-        return 0, 0, 0
-
-
-class RunsUpdateHandler(webapp2.RequestHandler):
-    def post(self):
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-        test_id, branch_id, platform_id = _get_test_branch_platform_ids(self)
-
-        branch = model_from_numeric_id(branch_id, Branch)
-        platform = model_from_numeric_id(platform_id, Platform)
-        test = model_from_numeric_id(test_id, Test)
-        assert branch
-        assert platform
-        assert test
-
-        Runs.update_or_insert(branch, platform, test)
-        self.response.out.write('OK')
-
-
-class CachedRunsHandler(webapp2.RequestHandler):
-    def get(self):
-        self.response.headers['Content-Type'] = 'application/json'
-
-        test_id, branch_id, platform_id = _get_test_branch_platform_ids(self)
-        runs = Runs.json_by_ids(branch_id, platform_id, test_id)
-        if runs:
-            self.response.out.write(runs)
-        elif model_from_numeric_id(branch_id, Branch) and model_from_numeric_id(platform_id, Platform) and model_from_numeric_id(test_id, Test):
-            schedule_runs_update(test_id, branch_id, platform_id)
-
-
-class RunsChartHandler(webapp2.RequestHandler):
-    def post(self):
-        x = 0
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-        test_id, branch_id, platform_id = _get_test_branch_platform_ids(self)
-
-        branch = model_from_numeric_id(branch_id, Branch)
-        platform = model_from_numeric_id(platform_id, Platform)
-        test = model_from_numeric_id(test_id, Test)
-        display_days = int(self.request.get('displayDays'))
-        assert branch
-        assert platform
-        assert test
-        params = Runs.get_by_objects(branch, platform, test).chart_params(display_days)
-        if not params:
-            return
-        dashboard_chart_file = urllib.urlopen('http://chart.googleapis.com/chart', urllib.urlencode(params))
-
-        DashboardImage.create(branch.id, platform.id, test.id, display_days, dashboard_chart_file.read())
-
-
-class DashboardImageHandler(webapp2.RequestHandler):
-    def get(self, test_id, branch_id, platform_id, display_days):
-        try:
-            branch_id = int(branch_id)
-            platform_id = int(platform_id)
-            test_id = int(test_id)
-            display_days = int(display_days)
-        except ValueError:
-            self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-            self.response.out.write('Failed')
-
-        self.response.headers['Content-Type'] = 'image/png'
-        self.response.out.write(DashboardImage.get_image(branch_id, platform_id, test_id, display_days))
-
-
-def schedule_report_process(log):
-    taskqueue.add(url='/api/test/report/process', params={'id': log.key().id()})
diff --git a/Websites/webkit-perf.appspot.com/create_handler.py b/Websites/webkit-perf.appspot.com/create_handler.py
deleted file mode 100644 (file)
index 5eb40a1..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import webapp2
-from google.appengine.ext import db
-
-import json
-
-from controller import schedule_dashboard_update
-from models import Builder
-from models import Branch
-from models import NumericIdHolder
-from models import Platform
-from models import create_in_transaction_with_numeric_id_holder
-
-
-class CreateHandler(webapp2.RequestHandler):
-    def post(self, model):
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-
-        try:
-            payload = json.loads(self.request.body)
-            key = payload.get('key', '')
-            name = payload.get('name', '')
-            password = payload.get('password', '')
-        except:
-            self.response.out.write("Failed to parse the payload: %s" % self.request.body)
-            return
-
-        if model == 'builder':
-            error = self._create_builder(name, password)
-        elif model == 'branch':
-            error = self._create_branch(key, name)
-        elif model == 'platform':
-            error = self._create_platform(key, name)
-        else:
-            error = "Unknown model type: %s\n" % model
-
-        # No need to clear manifest or runs since they only contain ones with test results
-        schedule_dashboard_update()
-        self.response.out.write(error if error else 'OK')
-
-    def _create_builder(self, name, password):
-        if not name or not password:
-            return 'Invalid name or password'
-
-        def execute():
-            message = None
-            bot = Builder.get_by_key_name(name)
-            if bot:
-                message = 'Updating the password since bot "%s" already exists' % name
-                bot.update_password(password)
-            else:
-                Builder.create(name, password)
-            return message
-
-        return db.run_in_transaction(execute)
-
-    def _create_branch(self, key, name):
-        if not key or not name:
-            return 'Invalid key or name'
-        return None if Branch.create_if_possible(key, name) else 'Branch "%s" already exists' % key
-
-    def _create_platform(self, key, name):
-        if not key or not name:
-            return 'Invalid key name'
-        return None if Platform.create_if_possible(key, name) else 'Platform "%s" already exists' % key
diff --git a/Websites/webkit-perf.appspot.com/css/admin.css b/Websites/webkit-perf.appspot.com/css/admin.css
deleted file mode 100644 (file)
index 2005899..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-html {
-    padding: 0px;
-    margin: 0px;
-    overflow: auto;
-}
-
-#summary, #manual-submission {
-    font-size: 14px;
-    line-height: 36px;
-}
-
-#summary {
-    margin-top: 49px;
-    display: table;
-    border-collapse: collapse;
-}
-
-section {
-    display: table-cell;
-    background: white;
-    border: 1px solid lightgrey;
-    border-collapse: collapse;
-    min-height: 300px;
-}
-
-h2 {
-    clear: both;
-    background: -moz-linear-gradient(-90deg, #f8f8f8, #e7e7e7);
-    background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#e7e7e7));
-    padding: 0 10px;
-    border-bottom: solid 1px lightgrey;
-}
-
-dl {
-    padding: 0 10px;
-}
-
-section > ul {
-}
-
-section > ul > li {
-    width: 100%;
-    display: table;
-}
-
-section > p {
-    border-top: solid 1px lightgrey;
-    margin: 0px;
-    padding: 0 10px;
-    text-align: center;
-}
-
-section > ul > li > h3 {
-    font-size: 1em;
-    font-weight: normal;
-    display: table-cell;
-    padding: 10px;
-}
-
-section .hidden {
-    color: #ccc;
-}
-
-section .hide {
-    display: table-cell;
-    padding: 0 10px;
-    width: 16px;
-    height: 16px;
-    background-image: url('visible.png');
-    background-repeat: no-repeat;
-    background-position: center center;
-}
-
-section .hide:hover {
-    background-image: url('visible-hover.png');
-}
-
-section .hidden .hide {
-    background-image: url('hidden.png');
-}
-
-section .hidden .hide:hover {
-    background-image: url('hidden-hover.png');
-}
-
-dt, dd {
-    display: table-cell;
-}
-
-dt {
-    text-align: right;
-    clear: both;
-}
-
-dt:after {
-    content: " : ";
-}
-
-dd {
-    text-indent: 0.5ex;
-}
-
-.counts dt {
-    width: 100px;
-}
-
-.counts dd {
-    width: 50px;
-}
-
-li.form {
-    padding: 0;
-    border-top: solid 1px lightgrey;
-}
-
-form {
-    text-align: right;
-    padding: 10px;
-}
-
-input {
-    width: 100%;
-    font-size: 14px;
-    border: solid 1px lightgrey;
-}
-
-form dt {
-    width: 70px;
-}
-
-form dd {
-    width: 150px;
-}
-
-#manual-submission form {
-    padding: 0;
-}
-#manual-submission textarea {
-    font-family: monospace;
-    font-size: 14px;
-    border: none;
-}
-
-#footer {
-    margin: 10px;
-}
diff --git a/Websites/webkit-perf.appspot.com/css/title.png b/Websites/webkit-perf.appspot.com/css/title.png
deleted file mode 100644 (file)
index 05928f7..0000000
Binary files a/Websites/webkit-perf.appspot.com/css/title.png and /dev/null differ
diff --git a/Websites/webkit-perf.appspot.com/index.yaml b/Websites/webkit-perf.appspot.com/index.yaml
deleted file mode 100644 (file)
index a3b9e05..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-indexes:
-
-# AUTOGENERATED
-
-# This index.yaml is automatically updated whenever the dev_appserver
-# detects that a new type of query is run.  If you want to manage the
-# index.yaml file manually, remove the above marker line (the line
-# saying "# AUTOGENERATED").  If you want to manage some indexes
-# manually, move them above the marker line.  The index.yaml file is
-# automatically uploaded to the admin console when you next deploy
-# your application using appcfg.py.
diff --git a/Websites/webkit-perf.appspot.com/js/admin.js b/Websites/webkit-perf.appspot.com/js/admin.js
deleted file mode 100644 (file)
index 00ef63e..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-function submitXHR(method, action, payload, callback) {
-    var xhr = new XMLHttpRequest;
-    xhr.onreadystatechange = function () {
-        if (xhr.readyState != 4)
-            return;
-        if (xhr.status != 200)
-            error('HTTP status: ' + xhr.status);
-        else if (xhr.responseText != 'OK')
-            error(xhr.responseText);
-        if (callback)
-            callback()
-    }
-    xhr.open(method, action, true);
-    xhr.send(payload);
-}
-
-function removeNonFormListItems(list) {
-    list.children().each(function () {
-        if ($.inArray('form', this.classList))
-            $(this).remove();
-    });
-}
-
-function createKeyNameReloader(name, visibilityAction, callback) {
-    return function () {
-        $.getJSON(name, function (entries) {
-            var list = $('#' + name + ' ul');
-            entries = sortProperties(entries);
-
-            $.each(entries, function (key, values) {
-                var label = key == values['name'] ? key : key + ' : ' + values['name'];
-                list.append('<li><h3 id="' + key + '">' + label + '</h3></li>');
-                var item = list[0].lastChild;
-
-                if (values['hidden'])
-                    item.className = 'hidden';
-
-                if (visibilityAction) {
-                    $(item).append(' <a class="hide"></a>');
-                    $(item.lastChild).click(function () {
-                        var json = {'hide': !this.parentNode.classList.contains('hidden')}
-                        json[visibilityAction] = this.parentNode.firstChild.id;
-
-                        submitXHR('POST', 'change-visibility', JSON.stringify(json));
-                        list.find('form').trigger('reload');
-                    });
-                }
-
-                if (callback)
-                    callback.call(item, values['hidden']);
-            });
-            list.append($('#' + name + ' ul .form'));
-        });
-    }
-}
-
-$('#branches form').bind('reload', createKeyNameReloader('branches'));
-$('#platforms form').bind('reload', createKeyNameReloader('platforms', 'platform'));
-
-$('#builders form').bind('reload', function () {
-    $.getJSON('builders', function (builders) {
-        var list = $('#builders ul');
-        removeNonFormListItems(list);
-        builders = builders.sort();
-        for (var i = 0; i < builders.length; i++)
-            list.append('<li><h3><a href="http://build.webkit.org/builders/' + builders[i] + '">' + builders[i] + '</a></h3></li>');
-        list.append($('#builders ul .form'));
-    });
-});
-
-var testReloader = createKeyNameReloader('tests', 'test', function (hidden) {
-    var testName = this.firstChild.id;
-    $('#tests select').append('<option value="' + testName + '">' + testName + '</option>');
-
-});
-$('#tests form').bind('reload', function () {
-    var select = $('#tests select');
-    select.children().remove();
-    testReloader();
-});
-
-$.ajaxSetup({
-    'error': function(xhr, e, message) { console.log(xhr); error('Failed with HTTP status: ' + xhr.status, e); },
-    cache: true,
-});
-
-$('form').trigger('reload');
-
-$('form').bind('submit', function (event) {
-    event.preventDefault();
-
-    var payload;
-    if (this.payload)
-        payload = this.payload.value;
-    else {
-        var contents = {};
-        for (var i = 0; i < this.elements.length; i++)
-            contents[this.elements[i].name] = this.elements[i].value;
-        payload = JSON.stringify(contents);
-    }
-
-    submitXHR(this.method, this.action, payload, function () {
-        $(this).trigger('reload');
-    })
-});
-
-$('#manual-submission textarea').val(JSON.stringify({
-    'branch': 'webkit-trunk',
-    'platform': 'chromium-mac',
-    'builder-name': 'Chromium Mac Release (Perf)',
-    'build-number': '123',
-    'timestamp': parseInt(Date.now() / 1000),
-    'webkit-revision': 104856,
-    'chromium-revision': 123059,
-    'results':
-        {
-            'webkit_style_test': {'avg': 100, 'median': 102, 'stdev': 5, 'min': 90, 'max': 110},
-            'some_test': 54,
-        },
-}, null, '  '));
diff --git a/Websites/webkit-perf.appspot.com/js/config.js b/Websites/webkit-perf.appspot.com/js/config.js
deleted file mode 100644 (file)
index 35c723a..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var USE_GENERATED_IMAGES_IN_DASHBOARD = true;
-var MAX_GRAPHS = 6;
-var MAX_CSETS = 100;
-var DAY = 86400000;
-
-var COLORS = ['#e7454c', '#6dba4b', '#4986cf', '#f5983d', '#884e9f', '#bf5c41'];
-
-// server for JSON performance data
-var SERVER = location.protocol.indexOf('http') == 0 ? location.protocol + '//' + location.host : 'http://webkit-perf.appspot.com';
-
-// server for static dashboard images
-var IMAGE_SERVER = SERVER;
-
-if ($.color) {
-    var LIGHT_COLORS = $.map(COLORS, function(color) {
-        return $.color.parse(color).add('a', -.5).toString();
-    });
-}
-
-var PLOT_OPTIONS = {
-    xaxis: { mode: 'time' },
-    crosshair: { mode: 'y' },
-    selection: { mode: 'xy', color: '#97c6e5' },
-    series: { shadowSize: 0 },
-    lines: { show: false },
-    points: { show: true },
-    grid: {
-        color: '#cdd6df',
-        borderWidth: 2,
-        backgroundColor: '#fff',
-        hoverable: true,
-        clickable: true,
-        autoHighlight: false
-    }
-};
-
-var OVERVIEW_OPTIONS = {
-    xaxis: { mode: 'time' },
-    selection: { mode: 'xy', color: '#97c6e5' },
-    series: {
-        lines: { show: true, lineWidth: 1 },
-        shadowSize: 0
-    },
-    grid: {
-        color: '#cdd6df',
-        borderWidth: 2,
-        backgroundColor: '#fff',
-        tickColor: 'rgba(0,0,0,0)'
-    }
-};
-
-var REPOSITORIES = ['WebKit', 'Chromium'];
-var DEFAULT_REPOSITORY = 'WebKit';
-
-function urlForChangeset(branch, changeset, repository)
-{
-    if (repository == 'Chromium')
-        return 'http://src.chromium.org/viewvc/chrome?view=rev&revision=' +
-               changeset;
-    else
-        return 'http://trac.webkit.org/changeset/' + changeset;
-}
-
-function urlForChangesetList(branch, changesetList, repository)
-{
-    var min = Math.min.apply(Math, changesetList);
-    var max = Math.max.apply(Math, changesetList);
-    if (repository == 'Chromium')
-        return 'http://build.chromium.org/f/chromium/perf/dashboard/ui/' +
-               'changelog.html?url=/trunk/src&mode=html&range=' + min + ':' +
-               max;
-    else
-        return 'http://trac.webkit.org/log/?rev=' + max + '&stop_rev=' + min +
-               '&verbose=on';
-}
-
-function sortProperties(object) {
-    var tests = Object.keys(object).sort();
-    var sortedObject = {};
-    for (var i = 0; i < tests.length; i++)
-        sortedObject[tests[i]] = object[tests[i]];
-    return sortedObject;
-}
-
-// FIXME move this back to dashboard.js once the bug 718925 is fixed
-function fetchDashboardManifest(callback)
-{
-    $.ajaxSetup({
-        'error': function(xhr, e, message) {
-            error('Could not download dashboard data from server', e);
-        },
-        cache: true,
-    });
-
-    $.getJSON(SERVER + '/api/test/dashboard', function (dashboardManifest) {
-        dashboardManifest['testToId'] = sortProperties(dashboardManifest['testToId']);
-        callback(dashboardManifest);
-    });
-}
-
-(function() {
-    $.ajaxSetup({
-        'error': function(xhr, e, message) {
-            error('Could not determine the the login status', e);
-        },
-        cache: true,
-    });
-
-    $.getJSON('/api/user/is-admin', function (isAdmin) {
-        if (isAdmin) {
-            $('#header nav').append('<a href="/admin/">Admin</a>');
-            if (!$('#header nav .selected').length) {
-                $('#header nav a').last().addClass('selected')
-            }
-        }
-    })
-})();
diff --git a/Websites/webkit-perf.appspot.com/json_generators.py b/Websites/webkit-perf.appspot.com/json_generators.py
deleted file mode 100644 (file)
index cea5080..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import json
-from datetime import datetime
-from datetime import timedelta
-from time import mktime
-
-from models import Build
-from models import Builder
-from models import Branch
-from models import Platform
-from models import Test
-from models import TestResult
-
-
-class JSONGeneratorBase(object):
-    def to_json(self):
-        return json.dumps(self.value())
-
-
-class DashboardJSONGenerator(JSONGeneratorBase):
-    def __init__(self):
-        # FIXME: Don't hard-code webkit-trunk here; ideally we want this be customizable.
-        webkit_trunk = Branch.get_by_key_name('webkit-trunk')
-        if not webkit_trunk:
-            self._dashboard = None
-            return
-
-        # FIXME: Determine popular branches, platforms, and tests
-        self._dashboard = {
-            'defaultBranch': 'WebKit trunk',
-            'branchToId': {webkit_trunk.name: webkit_trunk.id},
-            'platformToId': {},
-            'testToId': {},
-        }
-
-        for platform in Platform.all():
-            if not platform.hidden:
-                self._dashboard['platformToId'][platform.name] = platform.id
-
-        for test in Test.all():
-            if not test.hidden:
-                self._dashboard['testToId'][test.name] = test.id
-
-    def value(self):
-        return self._dashboard
-
-
-class ManifestJSONGenerator(JSONGeneratorBase):
-    def __init__(self):
-        # FIXME: This function is massive. Break it up
-        self._test_map = {}
-        platform_id_map = {}
-        branch_id_map = {}
-        for test in Test.all():
-            if test.hidden:
-                continue
-
-            branch_ids = [Branch.get(branch_key).id for branch_key in test.branches]
-            platform_ids = [Platform.get(platform_key).id for platform_key in test.platforms]
-            self._test_map[test.id] = {
-                'name': test.name,
-                'branchIds': branch_ids,
-                'platformIds': platform_ids,
-            }
-
-            for platform_id in platform_ids:
-                platform_id_map.setdefault(platform_id, {'tests': [], 'branches': []})
-                platform_id_map[platform_id]['tests'].append(test.id)
-                platform_id_map[platform_id]['branches'] += branch_ids
-
-            for branch_id in branch_ids:
-                branch_id_map.setdefault(branch_id, {'tests': [], 'platforms': []})
-                branch_id_map[branch_id]['tests'].append(test.id)
-                branch_id_map[branch_id]['platforms'] += platform_ids
-
-        self._platform_map = {}
-        for platform in Platform.all():
-            if platform.id not in platform_id_map:
-                continue
-
-            if platform.hidden:
-                for test_id in platform_id_map[platform.id]['tests']:
-                    self._test_map[test_id]['platformIds'].remove(platform.id)
-                for branch_id in platform_id_map[platform.id]['branches']:
-                    branch_id_map[branch_id]['platforms'].remove(platform.id)
-                continue
-
-            self._platform_map[platform.id] = {
-                'name': platform.name,
-                'testIds': list(set(platform_id_map[platform.id]['tests'])),
-                'branchIds': list(set(platform_id_map[platform.id]['branches'])),
-            }
-
-        self._branch_map = {}
-        for branch in Branch.all():
-            if branch.id not in branch_id_map:
-                continue
-            self._branch_map[branch.id] = {
-                'name': branch.name,
-                'testIds': list(set(branch_id_map[branch.id]['tests'])),
-                'platformIds': list(set(branch_id_map[branch.id]['platforms'])),
-            }
-
-    def value(self):
-        return {'branchMap': self._branch_map, 'platformMap': self._platform_map, 'testMap': self._test_map}
diff --git a/Websites/webkit-perf.appspot.com/json_generators_unittest.py b/Websites/webkit-perf.appspot.com/json_generators_unittest.py
deleted file mode 100644 (file)
index e54df05..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import json
-import models
-import unittest
-
-from google.appengine.ext import testbed
-from datetime import datetime
-from datetime import timedelta
-from json_generators import JSONGeneratorBase
-from json_generators import DashboardJSONGenerator
-from json_generators import ManifestJSONGenerator
-from models_unittest import DataStoreTestsBase
-from models import Branch
-from models import Build
-from models import Builder
-from models import Platform
-from models import Test
-from models import TestResult
-
-
-def _create_results(branch, platform, builder, test_name, values):
-    results = []
-    for i, value in enumerate(values):
-        build = Build(branch=branch, platform=platform, builder=builder,
-            buildNumber=i, revision=100 + i, timestamp=datetime.now())
-        build.put()
-        result = TestResult(name=test_name, build=build, value=value)
-        result.put()
-        Test.update_or_insert(test_name, branch, platform)
-        results.append(result)
-    return results
-
-
-class JSONGeneratorBaseTest(unittest.TestCase):
-    def test_to_json(self):
-
-        class AJSONGenerator(JSONGeneratorBase):
-            def value(self):
-                return {'key': 'value'}
-
-        self.assertEqual(AJSONGenerator().value(), {"key": "value"})
-        self.assertEqual(AJSONGenerator().to_json(), '{"key": "value"}')
-
-
-class DashboardJSONGeneratorTest(DataStoreTestsBase):
-    def test_value_no_branch(self):
-        self.assertThereIsNoInstanceOf(Branch)
-        self.assertEqual(DashboardJSONGenerator().value(), None)
-
-    def test_value_no_plaforms(self):
-        webkit_trunk = Branch.create_if_possible('webkit-trunk', 'WebKit trunk')
-        self.assertEqual(DashboardJSONGenerator().value(), {
-            'defaultBranch': 'WebKit trunk',
-            'branchToId': {'WebKit trunk': webkit_trunk.id},
-            'platformToId': {},
-            'testToId': {},
-        })
-
-    def test_value_single_platform(self):
-        webkit_trunk = Branch.create_if_possible('webkit-trunk', 'WebKit trunk')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        self.assertEqual(DashboardJSONGenerator().value(), {
-            'defaultBranch': 'WebKit trunk',
-            'branchToId': {'WebKit trunk': webkit_trunk.id},
-            'platformToId': {'Some Platform': some_platform.id},
-            'testToId': {},
-        })
-
-        Test.update_or_insert('some-test', webkit_trunk, some_platform)
-        self.assertEqual(DashboardJSONGenerator().value(), {
-            'defaultBranch': 'WebKit trunk',
-            'branchToId': {'WebKit trunk': webkit_trunk.id},
-            'platformToId': {'Some Platform': some_platform.id},
-            'testToId': {'some-test': Test.get_by_key_name('some-test').id},
-        })
-
-    def test_value_two_platforms(self):
-        webkit_trunk = Branch.create_if_possible('webkit-trunk', 'WebKit trunk')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        other_platform = Platform.create_if_possible('other-platform', 'Other Platform')
-        Test.update_or_insert('some-test', webkit_trunk, some_platform)
-        Test.update_or_insert('some-test', webkit_trunk, other_platform)
-        self.assertEqual(DashboardJSONGenerator().value(), {
-            'defaultBranch': 'WebKit trunk',
-            'branchToId': {'WebKit trunk': webkit_trunk.id},
-            'platformToId': {'Some Platform': some_platform.id, 'Other Platform': other_platform.id},
-            'testToId': {'some-test': Test.get_by_key_name('some-test').id},
-        })
-
-    def test_value_with_hidden_platform_and_tesst(self):
-        webkit_trunk = Branch.create_if_possible('webkit-trunk', 'WebKit trunk')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        hidden_platform = Platform.create_if_possible('hidden-platform', 'Hidden Platform')
-        hidden_platform.hidden = True
-        hidden_platform.put()
-        Test.update_or_insert('some-test', webkit_trunk, some_platform)
-        Test.update_or_insert('some-test', webkit_trunk, hidden_platform)
-        Test.update_or_insert('other-test', webkit_trunk, some_platform)
-        Test.update_or_insert('other-test', webkit_trunk, hidden_platform)
-        Test.update_or_insert('hidden-test', webkit_trunk, some_platform)
-        Test.update_or_insert('hidden-test', webkit_trunk, hidden_platform)
-        hidden_test = Test.get_by_key_name('hidden-test')
-        hidden_test.hidden = True
-        hidden_test.put()
-        self.assertEqual(DashboardJSONGenerator().value()['platformToId'], {'Some Platform': some_platform.id})
-        self.assertEqual(DashboardJSONGenerator().value()['testToId'],
-            {'some-test': Test.get_by_key_name('some-test').id, 'other-test': Test.get_by_key_name('other-test').id})
-
-
-class ManifestJSONGeneratorTest(DataStoreTestsBase):
-    def test_value_no_branch(self):
-        self.assertThereIsNoInstanceOf(Branch)
-        self.assertEqual(ManifestJSONGenerator().value(), {'branchMap': {}, 'platformMap': {}, 'testMap': {}})
-
-    def test_value_no_plaforms(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        self.assertEqual(ManifestJSONGenerator().value(), {'branchMap': {}, 'platformMap': {}, 'testMap': {}})
-
-    def _assert_single_test(self, value, branch, platform, test):
-        self.assertEqualUnorderedList(value.keys(), ['branchMap', 'platformMap', 'testMap'])
-        self.assertEqual(value['branchMap'],
-            {branch.id: {'name': branch.name, 'testIds': [test.id], 'platformIds': [platform.id]}})
-        self.assertEqual(value['platformMap'],
-            {platform.id: {'name': platform.name, 'branchIds': [branch.id], 'testIds': [test.id]}})
-        self.assertEqual(value['testMap'],
-            {test.id: {'name': test.name, 'branchIds': [branch.id], 'platformIds': [platform.id]}})
-
-    def test_value_single_platform(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        self.assertEqual(ManifestJSONGenerator().value(), {'branchMap': {}, 'platformMap': {}, 'testMap': {}})
-
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-        self._assert_single_test(ManifestJSONGenerator().value(), some_branch, some_platform, some_test)
-
-    def test_value_two_platforms(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        other_platform = Platform.create_if_possible('other-platform', 'Other Platform')
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-
-        self._assert_single_test(ManifestJSONGenerator().value(), some_branch, some_platform, some_test)
-
-        some_test = Test.update_or_insert('some-test', some_branch, other_platform)
-        self.assertEqualUnorderedList(some_test.platforms, [some_platform.key(), other_platform.key()])
-
-        value = ManifestJSONGenerator().value()
-        expected_platform_ids = [some_platform.id, other_platform.id]
-        self.assertEqualUnorderedList(value.keys(), ['branchMap', 'platformMap', 'testMap'])
-        self.assertEqualUnorderedList(value['branchMap'],
-            {some_branch.id: {'name': some_branch.name, 'testIds': [some_test.id], 'platformIds': expected_platform_ids}})
-        self.assertEqual(value['platformMap'],
-            {some_platform.id: {'name': some_platform.name, 'branchIds': [some_branch.id], 'testIds': [some_test.id]},
-            other_platform.id: {'name': other_platform.name, 'branchIds': [some_branch.id], 'testIds': [some_test.id]}})
-        self.assertEqual(value['testMap'],
-            {some_test.id: {'name': some_test.name, 'branchIds': [some_branch.id], 'platformIds': expected_platform_ids}})
-
-    def test_value_two_tests(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-
-        self._assert_single_test(ManifestJSONGenerator().value(), some_branch, some_platform, some_test)
-
-        other_test = Test.update_or_insert('other-test', some_branch, some_platform)
-
-        value = ManifestJSONGenerator().value()
-        expected_test_ids = [some_test.id, other_test.id]
-        self.assertEqualUnorderedList(value.keys(), ['branchMap', 'platformMap', 'testMap'])
-        self.assertEqual(value['branchMap'],
-            {some_branch.id: {'name': some_branch.name, 'testIds': expected_test_ids, 'platformIds': [some_platform.id]}})
-        self.assertEqual(value['platformMap'],
-            {some_platform.id: {'name': some_platform.name, 'branchIds': [some_branch.id], 'testIds': expected_test_ids}})
-        self.assertEqual(value['testMap'],
-            {some_test.id: {'name': some_test.name, 'branchIds': [some_branch.id], 'platformIds': [some_platform.id]},
-            other_test.id: {'name': other_test.name, 'branchIds': [some_branch.id], 'platformIds': [some_platform.id]}})
-
-    def test_value_with_hidden_platform_and_test(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        hidden_platform = Platform.create_if_possible('hidden-platform', 'Hidden Platform')
-        hidden_platform.hidden = True
-        hidden_platform.put()
-
-        Test.update_or_insert('some-test', some_branch, some_platform)
-        some_test = Test.update_or_insert('some-test', some_branch, hidden_platform)
-
-        Test.update_or_insert('hidden-test', some_branch, some_platform)
-        hidden_test = Test.update_or_insert('hidden-test', some_branch, hidden_platform)
-        hidden_test.hidden = True
-        hidden_test.put()
-
-        value = ManifestJSONGenerator().value()
-        expected_test_ids = []
-        self.assertEqualUnorderedList(value.keys(), ['branchMap', 'platformMap', 'testMap'])
-        self.assertEqual(value['branchMap'],
-            {some_branch.id: {'name': some_branch.name, 'testIds': [some_test.id], 'platformIds': [some_platform.id]}})
-        self.assertEqual(value['platformMap'],
-            {some_platform.id: {'name': some_platform.name, 'branchIds': [some_branch.id], 'testIds': [some_test.id]}})
-        self.assertEqual(value['testMap'],
-            {some_test.id: {'name': some_test.name, 'branchIds': [some_branch.id], 'platformIds': [some_platform.id]}})
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/Websites/webkit-perf.appspot.com/main.py b/Websites/webkit-perf.appspot.com/main.py
deleted file mode 100644 (file)
index 889d7b8..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2007, 2011 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-import webapp2
-from google.appengine.ext.webapp import util
-
-import json
-
-from admin_handlers import AdminDashboardHandler
-from admin_handlers import ChangeVisibilityHandler
-from admin_handlers import IsAdminHandler
-from admin_handlers import MergeTestsHandler
-from controller import CachedDashboardHandler
-from controller import CachedManifestHandler
-from controller import CachedRunsHandler
-from controller import DashboardImageHandler
-from controller import DashboardUpdateHandler
-from controller import ManifestUpdateHandler
-from controller import RunsChartHandler
-from controller import RunsUpdateHandler
-from create_handler import CreateHandler
-from report_handler import ReportHandler
-from report_handler import AdminReportHandler
-from report_process_handler import ReportProcessHandler
-from report_logs_handler import ReportLogsHandler
-
-routes = [
-    ('/admin/report/?', AdminReportHandler),
-    (r'/admin/merge-tests(?:/(.*))?', MergeTestsHandler),
-    ('/admin/report-logs/?', ReportLogsHandler),
-    ('/admin/create/(.*)', CreateHandler),
-    ('/admin/change-visibility/?', ChangeVisibilityHandler),
-    (r'/admin/([A-Za-z\-]*)', AdminDashboardHandler),
-
-    ('/api/user/is-admin', IsAdminHandler),
-    ('/api/test/?', CachedManifestHandler),
-    ('/api/test/update', ManifestUpdateHandler),
-    ('/api/test/report/?', ReportHandler),
-    ('/api/test/report/process', ReportProcessHandler),
-    ('/api/test/runs/?', CachedRunsHandler),
-    ('/api/test/runs/update', RunsUpdateHandler),
-    ('/api/test/runs/chart', RunsChartHandler),
-    ('/api/test/dashboard/?', CachedDashboardHandler),
-    ('/api/test/dashboard/update', DashboardUpdateHandler),
-
-    ('/images/dashboard/flot-(\d+)-(\d+)-(\d+)_(\d+).png', DashboardImageHandler)]
-
-
-def main():
-    application = webapp2.WSGIApplication(routes, debug=True)
-    util.run_wsgi_app(application)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/Websites/webkit-perf.appspot.com/models.py b/Websites/webkit-perf.appspot.com/models.py
deleted file mode 100644 (file)
index 50e458c..0000000
+++ /dev/null
@@ -1,540 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import hashlib
-import json
-import math
-import re
-
-from datetime import datetime
-from datetime import timedelta
-from google.appengine.ext import db
-from google.appengine.api import memcache
-from time import mktime
-
-
-class NumericIdHolder(db.Model):
-    owner = db.ReferenceProperty()
-    # Dummy class whose sole purpose is to generate key().id()
-
-
-def create_in_transaction_with_numeric_id_holder(callback):
-    id_holder = NumericIdHolder()
-    id_holder.put()
-    id_holder = NumericIdHolder.get(id_holder.key())
-    owner = None
-    try:
-        owner = db.run_in_transaction(callback, id_holder.key().id())
-        if owner:
-            id_holder.owner = owner
-            id_holder.put()
-    finally:
-        if not owner:
-            id_holder.delete()
-    return owner
-
-
-def delete_model_with_numeric_id_holder(model):
-    id_holder = NumericIdHolder.get_by_id(model.id)
-    model.delete()
-    id_holder.delete()
-
-
-def model_from_numeric_id(id, expected_kind):
-    id_holder = NumericIdHolder.get_by_id(id)
-    return id_holder.owner if id_holder and id_holder.owner and isinstance(id_holder.owner, expected_kind) else None
-
-
-def _create_if_possible(model, key, name):
-
-    def execute(id):
-        if model.get_by_key_name(key):
-            return None
-        branch = model(id=id, name=name, key_name=key)
-        branch.put()
-        return branch
-
-    return create_in_transaction_with_numeric_id_holder(execute)
-
-
-class Branch(db.Model):
-    id = db.IntegerProperty(required=True)
-    name = db.StringProperty(required=True)
-
-    @staticmethod
-    def create_if_possible(key, name):
-        return _create_if_possible(Branch, key, name)
-
-
-class Platform(db.Model):
-    id = db.IntegerProperty(required=True)
-    name = db.StringProperty(required=True)
-    hidden = db.BooleanProperty()
-
-    @staticmethod
-    def create_if_possible(key, name):
-        return _create_if_possible(Platform, key, name)
-
-
-class Builder(db.Model):
-    name = db.StringProperty(required=True)
-    password = db.StringProperty(required=True)
-
-    @staticmethod
-    def create(name, raw_password):
-        return Builder(name=name, password=Builder._hashed_password(raw_password), key_name=name).put()
-
-    def update_password(self, raw_password):
-        self.password = Builder._hashed_password(raw_password)
-        self.put()
-
-    def authenticate(self, raw_password):
-        return self.password == hashlib.sha256(raw_password).hexdigest()
-
-    @staticmethod
-    def _hashed_password(raw_password):
-        return hashlib.sha256(raw_password).hexdigest()
-
-
-class Build(db.Model):
-    branch = db.ReferenceProperty(Branch, required=True, collection_name='build_branch')
-    platform = db.ReferenceProperty(Platform, required=True, collection_name='build_platform')
-    builder = db.ReferenceProperty(Builder, required=True, collection_name='builder_key')
-    buildNumber = db.IntegerProperty(required=True)
-    revision = db.IntegerProperty(required=True)
-    chromiumRevision = db.IntegerProperty()
-    timestamp = db.DateTimeProperty(required=True)
-
-    @staticmethod
-    def get_or_insert_from_log(log):
-        builder = log.builder()
-        key_name = builder.name + ':' + str(int(mktime(log.timestamp().timetuple())))
-
-        return Build.get_or_insert(key_name, branch=log.branch(), platform=log.platform(), builder=builder,
-            buildNumber=log.build_number(), timestamp=log.timestamp(),
-            revision=log.webkit_revision(), chromiumRevision=log.chromium_revision())
-
-
-class Test(db.Model):
-    id = db.IntegerProperty(required=True)
-    name = db.StringProperty(required=True)
-    # FIXME: Storing branches and platforms separately is flawed since a test maybe available on
-    # one platform but only on some branch and vice versa.
-    branches = db.ListProperty(db.Key)
-    platforms = db.ListProperty(db.Key)
-    unit = db.StringProperty()
-    hidden = db.BooleanProperty()
-
-    @staticmethod
-    def update_or_insert(test_name, branch, platform, unit=None):
-        existing_test = [None]
-
-        def execute(id):
-            test = Test.get_by_key_name(test_name)
-            if test:
-                if branch.key() not in test.branches:
-                    test.branches.append(branch.key())
-                if platform.key() not in test.platforms:
-                    test.platforms.append(platform.key())
-                test.unit = unit
-                test.put()
-                existing_test[0] = test
-                return None
-
-            test = Test(id=id, name=test_name, key_name=test_name, unit=unit, branches=[branch.key()], platforms=[platform.key()])
-            test.put()
-            return test
-
-        return create_in_transaction_with_numeric_id_holder(execute) or existing_test[0]
-
-    def merge(self, other):
-        assert self.key() != other.key()
-
-        merged_results = TestResult.all()
-        merged_results.filter('name =', other.name)
-
-        # FIXME: We should be doing this check in a transaction but only ancestor queries are allowed
-        for result in merged_results:
-            if TestResult.get_by_key_name(TestResult.key_name(result.build, self.name)):
-                return None
-
-        branches_and_platforms_to_update = set()
-        for result in merged_results:
-            branches_and_platforms_to_update.add((result.build.branch.id, result.build.platform.id))
-            result.replace_to_change_test_name(self.name)
-
-        delete_model_with_numeric_id_holder(other)
-
-        return branches_and_platforms_to_update
-
-
-class TestResult(db.Model):
-    name = db.StringProperty(required=True)
-    build = db.ReferenceProperty(Build, required=True)
-    value = db.FloatProperty(required=True)
-    valueMedian = db.FloatProperty()
-    valueStdev = db.FloatProperty()
-    valueMin = db.FloatProperty()
-    valueMax = db.FloatProperty()
-    values = db.ListProperty(float)
-
-    @staticmethod
-    def key_name(build, test_name):
-        return build.key().name() + ':' + test_name
-
-    @classmethod
-    def get_or_insert_from_parsed_json(cls, test_name, build, result):
-        key_name = cls.key_name(build, test_name)
-
-        def _float_or_none(dictionary, key):
-            value = dictionary.get(key)
-            if value:
-                return float(value)
-            return None
-
-        if not isinstance(result, dict):
-            return cls.get_or_insert(key_name, name=test_name, build=build, value=float(result))
-
-        return cls.get_or_insert(key_name, name=test_name, build=build, value=float(result['avg']),
-            valueMedian=_float_or_none(result, 'median'), valueStdev=_float_or_none(result, 'stdev'),
-            valueMin=_float_or_none(result, 'min'), valueMax=_float_or_none(result, 'max'),
-            values=result.get('values', []))
-
-    def replace_to_change_test_name(self, new_name):
-        clone = TestResult(key_name=TestResult.key_name(self.build, new_name), name=new_name, build=self.build,
-            value=self.value, valueMedian=self.valueMedian, valueStdev=self.valueMin, valueMin=self.valueMin, valueMax=self.valueMax)
-        clone.put()
-        self.delete()
-        return clone
-
-
-class ReportLog(db.Model):
-    timestamp = db.DateTimeProperty(required=True)
-    headers = db.TextProperty()
-    payload = db.TextProperty()
-    commit = db.BooleanProperty()
-
-    def _parsed_payload(self):
-        if self.__dict__.get('_parsed') == None:
-            try:
-                self._parsed = json.loads(self.payload)
-            except ValueError:
-                self._parsed = False
-        return self._parsed
-
-    def get_value(self, keyName):
-        parsed = self._parsed_payload()
-        if not parsed:
-            return None
-        if isinstance(parsed, list):
-            parsed = parsed[0]
-        return parsed.get(keyName)
-
-    def results(self):
-        return self.get_value('results')
-
-    def results_are_well_formed(self):
-
-        def _is_float_convertible(value):
-            try:
-                float(value)
-                return True
-            except TypeError:
-                return False
-            except ValueError:
-                return False
-
-        if isinstance(self._parsed_payload(), list) and len(self._parsed_payload()) != 1:
-            return False
-
-        if not isinstance(self.results(), dict):
-            return False
-
-        for testResult in self.results().values():
-            if isinstance(testResult, dict):
-                for key, value in testResult.iteritems():
-                    if key == "values":
-                        if not isinstance(value, list):
-                            return False
-                        for item in value:
-                            if not _is_float_convertible(item):
-                                return False
-                    elif key != "unit" and not _is_float_convertible(value):
-                        return False
-                if 'avg' not in testResult:
-                    return False
-                continue
-            if not _is_float_convertible(testResult):
-                return False
-
-        return True
-
-    def builder(self):
-        return self._model_by_key_name_in_payload(Builder, 'builder-name')
-
-    def branch(self):
-        return self._model_by_key_name_in_payload(Branch, 'branch')
-
-    def platform(self):
-        return self._model_by_key_name_in_payload(Platform, 'platform')
-
-    def build_number(self):
-        return self._integer_in_payload('build-number')
-
-    def webkit_revision(self):
-        return self._integer_in_payload('webkit-revision')
-
-    def chromium_revision(self):
-        return self._integer_in_payload('chromium-revision')
-
-    def _model_by_key_name_in_payload(self, model, keyName):
-        key = self.get_value(keyName)
-        if not key:
-            return None
-        return model.get_by_key_name(key)
-
-    def _integer_in_payload(self, keyName):
-        try:
-            return int(self.get_value(keyName))
-        except TypeError:
-            return None
-        except ValueError:
-            return None
-
-    # FIXME: We also have timestamp as a member variable.
-    def timestamp(self):
-        try:
-            return datetime.fromtimestamp(self._integer_in_payload('timestamp'))
-        except TypeError:
-            return None
-        except ValueError:
-            return None
-
-
-class PersistentCache(db.Model):
-    value = db.TextProperty(required=True)
-
-    @staticmethod
-    def set_cache(name, value):
-        memcache.set(name, value)
-        PersistentCache(key_name=name, value=value).put()
-
-    @staticmethod
-    def get_cache(name):
-        value = memcache.get(name)
-        if value:
-            return value
-        cache = PersistentCache.get_by_key_name(name)
-        if not cache:
-            return None
-        memcache.set(name, cache.value)
-        return cache.value
-
-
-class Runs(db.Model):
-    branch = db.ReferenceProperty(Branch, required=True, collection_name='runs_branch')
-    platform = db.ReferenceProperty(Platform, required=True, collection_name='runs_platform')
-    test = db.ReferenceProperty(Test, required=True, collection_name='runs_test')
-    json_runs = db.TextProperty()
-    json_averages = db.TextProperty()
-    json_min = db.FloatProperty()
-    json_max = db.FloatProperty()
-
-    @staticmethod
-    def _generate_runs(branch, platform, test_name):
-        builds = Build.all()
-        builds.filter('branch =', branch)
-        builds.filter('platform =', platform)
-
-        for build in builds:
-            results = TestResult.all()
-            results.filter('name =', test_name)
-            results.filter('build =', build)
-            for result in results:
-                yield build, result
-        raise StopIteration
-
-    @staticmethod
-    def _entry_from_build_and_result(build, result):
-        builder_id = build.builder.key().id()
-        timestamp = mktime(build.timestamp.timetuple())
-        statistics = None
-        supplementary_revisions = None
-
-        if result.valueStdev != None and result.valueMin != None and result.valueMax != None:
-            statistics = {'stdev': result.valueStdev, 'min': result.valueMin, 'max': result.valueMax}
-
-        if build.chromiumRevision != None:
-            supplementary_revisions = {'Chromium': build.chromiumRevision}
-
-        return [result.key().id(),
-            [build.key().id(), build.buildNumber, build.revision, supplementary_revisions],
-            timestamp, result.value, 0,  # runNumber
-            [],  # annotations
-            builder_id, statistics]
-
-    @staticmethod
-    def _timestamp_and_value_from_json_entry(json_entry):
-        return json_entry[2], json_entry[3]
-
-    @staticmethod
-    def _key_name(branch_id, platform_id, test_id):
-        return 'runs:%d,%d,%d' % (test_id, branch_id, platform_id)
-
-    @classmethod
-    def update_or_insert(cls, branch, platform, test):
-        key_name = cls._key_name(branch.id, platform.id, test.id)
-        runs = Runs(key_name=key_name, branch=branch, platform=platform, test=test, json_runs='', json_averages='')
-
-        for build, result in cls._generate_runs(branch, platform, test.name):
-            runs.update_incrementally(build, result, check_duplicates_and_save=False)
-
-        runs.put()
-        memcache.set(key_name, runs.to_json())
-        return runs
-
-    def update_incrementally(self, build, result, check_duplicates_and_save=True):
-        new_entry = Runs._entry_from_build_and_result(build, result)
-
-        # Check for duplicate entries
-        if check_duplicates_and_save:
-            revision_is_in_runs = str(build.revision) in json.loads('{' + self.json_averages + '}')
-            if revision_is_in_runs and new_entry[1] in [entry[1] for entry in json.loads('[' + self.json_runs + ']')]:
-                return
-
-        if self.json_runs:
-            self.json_runs += ','
-
-        if self.json_averages:
-            self.json_averages += ','
-
-        self.json_runs = (self.json_runs + json.dumps(new_entry)).replace(', ', ',')
-        # FIXME: Calculate the average. In practice, we wouldn't have more than one value for a given revision.
-        self.json_averages = (self.json_averages + '"%d":%f' % (build.revision, result.value)).replace(', ', ',')
-        self.json_min = min(self.json_min, result.value) if self.json_min != None else result.value
-        self.json_max = max(self.json_max, result.value)
-
-        if check_duplicates_and_save:
-            self.put()
-            memcache.set(self.key().name(), self.to_json())
-
-    @staticmethod
-    def get_by_objects(branch, platform, test):
-        return Runs.get_by_key_name(Runs._key_name(branch.id, platform.id, test.id))
-
-    @classmethod
-    def json_by_ids(cls, branch_id, platform_id, test_id):
-        key_name = cls._key_name(branch_id, platform_id, test_id)
-        runs_json = memcache.get(key_name)
-        if not runs_json:
-            runs = cls.get_by_key_name(key_name)
-            if not runs:
-                return None
-            runs_json = runs.to_json()
-            memcache.set(key_name, runs_json)
-        return runs_json
-
-    def to_json(self):
-        # date_range is never used by common.js.
-        return '{"test_runs": [%s], "averages": {%s}, "min": %s, "max": %s, "unit": %s, "date_range": null, "stat": "ok"}' % (self.json_runs,
-            self.json_averages, str(self.json_min) if self.json_min else 'null', str(self.json_max) if self.json_max else 'null',
-            '"%s"' % self.test.unit if self.test.unit else 'null')
-
-    def chart_params(self, display_days):
-        chart_data_x = []
-        chart_data_y = []
-        timestamp_from_entry = lambda entry: Runs._timestamp_and_value_from_json_entry(entry)[0]
-        runs = sorted(json.loads('[' + self.json_runs + ']'), lambda a, b: int(timestamp_from_entry(a) - timestamp_from_entry(b)))
-        if not runs:
-            return None
-
-        end_timestamp = timestamp_from_entry(runs[-1])
-        start_timestamp = end_timestamp - display_days * 24 * 3600
-        for entry in runs:
-            timestamp, value = Runs._timestamp_and_value_from_json_entry(entry)
-            if timestamp < start_timestamp or timestamp > end_timestamp:
-                continue
-            chart_data_x.append(timestamp)
-            chart_data_y.append(value)
-
-        dates = [datetime.fromtimestamp(end_timestamp) - timedelta(display_days / 7.0 * (7 - i)) for i in range(0, 8)]
-
-        y_max = max(chart_data_y) * 1.1
-        y_axis_label_step = int(y_max / 5 + 0.5)  # This won't work for decimal numbers
-
-        return {
-            'cht': 'lxy',  # Specify with X and Y coordinates
-            'chxt': 'x,y',  # Display both X and Y axies
-            'chxl': '0:|' + '|'.join([date.strftime('%b %d') for date in dates]),  # X-axis labels
-            'chxr': '1,0,%f,%f' % (int(y_max + 0.5), y_axis_label_step),  # Y-axis range: min=0, max, step
-            'chds': '%f,%f,%f,%f' % (start_timestamp, end_timestamp, 0, y_max),  # X, Y data range
-            'chxs': '1,676767,11.167,0,l,676767',  # Y-axis label: 1,color,font-size,centerd on tick,axis line/no ticks, tick color
-            'chs': '360x240',  # Image size: 360px by 240px
-            'chco': 'ff0000',  # Plot line color
-            'chg': '%f,20,0,0' % (100 / (len(dates) - 1)),  # X, Y grid line step sizes - max is 100.
-            'chls': '3',  # Line thickness
-            'chf': 'bg,s,eff6fd',  # Transparent background
-            'chd': 't:' + ','.join([str(x) for x in chart_data_x]) + '|' + ','.join([str(y) for y in chart_data_y]),  # X, Y data
-        }
-
-
-class DashboardImage(db.Model):
-    image = db.BlobProperty(required=True)
-    createdAt = db.DateTimeProperty(required=True, auto_now=True)
-
-    @staticmethod
-    def create(branch_id, platform_id, test_id, display_days, image):
-        key_name = DashboardImage.key_name(branch_id, platform_id, test_id, display_days)
-        instance = DashboardImage(key_name=key_name, image=image)
-        instance.put()
-        memcache.set('dashboard-image:' + key_name, image)
-        return instance
-
-    @staticmethod
-    def get_image(branch_id, platform_id, test_id, display_days):
-        key_name = DashboardImage.key_name(branch_id, platform_id, test_id, display_days)
-        image = memcache.get('dashboard-image:' + key_name)
-        if not image:
-            instance = DashboardImage.get_by_key_name(key_name)
-            image = instance.image if instance else None
-            memcache.set('dashboard-image:' + key_name, image)
-        return image
-
-    @classmethod
-    def needs_update(cls, branch_id, platform_id, test_id, display_days, now=datetime.now()):
-        if display_days < 10:
-            return True
-        image = DashboardImage.get_by_key_name(cls.key_name(branch_id, platform_id, test_id, display_days))
-        duration = math.sqrt(display_days) / 10
-        # e.g. 13 hours for 30 days, 23 hours for 90 days, and 46 hours for 365 days
-        return not image or image.createdAt < now - timedelta(duration)
-
-    @staticmethod
-    def key_name(branch_id, platform_id, test_id, display_days):
-        return '%d:%d:%d:%d' % (branch_id, platform_id, test_id, display_days)
diff --git a/Websites/webkit-perf.appspot.com/models_unittest.py b/Websites/webkit-perf.appspot.com/models_unittest.py
deleted file mode 100644 (file)
index 0014e08..0000000
+++ /dev/null
@@ -1,882 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import json
-import models
-import unittest
-
-from datetime import datetime
-from datetime import timedelta
-from google.appengine.api import memcache
-from google.appengine.ext import testbed
-from time import mktime
-
-from models import NumericIdHolder
-from models import Branch
-from models import Platform
-from models import Builder
-from models import Build
-from models import Test
-from models import TestResult
-from models import ReportLog
-from models import PersistentCache
-from models import Runs
-from models import DashboardImage
-from models import create_in_transaction_with_numeric_id_holder
-from models import delete_model_with_numeric_id_holder
-from models import model_from_numeric_id
-
-
-class DataStoreTestsBase(unittest.TestCase):
-    def setUp(self):
-        self.testbed = testbed.Testbed()
-        self.testbed.activate()
-        self.testbed.init_datastore_v3_stub()
-
-    def tearDown(self):
-        self.testbed.deactivate()
-
-    def assertThereIsNoInstanceOf(self, model):
-        self.assertEqual(len(model.all().fetch(5)), 0)
-
-    def assertOnlyInstance(self, only_instasnce):
-        self.assertOnlyInstances([only_instasnce])
-
-    def assertOnlyInstances(self, expected_instances):
-        actual_instances = expected_instances[0].__class__.all().fetch(len(expected_instances) + 1)
-        self.assertEqualUnorderedModelList(actual_instances, expected_instances)
-
-    def assertEqualUnorderedModelList(self, list1, list2):
-        self.assertEqualUnorderedList([item.key() for item in list1], [item.key() for item in list1])
-
-    def assertEqualUnorderedList(self, list1, list2):
-        self.assertEqual(set(list1), set(list2))
-        self.assertEqual(len(list1), len(list2))
-
-
-class HelperTests(DataStoreTestsBase):
-    def _assert_there_is_exactly_one_id_holder_and_matches(self, id):
-        id_holders = NumericIdHolder.all().fetch(5)
-        self.assertEqual(len(id_holders), 1)
-        self.assertTrue(id_holders[0])
-        self.assertEqual(id_holders[0].key().id(), id)
-
-    def test_create_in_transaction_with_numeric_id_holder(self):
-
-        def execute(id):
-            return Branch(id=id, name='some branch', key_name='some-branch').put()
-
-        self.assertThereIsNoInstanceOf(Branch)
-        self.assertThereIsNoInstanceOf(NumericIdHolder)
-
-        self.assertTrue(create_in_transaction_with_numeric_id_holder(execute))
-
-        branches = Branch.all().fetch(5)
-        self.assertEqual(len(branches), 1)
-        self.assertEqual(branches[0].name, 'some branch')
-        self.assertEqual(branches[0].key().name(), 'some-branch')
-
-        self._assert_there_is_exactly_one_id_holder_and_matches(branches[0].id)
-
-    def test_failing_in_create_in_transaction_with_numeric_id_holder(self):
-
-        def execute(id):
-            return None
-
-        self.assertThereIsNoInstanceOf(Branch)
-        self.assertThereIsNoInstanceOf(NumericIdHolder)
-
-        self.assertFalse(create_in_transaction_with_numeric_id_holder(execute))
-
-        self.assertThereIsNoInstanceOf(Branch)
-        self.assertThereIsNoInstanceOf(NumericIdHolder)
-
-    def test_raising_in_create_in_transaction_with_numeric_id_holder(self):
-
-        def execute(id):
-            raise TypeError
-            return None
-
-        self.assertThereIsNoInstanceOf(Branch)
-        self.assertThereIsNoInstanceOf(NumericIdHolder)
-
-        self.assertRaises(TypeError, create_in_transaction_with_numeric_id_holder, (execute))
-
-        self.assertThereIsNoInstanceOf(Branch)
-        self.assertThereIsNoInstanceOf(NumericIdHolder)
-
-    def test_delete_model_with_numeric_id_holder(self):
-
-        def execute(id):
-            return Branch(id=id, name='some branch', key_name='some-branch').put()
-
-        branch = Branch.get(create_in_transaction_with_numeric_id_holder(execute))
-        self.assertOnlyInstance(branch)
-
-        delete_model_with_numeric_id_holder(branch)
-
-        self.assertThereIsNoInstanceOf(Branch)
-        self.assertThereIsNoInstanceOf(NumericIdHolder)
-
-    def test_model_from_numeric_id(self):
-
-        def execute(id):
-            return Branch(id=id, name='some branch', key_name='some-branch').put()
-
-        branch = Branch.get(create_in_transaction_with_numeric_id_holder(execute))
-
-        self.assertEqual(model_from_numeric_id(branch.id, Branch).key(), branch.key())
-        self.assertEqual(model_from_numeric_id(branch.id + 1, Branch), None)
-        delete_model_with_numeric_id_holder(branch)
-        self.assertEqual(model_from_numeric_id(branch.id, Branch), None)
-
-
-class BranchTests(DataStoreTestsBase):
-    def test_create_if_possible(self):
-        self.assertThereIsNoInstanceOf(Branch)
-
-        branch = Branch.create_if_possible('some-branch', 'some branch')
-        self.assertTrue(branch)
-        self.assertTrue(branch.key().name(), 'some-branch')
-        self.assertTrue(branch.name, 'some branch')
-        self.assertOnlyInstance(branch)
-
-        self.assertFalse(Branch.create_if_possible('some-branch', 'some other branch'))
-        self.assertTrue(branch.name, 'some branch')
-        self.assertOnlyInstance(branch)
-
-
-class PlatformTests(DataStoreTestsBase):
-    def test_create_if_possible(self):
-        self.assertThereIsNoInstanceOf(Platform)
-
-        platform = Platform.create_if_possible('some-platform', 'some platform')
-        self.assertTrue(platform)
-        self.assertTrue(platform.key().name(), 'some-platform')
-        self.assertTrue(platform.name, 'some platform')
-        self.assertOnlyInstance(platform)
-
-        self.assertFalse(Platform.create_if_possible('some-platform', 'some other platform'))
-        self.assertTrue(platform.name, 'some platform')
-        self.assertOnlyInstance(platform)
-
-
-class BuilderTests(DataStoreTestsBase):
-    def test_create(self):
-        builder_key = Builder.create('some builder', 'some password')
-        self.assertTrue(builder_key)
-        builder = Builder.get(builder_key)
-        self.assertEqual(builder.key().name(), 'some builder')
-        self.assertEqual(builder.name, 'some builder')
-        self.assertEqual(builder.password, Builder._hashed_password('some password'))
-
-    def test_update_password(self):
-        builder = Builder.get(Builder.create('some builder', 'some password'))
-        self.assertEqual(builder.password, Builder._hashed_password('some password'))
-        builder.update_password('other password')
-        self.assertEqual(builder.password, Builder._hashed_password('other password'))
-
-        # Make sure it's saved
-        builder = Builder.get(builder.key())
-        self.assertEqual(builder.password, Builder._hashed_password('other password'))
-
-    def test_hashed_password(self):
-        self.assertNotEqual(Builder._hashed_password('some password'), 'some password')
-        self.assertFalse('some password' in Builder._hashed_password('some password'))
-        self.assertEqual(len(Builder._hashed_password('some password')), 64)
-
-    def test_authenticate(self):
-        builder = Builder.get(Builder.create('some builder', 'some password'))
-        self.assertTrue(builder.authenticate('some password'))
-        self.assertFalse(builder.authenticate('bad password'))
-
-
-def _create_some_builder():
-    branch = Branch.create_if_possible('some-branch', 'Some Branch')
-    platform = Platform.create_if_possible('some-platform', 'Some Platform')
-    builder_key = Builder.create('some-builder', 'Some Builder')
-    return branch, platform, Builder.get(builder_key)
-
-
-def _create_build(branch, platform, builder, key_name='some-build'):
-    build_key = Build(key_name=key_name, branch=branch, platform=platform, builder=builder,
-        buildNumber=1, revision=100, timestamp=datetime.now()).put()
-    return Build.get(build_key)
-
-
-class BuildTests(DataStoreTestsBase):
-    def test_get_or_insert_from_log(self):
-        branch, platform, builder = _create_some_builder()
-
-        timestamp = datetime.now().replace(microsecond=0)
-        log = ReportLog(timestamp=timestamp, headers='some headers',
-            payload='{"branch": "some-branch", "platform": "some-platform", "builder-name": "some-builder",' +
-                '"build-number": 123, "webkit-revision": 456, "timestamp": %d}' % int(mktime(timestamp.timetuple())))
-
-        self.assertThereIsNoInstanceOf(Build)
-
-        build = Build.get_or_insert_from_log(log)
-        self.assertTrue(build)
-        self.assertEqual(build.branch.key(), branch.key())
-        self.assertEqual(build.platform.key(), platform.key())
-        self.assertEqual(build.builder.key(), builder.key())
-        self.assertEqual(build.buildNumber, 123)
-        self.assertEqual(build.revision, 456)
-        self.assertEqual(build.chromiumRevision, None)
-        self.assertEqual(build.timestamp, timestamp)
-
-        self.assertOnlyInstance(build)
-
-
-class TestModelTests(DataStoreTestsBase):
-    def test_update_or_insert(self):
-        branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        platform = Platform.create_if_possible('some-platform', 'Some Platform')
-
-        self.assertThereIsNoInstanceOf(Test)
-
-        test = Test.update_or_insert('some-test', branch, platform)
-        self.assertTrue(test)
-        self.assertEqual(test.branches, [branch.key()])
-        self.assertEqual(test.platforms, [platform.key()])
-        self.assertEqual(test.unit, None)
-        self.assertOnlyInstance(test)
-
-    def test_update_or_insert_with_unit(self):
-        branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        test = Test.update_or_insert('some-test', branch, platform, 'runs/s')
-        self.assertOnlyInstance(test)
-        self.assertEqualUnorderedList(test.unit, 'runs/s')
-
-    def test_update_or_insert_to_update(self):
-        branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        test = Test.update_or_insert('some-test', branch, platform)
-        self.assertOnlyInstance(test)
-
-        other_branch = Branch.create_if_possible('other-branch', 'Other Branch')
-        other_platform = Platform.create_if_possible('other-platform', 'Other Platform')
-        test = Test.update_or_insert('some-test', other_branch, other_platform, 'ms')
-        self.assertOnlyInstance(test)
-        self.assertEqualUnorderedList(test.branches, [branch.key(), other_branch.key()])
-        self.assertEqualUnorderedList(test.platforms, [platform.key(), other_platform.key()])
-        self.assertEqualUnorderedList(test.unit, 'ms')
-
-    def test_merge(self):
-        branch, platform, builder = _create_some_builder()
-        some_build = _create_build(branch, platform, builder)
-        some_result = TestResult.get_or_insert_from_parsed_json('some-test', some_build, 50)
-        some_test = Test.update_or_insert('some-test', branch, platform)
-
-        other_build = _create_build(branch, platform, builder, 'other-build')
-        other_result = TestResult.get_or_insert_from_parsed_json('other-test', other_build, 30)
-        other_test = Test.update_or_insert('other-test', branch, platform)
-
-        self.assertOnlyInstances([some_result, other_result])
-        self.assertNotEqual(some_result.key(), other_result.key())
-        self.assertOnlyInstances([some_test, other_test])
-
-        self.assertRaises(AssertionError, some_test.merge, (some_test))
-        self.assertOnlyInstances([some_test, other_test])
-
-        some_test.merge(other_test)
-        results_for_some_test = TestResult.all()
-        results_for_some_test.filter('name =', 'some-test')
-        results_for_some_test = results_for_some_test.fetch(5)
-        self.assertEqual(len(results_for_some_test), 2)
-
-        self.assertEqual(results_for_some_test[0].name, 'some-test')
-        self.assertEqual(results_for_some_test[1].name, 'some-test')
-
-        if results_for_some_test[0].value == 50:
-            self.assertEqual(results_for_some_test[1].value, 30)
-        else:
-            self.assertEqual(results_for_some_test[1].value, 50)
-
-
-class TestResultTests(DataStoreTestsBase):
-    def test_get_or_insert_value(self):
-        branch, platform, builder = _create_some_builder()
-        build = _create_build(branch, platform, builder)
-        self.assertThereIsNoInstanceOf(TestResult)
-        result = TestResult.get_or_insert_from_parsed_json('some-test', build, 50)
-        self.assertOnlyInstance(result)
-        self.assertEqual(result.name, 'some-test')
-        self.assertEqual(result.build.key(), build.key())
-        self.assertEqual(result.value, 50.0)
-        self.assertEqual(result.valueMedian, None)
-        self.assertEqual(result.valueStdev, None)
-        self.assertEqual(result.valueMin, None)
-        self.assertEqual(result.valueMax, None)
-
-    def test_get_or_insert_stat_value(self):
-        branch, platform, builder = _create_some_builder()
-        build = _create_build(branch, platform, builder)
-        self.assertThereIsNoInstanceOf(TestResult)
-        result = TestResult.get_or_insert_from_parsed_json('some-test', build,
-            {"avg": 40, "median": "40.1", "stdev": 3.25, "min": 30.5, "max": 45})
-        self.assertOnlyInstance(result)
-        self.assertEqual(result.name, 'some-test')
-        self.assertEqual(result.build.key(), build.key())
-        self.assertEqual(result.value, 40.0)
-        self.assertEqual(result.valueMedian, 40.1)
-        self.assertEqual(result.valueStdev, 3.25)
-        self.assertEqual(result.valueMin, 30.5)
-        self.assertEqual(result.valueMax, 45)
-        self.assertEqual(result.values, [])
-
-    def test_get_or_insert_stat_value_with_values(self):
-        branch, platform, builder = _create_some_builder()
-        build = _create_build(branch, platform, builder)
-        result = TestResult.get_or_insert_from_parsed_json('some-test', build,
-            {"avg": 40, "median": "40.1", "stdev": 3.25, "min": 30.5, "max": 45, "values": [1.0, 2.0, 3.0]})
-        self.assertEqual(result.values, [1.0, 2.0, 3.0])
-
-    def test_replace_to_change_test_name(self):
-        branch, platform, builder = _create_some_builder()
-        build = _create_build(branch, platform, builder)
-        self.assertThereIsNoInstanceOf(TestResult)
-        result = TestResult.get_or_insert_from_parsed_json('some-test', build, 50)
-        self.assertOnlyInstance(result)
-        self.assertEqual(result.name, 'some-test')
-
-        new_result = result.replace_to_change_test_name('other-test')
-        self.assertNotEqual(result, new_result)
-        self.assertOnlyInstance(new_result)
-
-        self.assertEqual(new_result.name, 'other-test')
-        self.assertEqual(new_result.build.key(), result.build.key())
-        self.assertEqual(new_result.value, result.value)
-        self.assertEqual(new_result.valueMedian, None)
-        self.assertEqual(new_result.valueStdev, None)
-        self.assertEqual(new_result.valueMin, None)
-        self.assertEqual(new_result.valueMax, None)
-
-    def test_replace_to_change_test_name_with_stat_value(self):
-        branch, platform, builder = _create_some_builder()
-        build = _create_build(branch, platform, builder)
-        self.assertThereIsNoInstanceOf(TestResult)
-        result = TestResult.get_or_insert_from_parsed_json('some-test', build,
-            {"avg": 40, "median": "40.1", "stdev": 3.25, "min": 30.5, "max": 45})
-        self.assertOnlyInstance(result)
-        self.assertEqual(result.name, 'some-test')
-
-        new_result = result.replace_to_change_test_name('other-test')
-        self.assertNotEqual(result, new_result)
-        self.assertOnlyInstance(new_result)
-
-        self.assertEqual(new_result.name, 'other-test')
-        self.assertEqual(new_result.build.key(), result.build.key())
-        self.assertEqual(new_result.value, result.value)
-        self.assertEqual(result.value, 40.0)
-        self.assertEqual(result.valueMedian, 40.1)
-        self.assertEqual(result.valueStdev, 3.25)
-        self.assertEqual(result.valueMin, 30.5)
-        self.assertEqual(result.valueMax, 45)
-
-    def test_replace_to_change_test_name_overrides_conflicting_result(self):
-        branch, platform, builder = _create_some_builder()
-        build = _create_build(branch, platform, builder)
-        self.assertThereIsNoInstanceOf(TestResult)
-        result = TestResult.get_or_insert_from_parsed_json('some-test', build, 20)
-        self.assertOnlyInstance(result)
-
-        conflicting_result = TestResult.get_or_insert_from_parsed_json('other-test', build, 10)
-
-        new_result = result.replace_to_change_test_name('other-test')
-        self.assertNotEqual(result, new_result)
-        self.assertOnlyInstance(new_result)
-
-        self.assertEqual(new_result.name, 'other-test')
-        self.assertEqual(TestResult.get(conflicting_result.key()).value, 20)
-
-
-class ReportLogTests(DataStoreTestsBase):
-    def _create_log_with_payload(self, payload):
-        return ReportLog(timestamp=datetime.now(), headers='some headers', payload=payload)
-
-    def test_parsed_payload(self):
-        log = self._create_log_with_payload('')
-        self.assertFalse('_parsed' in log.__dict__)
-        self.assertEqual(log._parsed_payload(), False)
-        self.assertEqual(log._parsed, False)
-
-        log = self._create_log_with_payload('{"key": "value", "another key": 1}')
-        self.assertEqual(log._parsed_payload(), {"key": "value", "another key": 1})
-        self.assertEqual(log._parsed, {"key": "value", "another key": 1})
-
-    def test_get_value(self):
-        log = self._create_log_with_payload('{"string": "value", "integer": 1, "float": 1.1}')
-        self.assertEqual(log.get_value('string'), 'value')
-        self.assertEqual(log.get_value('integer'), 1)
-        self.assertEqual(log.get_value('float'), 1.1)
-        self.assertEqual(log.get_value('bad'), None)
-
-    def test_results(self):
-        log = self._create_log_with_payload('{"results": 123}')
-        self.assertEqual(log.results(), 123)
-
-        log = self._create_log_with_payload('{"key": "value"}')
-        self.assertEqual(log.results(), None)
-
-    def test_results_are_well_formed(self):
-
-        def assert_results_are_well_formed(json, expected):
-            self.assertEqual(self._create_log_with_payload(json).results_are_well_formed(), expected)
-
-        assert_results_are_well_formed('{"results": 123}', False)
-        assert_results_are_well_formed('{"results": {"test": 123}}', True)
-        assert_results_are_well_formed('{"results": {"test": 123, "other-test": 456}}', True)
-        assert_results_are_well_formed('{"results": {"test": 123, "other-test": 456, "bad-test": "hi"}}', False)
-        assert_results_are_well_formed('{"results": {"test": {"avg": 456}}}', True)
-        assert_results_are_well_formed('{"results": {"test": {"avg": 456, "median": "hello"}}}', False)
-        assert_results_are_well_formed('{"results": {"test": {"avg": 456, "median": 789}}}', True)
-        assert_results_are_well_formed('{"results": {"test": {"avg": 456, "unit": "bytes"}}}', True)
-        assert_results_are_well_formed('{"results": {"test": {"avg": 456, "unit": "bytes", "values": [1.0, 2.0, 3.0]}}}', True)
-
-        assert_results_are_well_formed('[]', False)
-        assert_results_are_well_formed('[{"results": {"test": 123}}]', True)
-        assert_results_are_well_formed('[{"results": {"test": 123}}, {"results": {"test": 123}}]', False)
-        assert_results_are_well_formed('[{"results": {"test": {"avg": 456, "unit": "bytes", "values": [1.0, 2.0, 3.0]}}}]', True)
-
-    def test_builder(self):
-        log = self._create_log_with_payload('{"key": "value"}')
-        self.assertEqual(log.builder(), None)
-
-        builder_name = "Chromium Mac Release (Perf)"
-        log = self._create_log_with_payload('{"builder-name": "%s"}' % builder_name)
-        self.assertEqual(log.builder(), None)
-
-        builder_key = Builder.create(builder_name, 'some password')
-        log = self._create_log_with_payload('{"builder-name": "%s"}' % builder_name)
-        self.assertEqual(log.builder().key(), builder_key)
-
-    def test_branch(self):
-        log = self._create_log_with_payload('{"key": "value"}')
-        self.assertEqual(log.branch(), None)
-
-        log = self._create_log_with_payload('{"branch": "some-branch"}')
-        self.assertEqual(log.branch(), None)
-
-        branch = Branch.create_if_possible("some-branch", "Some Branch")
-        log = self._create_log_with_payload('{"branch": "some-branch"}')
-        self.assertEqual(log.branch().key(), branch.key())
-
-    def test_platform(self):
-        log = self._create_log_with_payload('{"key": "value"}')
-        self.assertEqual(log.platform(), None)
-
-        log = self._create_log_with_payload('{"platform": "some-platform"}')
-        self.assertEqual(log.platform(), None)
-
-        platform = Platform.create_if_possible("some-platform", "Some Platform")
-        log = self._create_log_with_payload('{"platform": "some-platform"}')
-        self.assertEqual(log.platform().key(), platform.key())
-
-    def test_build_number(self):
-        log = self._create_log_with_payload('{"build-number": 123}')
-        self.assertEqual(log.build_number(), 123)
-
-        log = self._create_log_with_payload('{"key": "value"}')
-        self.assertEqual(log.build_number(), None)
-
-    def test_webkit_revision(self):
-        log = self._create_log_with_payload('{"key": "value"}')
-        self.assertEqual(log.webkit_revision(), None)
-
-        log = self._create_log_with_payload('{"webkit-revision": 123}')
-        self.assertEqual(log.webkit_revision(), 123)
-
-    def test_chromium_revision(self):
-        log = self._create_log_with_payload('{"chromium-revision": 123}')
-        self.assertEqual(log.chromium_revision(), 123)
-
-        log = self._create_log_with_payload('{"key": "value"}')
-        self.assertEqual(log.chromium_revision(), None)
-
-    def test_results_in_array(self):
-        platform = Platform.create_if_possible("some-platform", "Some Platform")
-        log = self._create_log_with_payload('[{"platform": "some-platform", "build-number": 123, "webkit-revision": 456}]')
-        self.assertEqual(log.platform().key(), platform.key())
-        self.assertEqual(log.build_number(), 123)
-        self.assertEqual(log.webkit_revision(), 456)
-
-
-class PersistentCacheTests(DataStoreTestsBase):
-    def setUp(self):
-        super(PersistentCacheTests, self).setUp()
-        self.testbed.init_memcache_stub()
-
-    def _assert_persistent_cache(self, name, value):
-        self.assertEqual(PersistentCache.get_by_key_name(name).value, value)
-        self.assertEqual(memcache.get(name), value)
-
-    def test_set_cache(self):
-        self.assertThereIsNoInstanceOf(PersistentCache)
-
-        PersistentCache.set_cache('some-cache', 'some data')
-        self._assert_persistent_cache('some-cache', 'some data')
-
-        PersistentCache.set_cache('some-cache', 'some other data')
-
-        self._assert_persistent_cache('some-cache', 'some other data')
-
-    def test_get_cache(self):
-        self.assertEqual(memcache.get('some-cache'), None)
-        self.assertEqual(PersistentCache.get_cache('some-cache'), None)
-
-        PersistentCache.set_cache('some-cache', 'some data')
-
-        self.assertEqual(memcache.get('some-cache'), 'some data')
-        self.assertEqual(PersistentCache.get_cache('some-cache'), 'some data')
-
-        memcache.delete('some-cache')
-        self.assertEqual(memcache.get('some-cache'), None)
-        self.assertEqual(PersistentCache.get_cache('some-cache'), 'some data')
-
-
-class RunsTest(DataStoreTestsBase):
-    def setUp(self):
-        super(RunsTest, self).setUp()
-        self.testbed.init_memcache_stub()
-
-    def _create_results(self, branch, platform, builder, test_name, values, timestamps=None, starting_revision=100):
-        builds = []
-        results = []
-        for i, value in enumerate(values):
-            build = Build(branch=branch, platform=platform, builder=builder,
-                buildNumber=i, revision=starting_revision + i, timestamp=timestamps[i] if timestamps else datetime.now())
-            build.put()
-            result = TestResult(name=test_name, build=build, value=value)
-            result.put()
-            builds.append(build)
-            results.append(result)
-        return builds, results
-
-    def test_generate_runs(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-
-        builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0, 51.0, 52.0, 49.0, 48.0])
-        last_i = 0
-        for i, (build, result) in enumerate(Runs._generate_runs(some_branch, some_platform, some_test)):
-            self.assertEqual(build.buildNumber, i)
-            self.assertEqual(build.revision, 100 + i)
-            self.assertEqual(result.name, 'some-test')
-            self.assertEqual(result.value, results[i].value)
-            last_i = i
-        self.assertTrue(last_i + 1, len(results))
-
-    def test_update_or_insert(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-        self.assertThereIsNoInstanceOf(Runs)
-
-        runs = Runs.update_or_insert(some_branch, some_platform, some_test)
-        self.assertOnlyInstance(runs)
-        self.assertEqual(runs.json_runs, '')
-        self.assertEqual(runs.json_averages, '')
-        self.assertEqual(runs.json_min, None)
-        self.assertEqual(runs.json_max, None)
-        old_memcache_value = memcache.get(Runs._key_name(some_branch.id, some_platform.id, some_test.id))
-        self.assertTrue(old_memcache_value)
-
-        runs.delete()
-        self.assertThereIsNoInstanceOf(Runs)
-
-        builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0])
-        runs = Runs.update_or_insert(some_branch, some_platform, some_test)
-        self.assertOnlyInstance(runs)
-        self.assertTrue(runs.json_runs.startswith('[5,[4,0,100,null],'))
-        self.assertEqual(json.loads('{' + runs.json_averages + '}'), {"100": 50.0})
-        self.assertEqual(runs.json_min, 50.0)
-        self.assertEqual(runs.json_max, 50.0)
-        self.assertNotEqual(memcache.get(Runs._key_name(some_branch.id, some_platform.id, some_test.id)), old_memcache_value)
-
-    def test_update_incrementally(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-        self.assertThereIsNoInstanceOf(Runs)
-
-        timestamps = [datetime.now(), datetime.now()]
-        builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0, 52.0], timestamps)
-        runs = Runs.update_or_insert(some_branch, some_platform, some_test)
-        self.assertOnlyInstance(runs)
-        self.assertEqual(json.loads('[' + runs.json_runs + ']'),
-            [[5, [4, 0, 100, None], mktime(timestamps[0].timetuple()), 50.0, 0, [], None, None],
-            [7, [6, 1, 101, None], mktime(timestamps[1].timetuple()), 52.0, 0, [], None, None]])
-        self.assertEqual(json.loads('{' + runs.json_averages + '}'), {"100": 50.0, "101": 52.0})
-        self.assertEqual(runs.json_min, 50.0)
-        self.assertEqual(runs.json_max, 52.0)
-
-        timestamps.append(datetime.now())
-        builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [48.0],
-            timestamps[2:], starting_revision=102)
-        runs.update_incrementally(builds[0], results[0])
-
-        self.assertOnlyInstance(runs)
-        self.assertEqual(json.loads('[' + runs.json_runs + ']'),
-            [[5, [4, 0, 100, None], mktime(timestamps[0].timetuple()), 50.0, 0, [], None, None],
-            [7, [6, 1, 101, None], mktime(timestamps[1].timetuple()), 52.0, 0, [], None, None],
-            [9, [8, 0, 102, None], mktime(timestamps[2].timetuple()), 48.0, 0, [], None, None]])
-        self.assertEqual(json.loads('{' + runs.json_averages + '}'), {"100": 50.0, "101": 52.0, "102": 48.0})
-        self.assertEqual(runs.json_min, 48.0)
-        self.assertEqual(runs.json_max, 52.0)
-
-    def test_json_by_ids(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-
-        self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0])
-        runs = Runs.update_or_insert(some_branch, some_platform, some_test)
-        runs_json = runs.to_json()
-
-        key_name = Runs._key_name(some_branch.id, some_platform.id, some_test.id)
-        self.assertEqual(Runs.json_by_ids(some_branch.id, some_platform.id, some_test.id), runs_json)
-        self.assertEqual(memcache.get(key_name), runs_json)
-
-        memcache.set(key_name, 'blah')
-        self.assertEqual(Runs.json_by_ids(some_branch.id, some_platform.id, some_test.id), 'blah')
-
-        memcache.delete(key_name)
-        self.assertEqual(Runs.json_by_ids(some_branch.id, some_platform.id, some_test.id), runs_json)
-        self.assertEqual(memcache.get(key_name), runs_json)
-
-    def test_to_json_without_results(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-        self.assertOnlyInstance(some_test)
-        self.assertThereIsNoInstanceOf(TestResult)
-        self.assertEqual(json.loads(Runs.update_or_insert(some_branch, some_platform, some_test).to_json()), {
-            'test_runs': [],
-            'averages': {},
-            'min': None,
-            'max': None,
-            'unit': None,
-            'date_range': None,
-            'stat': 'ok'})
-
-    def test_to_json_with_results(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-        builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0, 51.0, 52.0, 49.0, 48.0])
-
-        value = json.loads(Runs.update_or_insert(some_branch, some_platform, some_test).to_json())
-        self.assertEqualUnorderedList(value.keys(), ['test_runs', 'averages', 'min', 'max', 'unit', 'date_range', 'stat'])
-        self.assertEqual(value['stat'], 'ok')
-        self.assertEqual(value['min'], 48.0)
-        self.assertEqual(value['max'], 52.0)
-        self.assertEqual(value['unit'], None)
-        self.assertEqual(value['date_range'], None)  # date_range is never given
-
-        self.assertEqual(len(value['test_runs']), len(results))
-        for i, run in enumerate(value['test_runs']):
-            result = results[i]
-            self.assertEqual(run[0], result.key().id())
-            self.assertEqual(run[1][1], i)  # Build number
-            self.assertEqual(run[1][2], 100 + i)  # Revision
-            self.assertEqual(run[1][3], None)  # Supplementary revision
-            self.assertEqual(run[3], result.value)
-            self.assertEqual(run[6], some_builder.key().id())
-            self.assertEqual(run[7], None)  # Statistics
-
-    def test_to_json_with_unit(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform, 'runs/s')
-        builds, results = self._create_results(some_branch, some_platform, some_builder, 'some-test', [50.0, 51.0, 52.0, 49.0, 48.0])
-
-        value = json.loads(Runs.update_or_insert(some_branch, some_platform, some_test).to_json())
-        self.assertEqual(value['unit'], 'runs/s')
-
-    def _assert_entry(self, entry, build, result, value, statistics=None, supplementary_revisions=None):
-        entry = entry[:]
-        entry[2] = None  # timestamp
-        self.assertEqual(entry, [result.key().id(), [build.key().id(), build.buildNumber, build.revision, supplementary_revisions],
-            None,  # timestamp
-            value, 0,  # runNumber
-            [],  # annotations
-            build.builder.key().id(), statistics])
-
-    def test_run_from_build_and_result(self):
-        branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
-        test_name = ' some-test'
-
-        def create_build(build_number, revision):
-            timestamp = datetime.now().replace(microsecond=0)
-            build = Build(branch=branch, platform=platform, builder=builder, buildNumber=build_number,
-                revision=revision, timestamp=timestamp)
-            build.put()
-            return build
-
-        build = create_build(1, 101)
-        result = TestResult(name=test_name, value=123.0, build=build)
-        result.put()
-        self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 123.0)
-
-        build = create_build(2, 102)
-        result = TestResult(name=test_name, value=456.0, valueMedian=789.0, build=build)
-        result.put()
-        self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0)
-
-        result.valueStdev = 7.0
-        result.put()
-        self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0)
-
-        result.valueStdev = None
-        result.valueMin = 123.0
-        result.valueMax = 789.0
-        result.put()
-        self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0)
-
-        result.valueStdev = 8.0
-        result.valueMin = 123.0
-        result.valueMax = 789.0
-        result.put()
-        self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0,
-            statistics={'stdev': 8.0, 'min': 123.0, 'max': 789.0})
-
-        result.valueMedian = 345.0  # Median is never used by the frontend.
-        result.valueStdev = 8.0
-        result.valueMin = 123.0
-        result.valueMax = 789.0
-        result.put()
-        self._assert_entry(Runs._entry_from_build_and_result(build, result), build, result, 456.0,
-            statistics={'stdev': 8.0, 'min': 123.0, 'max': 789.0})
-
-    def test_chart_params_with_value(self):
-        some_branch = Branch.create_if_possible('some-branch', 'Some Branch')
-        some_platform = Platform.create_if_possible('some-platform', 'Some Platform')
-        some_builder = Builder.get(Builder.create('some-builder', 'Some Builder'))
-        some_test = Test.update_or_insert('some-test', some_branch, some_platform)
-
-        start_time = datetime(2011, 2, 21, 12, 0, 0)
-        end_time = datetime(2011, 2, 28, 12, 0, 0)
-        results = self._create_results(some_branch, some_platform, some_builder, 'some-test',
-            [50.0, 51.0, 52.0, 49.0, 48.0, 51.9, 50.7, 51.1],
-            [start_time + timedelta(day) for day in range(0, 8)])
-
-        # Use int despite of its impreciseness since tests may fail due to rounding errors otherwise.
-        def split_as_int(string):
-            return [int(float(value)) for value in string.split(',')]
-
-        params = Runs.update_or_insert(some_branch, some_platform, some_test).chart_params(7)
-        self.assertEqual(params['chxl'], '0:|Feb 21|Feb 22|Feb 23|Feb 24|Feb 25|Feb 26|Feb 27|Feb 28')
-        self.assertEqual(split_as_int(params['chxr']), [1, 0, 57, int(52 * 1.1 / 5 + 0.5)])
-        x_min, x_max, y_min, y_max = split_as_int(params['chds'])
-        self.assertEqual(datetime.fromtimestamp(x_min), start_time)
-        self.assertEqual(datetime.fromtimestamp(x_max), end_time)
-        self.assertEqual(y_min, 0)
-        self.assertEqual(y_max, int(52 * 1.1))
-        self.assertEqual(split_as_int(params['chg']), [int(100 / 7), 20, 0, 0])
-
-        params = Runs.update_or_insert(some_branch, some_platform, some_test).chart_params(14)
-        self.assertEqual(params['chxl'], '0:|Feb 14|Feb 16|Feb 18|Feb 20|Feb 22|Feb 24|Feb 26|Feb 28')
-        self.assertEqual(split_as_int(params['chxr']), [1, 0, 57, int(52 * 1.1 / 5 + 0.5)])
-        x_min, x_max, y_min, y_max = split_as_int(params['chds'])
-        self.assertEqual(datetime.fromtimestamp(x_min), datetime(2011, 2, 14, 12, 0, 0))
-        self.assertEqual(datetime.fromtimestamp(x_max), end_time)
-        self.assertEqual(y_min, 0)
-        self.assertEqual(y_max, int(52 * 1.1))
-        self.assertEqual(split_as_int(params['chg']), [int(100 / 7), 20, 0, 0])
-
-
-class DashboardImageTests(DataStoreTestsBase):
-    def setUp(self):
-        super(DashboardImageTests, self).setUp()
-        self.testbed.init_memcache_stub()
-
-    def test_create(self):
-        self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), None)
-        self.assertThereIsNoInstanceOf(DashboardImage)
-        image = DashboardImage.create(1, 2, 3, 7, 'blah')
-        self.assertOnlyInstance(image)
-        self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), 'blah')
-
-    def test_get(self):
-        image = DashboardImage.create(1, 2, 3, 7, 'blah')
-        self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), 'blah')
-        memcache.set('dashboard-image:1:2:3:7', 'new value')
-
-        # Check twice to make sure the first call doesn't clear memcache
-        self.assertEqual(DashboardImage.get_image(1, 2, 3, 7), 'new value')
-        self.assertEqual(DashboardImage.get_image(1, 2, 3, 7), 'new value')
-
-        memcache.delete('dashboard-image:1:2:3:7')
-        self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), None)
-        self.assertEqual(DashboardImage.get_image(1, 2, 3, 7), 'blah')
-        self.assertEqual(memcache.get('dashboard-image:1:2:3:7'), 'blah')
-
-    def test_needs_update(self):
-        self.assertTrue(DashboardImage.needs_update(1, 2, 3, 7))
-        self.assertTrue(DashboardImage.needs_update(1, 2, 3, 30))
-        self.assertTrue(DashboardImage.needs_update(1, 2, 3, 60))
-        self.assertTrue(DashboardImage.needs_update(1, 2, 3, 365))
-
-        image = DashboardImage(key_name=DashboardImage.key_name(1, 2, 3, 7), image='blah')
-        image.put()
-        self.assertOnlyInstance(image)
-        self.assertTrue(DashboardImage.needs_update(1, 2, 3, 7))
-
-        DashboardImage(key_name=DashboardImage.key_name(1, 2, 3, 30), image='blah').put()
-        self.assertFalse(DashboardImage.needs_update(1, 2, 3, 30, datetime.now() + timedelta(0, 10)))
-
-        DashboardImage(key_name=DashboardImage.key_name(1, 2, 4, 30), image='blah').put()
-        self.assertTrue(DashboardImage.needs_update(1, 2, 4, 30, datetime.now() + timedelta(1)))
-
-        DashboardImage(key_name=DashboardImage.key_name(1, 2, 3, 90), image='blah').put()
-        self.assertFalse(DashboardImage.needs_update(1, 2, 3, 90, datetime.now() + timedelta(0, 20)))
-
-        DashboardImage(key_name=DashboardImage.key_name(1, 2, 4, 90), image='blah').put()
-        self.assertTrue(DashboardImage.needs_update(1, 2, 4, 90, datetime.now() + timedelta(1)))
-
-        DashboardImage(key_name=DashboardImage.key_name(1, 2, 3, 365), image='blah').put()
-        self.assertFalse(DashboardImage.needs_update(1, 2, 3, 365, datetime.now() + timedelta(1)))
-
-        DashboardImage(key_name=DashboardImage.key_name(1, 2, 4, 365), image='blah').put()
-        self.assertTrue(DashboardImage.needs_update(1, 2, 4, 365, datetime.now() + timedelta(10)))
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/Websites/webkit-perf.appspot.com/report_handler.py b/Websites/webkit-perf.appspot.com/report_handler.py
deleted file mode 100644 (file)
index fdc8a63..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import webapp2
-from google.appengine.ext import db
-
-import json
-import re
-from datetime import datetime
-
-from models import ReportLog
-from controller import schedule_report_process
-
-
-class ReportHandler(webapp2.RequestHandler):
-    def post(self):
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-
-        headers = "\n".join([key + ': ' + value for key, value in self.request.headers.items()])
-
-        # Do as best as we can to remove the password
-        request_body_without_password = re.sub(r',\s*"password"\s*:\s*".+?"', '', self.request.body)
-        log = ReportLog(timestamp=datetime.now(), headers=headers, payload=request_body_without_password)
-        log.put()
-
-        self._encountered_error = False
-
-        try:
-            parsedPayload = json.loads(self.request.body)
-            if isinstance(parsedPayload, list):
-                parsedPayload = parsedPayload[0]
-            password = parsedPayload.get('password', '')
-        except:
-            return self._output('Failed to parse the payload as a json. Report key: %d' % log.key().id())
-
-        builder = log.builder()
-        builder != None or self._output('No builder named "%s"' % log.get_value('builder-name'))
-        log.branch() != None or self._output('No branch named "%s"' % log.get_value('branch'))
-        log.platform() != None or self._output('No platform named "%s"' % log.get_value('platform'))
-        log.build_number() != None or self._output('Invalid build number "%s"' % log.get_value('build-number'))
-        log.timestamp() != None or self._output('Invalid timestamp "%s"' % log.get_value('timestamp'))
-        log.webkit_revision() != None or self._output('Invalid webkit revision "%s"' % log.get_value('webkit-revision'))
-
-        failed = False
-        if builder and not (self.bypass_authentication() or builder.authenticate(password)):
-            self._output('Authentication failed')
-
-        if not log.results_are_well_formed():
-            self._output("The payload doesn't contain results or results are malformed")
-
-        if self._encountered_error:
-            return
-
-        log.commit = True
-        log.put()
-        schedule_report_process(log)
-        self._output("OK")
-
-    def _output(self, message):
-        self._encountered_error = True
-        self.response.out.write(message + '\n')
-
-    def bypass_authentication(self):
-        return False
-
-
-class AdminReportHandler(ReportHandler):
-    def bypass_authentication(self):
-        return True
diff --git a/Websites/webkit-perf.appspot.com/report_logs.html b/Websites/webkit-perf.appspot.com/report_logs.html
deleted file mode 100644 (file)
index dfbbc38..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<pre>{{ status }}</pre>
-<h1>Report logs</h1>
-
-<style type="text/css" scoped>
-
-table { width: 100%; border: solid 1px #ccc; border-collapse: collapse; }
-td { border: solid 1px #ccc; padding: 5px; }
-.control code { display: none; }
-code { white-space: pre-wrap; }
-form { display: inline; }
-
-</style>
-<script>
-
-$ = function (id) { return document.getElementById(id); }
-
-function show(id) {
-    var row = $('row_' + id);
-    var code = row.querySelector('code');
-    if (!code)
-        return;
-    var newRow = document.createElement('tr');
-    newRow.appendChild(document.createElement('td'));
-    newRow.firstChild.appendChild(code);
-    newRow.firstChild.colSpan = 8;
-    row.parentNode.insertBefore(newRow, row.nextSibling);
-    try {
-        code.textContent = JSON.stringify(JSON.parse(code.textContent), null, 2);
-    } catch (e) { }
-}
-
-function submit(form, event) {
-    if (!confirm('Are you sure?'))
-        event.preventDefault();
-}
-
-</script>
-<table>
-<thead>
-<tr>
-    <td>Id</td>
-    <td>Branch</td>
-    <td>Platform</td>
-    <td>Builder</td>
-    <td>Build</td>
-    <td>WebKit revision</td>
-    <td>Chromium revision</td>
-    <td class="control">Payload</td>
-</tr>
-</thead>
-<tbody>
-{% for log in logs %}
-<tr id="row_{{ log.key.id }}">
-    <td>{{ log.key.id }}</td>
-    <td>{{ log.branch.name }}</td>
-    <td>{{ log.platform.name }}</td>
-    <td><a href="http://build.webkit.org/builders/{{ log.builder.name }}/">{{ log.builder.name }}</a></td>
-    <td><a href="http://build.webkit.org/builders/{{ log.builder.name }}/builds/{{ log.build_number }}">{{ log.build_number }}</a></td>
-    <td><a href="http://trac.webkit.org/changeset/{{ log.webkit_revision }}">{{ log.webkit_revision }}</a></td>
-    <td><a href="http://src.chromium.org/viewvc/chrome?view=rev&amp;revision={{ log.chromium_revision }}">{{ log.chromium_revision }}</a></td>
-    <td class="control"><button onclick="show({{ log.key.id }})">Show</button>
-        <form method="post" action="/admin/report-logs" onsubmit="submit(this, event)">
-        <input type="hidden" name="id" value="{{ log.key.id }}">
-        <button name="commit" value="true">Commit</button>
-        <button name="delete" value="true">Delete</button></form>
-        <code>{{ log.payload }}</code></td>
-</tr>
-{% endfor %}
-</tbody>
-</table>
-
-</body>
-</html>
diff --git a/Websites/webkit-perf.appspot.com/report_logs_handler.py b/Websites/webkit-perf.appspot.com/report_logs_handler.py
deleted file mode 100644 (file)
index 2a1905f..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import webapp2
-from google.appengine.ext.webapp import template
-
-import os
-
-from controller import schedule_report_process
-from models import ReportLog
-
-
-class ReportLogsHandler(webapp2.RequestHandler):
-    def get(self):
-        self.response.out.write(template.render('report_logs.html', {'logs': ReportLog.all()}))
-
-    def post(self):
-        commit = bool(self.request.get('commit'))
-        delete = bool(self.request.get('delete'))
-        if commit == delete:
-            return self._error('Invalid request')
-
-        try:
-            log = ReportLog.get_by_id(int(self.request.get('id', 0)))
-        except:
-            return self._error('Invalid log id "%s"' % self.request.get('id', ''))
-
-        if not log:
-            return self._error('No log found for "%s"' % self.request.get('id', ''))
-
-        if commit:
-            log.commit = True
-            log.put()
-            schedule_report_process(log)
-        else:
-            log.delete()
-
-        self.response.out.write(template.render('report_logs.html', {'logs': ReportLog.all(), 'status': 'OK'}))
-
-    def _error(self, message):
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-        self.response.out.write(message + '\n')
diff --git a/Websites/webkit-perf.appspot.com/report_process_handler.py b/Websites/webkit-perf.appspot.com/report_process_handler.py
deleted file mode 100644 (file)
index 6610bd8..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2012 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import webapp2
-from google.appengine.ext import db
-
-import time
-
-from controller import schedule_runs_update
-from controller import schedule_dashboard_update
-from controller import schedule_manifest_update
-from models import Build
-from models import ReportLog
-from models import Runs
-from models import Test
-from models import TestResult
-
-
-class ReportProcessHandler(webapp2.RequestHandler):
-    def post(self):
-        self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
-
-        log_id = int(self.request.get('id', 0))
-
-        log = ReportLog.get_by_id(log_id)
-        if not log or not log.commit:
-            self.response.out.write("Not processed")
-            return
-
-        branch = log.branch()
-        platform = log.platform()
-        build = Build.get_or_insert_from_log(log)
-
-        for test_name, result_value in log.results().iteritems():
-            unit = result_value.get('unit') if isinstance(result_value, dict) else None
-            test = Test.update_or_insert(test_name, branch, platform, unit)
-            result = TestResult.get_or_insert_from_parsed_json(test_name, build, result_value)
-            runs = Runs.get_by_objects(branch, platform, test)
-            regenerate_runs = True
-            if runs:
-                runs.update_incrementally(build, result)
-                regenerate_runs = False
-            schedule_runs_update(test.id, branch.id, platform.id, regenerate_runs)
-
-        log = ReportLog.get(log.key())
-        log.delete()
-
-        # We need to update dashboard and manifest because they are affected by the existance of test results
-        schedule_dashboard_update()
-        schedule_manifest_update()
-
-        self.response.out.write('OK')