4e6e2e846853ac9febcdc876dade3dc0dcf8f65f
[WebKit-https.git] / Websites / webkit-perf.appspot.com / report_process_handler.py
1 #!/usr/bin/env python
2 # Copyright (C) 2012 Google Inc. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 #     * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 #     * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
13 # distribution.
14 #     * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 import webapp2
31 from google.appengine.ext import db
32
33 import time
34
35 from controller import schedule_runs_update
36 from controller import schedule_dashboard_update
37 from controller import schedule_manifest_update
38 from models import Build
39 from models import ReportLog
40 from models import Test
41 from models import TestResult
42 from models import create_in_transaction_with_numeric_id_holder
43
44
45 class ReportProcessHandler(webapp2.RequestHandler):
46     def post(self):
47         self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
48
49         log_id = int(self.request.get('id', 0))
50
51         log = ReportLog.get_by_id(log_id)
52         if not log or not log.commit:
53             self.response.out.write("Not processed")
54             return
55
56         branch = log.branch()
57         platform = log.platform()
58         build = self._create_build_if_possible(log, branch, platform)
59
60         for test_name, result in log.results().iteritems():
61             test = self._add_test_if_needed(test_name, branch, platform)
62             self._add_test_result_if_needed(test_name, build, result)
63             schedule_runs_update(test.id, branch.id, platform.id)
64
65         log = ReportLog.get(log.key())
66         log.delete()
67
68         # We need to update dashboard and manifest because they are affected by the existance of test results
69         schedule_dashboard_update()
70         schedule_manifest_update()
71
72         self.response.out.write('OK')
73
74     def _create_build_if_possible(self, log, branch, platform):
75         builder = log.builder()
76         key_name = builder.name + ':' + str(int(time.mktime(log.timestamp().timetuple())))
77
78         return Build.get_or_insert(key_name, branch=branch, platform=platform, builder=builder, buildNumber=log.build_number(),
79             timestamp=log.timestamp(), revision=log.webkit_revision(), chromiumRevision=log.chromium_revision())
80
81     def _add_test_if_needed(self, test_name, branch, platform):
82
83         def execute(id):
84             test = Test.get_by_key_name(test_name)
85             returnValue = None
86             if not test:
87                 test = Test(id=id, name=test_name, key_name=test_name)
88                 returnValue = test
89             if branch.key() not in test.branches:
90                 test.branches.append(branch.key())
91             if platform.key() not in test.platforms:
92                 test.platforms.append(platform.key())
93             test.put()
94             return returnValue
95         return create_in_transaction_with_numeric_id_holder(execute) or Test.get_by_key_name(test_name)
96
97     def _add_test_result_if_needed(self, test_name, build, result):
98         key_name = TestResult.key_name(build, test_name)
99
100         def _float_or_none(dictionary, key):
101             value = dictionary.get(key)
102             if value:
103                 return float(value)
104             return None
105
106         if not isinstance(result, dict):
107             return TestResult.get_or_insert(key_name, name=test_name, build=build, value=float(result))
108
109         return TestResult.get_or_insert(key_name, name=test_name, build=build, value=float(result['avg']),
110             valueMedian=_float_or_none(result, 'median'), valueStdev=_float_or_none(result, 'stdev'),
111             valueMin=_float_or_none(result, 'min'), valueMax=_float_or_none(result, 'max'))