1d7e0d0afbb403790e6736f3531190ca7c6cbb40
[WebKit-https.git] / Websites / webkit-perf.appspot.com / controller.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 urllib
31 import webapp2
32 from google.appengine.api import taskqueue
33 from google.appengine.ext import db
34
35 from json_generators import DashboardJSONGenerator
36 from json_generators import ManifestJSONGenerator
37 from models import Branch
38 from models import DashboardImage
39 from models import PersistentCache
40 from models import Platform
41 from models import Runs
42 from models import Test
43 from models import model_from_numeric_id
44
45
46 def schedule_manifest_update():
47     taskqueue.add(url='/api/test/update')
48
49
50 class ManifestUpdateHandler(webapp2.RequestHandler):
51     def post(self):
52         self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
53         PersistentCache.set_cache('manifest', ManifestJSONGenerator().to_json())
54         self.response.out.write('OK')
55
56
57 class CachedManifestHandler(webapp2.RequestHandler):
58     def get(self):
59         self.response.headers['Content-Type'] = 'application/json'
60         manifest = PersistentCache.get_cache('manifest')
61         if manifest:
62             self.response.out.write(manifest)
63         else:
64             schedule_manifest_update()
65
66
67 def schedule_dashboard_update():
68     taskqueue.add(url='/api/test/dashboard/update')
69
70
71 class DashboardUpdateHandler(webapp2.RequestHandler):
72     def post(self):
73         self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
74         PersistentCache.set_cache('dashboard', DashboardJSONGenerator().to_json())
75         self.response.out.write('OK')
76
77
78 class CachedDashboardHandler(webapp2.RequestHandler):
79     def get(self):
80         self.response.headers['Content-Type'] = 'application/json'
81         dashboard = PersistentCache.get_cache('dashboard')
82         if dashboard:
83             self.response.out.write(dashboard)
84         else:
85             schedule_dashboard_update()
86
87
88 def schedule_runs_update(test_id, branch_id, platform_id, regenerate_runs=True):
89     if regenerate_runs:
90         taskqueue.add(url='/api/test/runs/update', params={'id': test_id, 'branchid': branch_id, 'platformid': platform_id})
91     taskqueue.add(url='/api/test/runs/chart', params={'id': test_id, 'branchid': branch_id, 'platformid': platform_id,
92         'displayDays': 7})
93
94
95 def _get_test_branch_platform_ids(handler):
96     try:
97         test_id = int(handler.request.get('id', 0))
98         branch_id = int(handler.request.get('branchid', 0))
99         platform_id = int(handler.request.get('platformid', 0))
100         return test_id, branch_id, platform_id
101     except TypeError:
102         # FIXME: Output an error here
103         return 0, 0, 0
104
105
106 class RunsUpdateHandler(webapp2.RequestHandler):
107     def post(self):
108         self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
109         test_id, branch_id, platform_id = _get_test_branch_platform_ids(self)
110
111         branch = model_from_numeric_id(branch_id, Branch)
112         platform = model_from_numeric_id(platform_id, Platform)
113         test = model_from_numeric_id(test_id, Test)
114         assert branch
115         assert platform
116         assert test
117
118         Runs.update_or_insert(branch, platform, test)
119         self.response.out.write('OK')
120
121
122 class CachedRunsHandler(webapp2.RequestHandler):
123     def get(self):
124         self.response.headers['Content-Type'] = 'application/json'
125
126         test_id, branch_id, platform_id = _get_test_branch_platform_ids(self)
127         runs = Runs.json_by_ids(branch_id, platform_id, test_id)
128         if runs:
129             self.response.out.write(runs)
130         elif model_from_numeric_id(branch_id, Branch) and model_from_numeric_id(platform_id, Platform) and model_from_numeric_id(test_id, Test):
131             schedule_runs_update(test_id, branch_id, platform_id)
132
133
134 class RunsChartHandler(webapp2.RequestHandler):
135     def post(self):
136         x = 0
137         self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
138         test_id, branch_id, platform_id = _get_test_branch_platform_ids(self)
139
140         branch = model_from_numeric_id(branch_id, Branch)
141         platform = model_from_numeric_id(platform_id, Platform)
142         test = model_from_numeric_id(test_id, Test)
143         display_days = int(self.request.get('displayDays'))
144         assert branch
145         assert platform
146         assert test
147         params = Runs.update_or_insert(branch, platform, test).chart_params(display_days)
148         if not params:
149             return
150         dashboard_chart_file = urllib.urlopen('http://chart.googleapis.com/chart', urllib.urlencode(params))
151
152         DashboardImage.create(branch.id, platform.id, test.id, display_days, dashboard_chart_file.read())
153
154
155 class DashboardImageHandler(webapp2.RequestHandler):
156     def get(self, test_id, branch_id, platform_id, display_days):
157         try:
158             branch_id = int(branch_id)
159             platform_id = int(platform_id)
160             test_id = int(test_id)
161             display_days = int(display_days)
162         except ValueError:
163             self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
164             self.response.out.write('Failed')
165
166         self.response.headers['Content-Type'] = 'image/png'
167         self.response.out.write(DashboardImage.get_image(branch_id, platform_id, test_id, display_days))
168
169
170 def schedule_report_process(log):
171     taskqueue.add(url='/api/test/report/process', params={'id': log.key().id()})