Clean up ChunkedUpdateDrawingAreaProxy
[WebKit-https.git] / WebKitTools / TestResultServer / handlers / testfilehandler.py
1 # Copyright (C) 2010 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 #     * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 #     * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 #     * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 import logging
30 import urllib
31
32 from google.appengine.api import users
33 from google.appengine.ext import webapp
34 from google.appengine.ext.webapp import template
35
36 from model.jsonresults import JsonResults
37 from model.testfile import TestFile
38
39 PARAM_MASTER = "master"
40 PARAM_BUILDER = "builder"
41 PARAM_DIR = "dir"
42 PARAM_FILE = "file"
43 PARAM_NAME = "name"
44 PARAM_KEY = "key"
45 PARAM_TEST_TYPE = "testtype"
46 PARAM_INCREMENTAL = "incremental"
47 PARAM_TEST_LIST_JSON = "testlistjson"
48
49
50 class DeleteFile(webapp.RequestHandler):
51     """Delete test file for a given builder and name from datastore."""
52
53     def get(self):
54         key = self.request.get(PARAM_KEY)
55         master = self.request.get(PARAM_MASTER)
56         builder = self.request.get(PARAM_BUILDER)
57         test_type = self.request.get(PARAM_TEST_TYPE)
58         name = self.request.get(PARAM_NAME)
59
60         logging.debug(
61             "Deleting File, master: %s, builder: %s, test_type: %s, name: %s, key: %s.",
62             master, builder, test_type, name, key)
63
64         TestFile.delete_file(key, master, builder, test_type, name, 100)
65
66         # Display file list after deleting the file.
67         self.redirect("/testfile?master=%s&builder=%s&testtype=%s&name=%s"
68             % (master, builder, test_type, name))
69
70
71 class GetFile(webapp.RequestHandler):
72     """Get file content or list of files for given builder and name."""
73
74     def _get_file_list(self, master, builder, test_type, name):
75         """Get and display a list of files that matches builder and file name.
76
77         Args:
78             builder: builder name
79             test_type: type of the test
80             name: file name
81         """
82
83         files = TestFile.get_files(
84             master, builder, test_type, name, load_data=False, limit=100)
85         if not files:
86             logging.info("File not found, master: %s, builder: %s, test_type: %s, name: %s.",
87                          master, builder, test_type, name)
88             self.response.out.write("File not found")
89             return
90
91         template_values = {
92             "admin": users.is_current_user_admin(),
93             "master": master,
94             "builder": builder,
95             "test_type": test_type,
96             "name": name,
97             "files": files,
98         }
99         self.response.out.write(template.render("templates/showfilelist.html",
100                                                 template_values))
101
102     def _get_file_content(self, master, builder, test_type, name):
103         """Return content of the file that matches builder and file name.
104
105         Args:
106             builder: builder name
107             test_type: type of the test
108             name: file name
109         """
110
111         files = TestFile.get_files(
112             master, builder, test_type, name, load_data=True, limit=1)
113         if not files:
114             logging.info("File not found, master %s, builder: %s, test_type: %s, name: %s.",
115                          master, builder, test_type, name)
116             return None
117
118         return files[0].data
119
120     def _get_test_list_json(self, master, builder, test_type):
121         """Return json file with test name list only, do not include test
122            results and other non-test-data .
123
124         Args:
125             builder: builder name.
126             test_type: type of test results.
127         """
128
129         json = self._get_file_content(master, builder, test_type, "results.json")
130         if not json:
131             return None
132
133         return JsonResults.get_test_list(builder, json)
134
135     def get(self):
136         master = self.request.get(PARAM_MASTER)
137         builder = self.request.get(PARAM_BUILDER)
138         test_type = self.request.get(PARAM_TEST_TYPE)
139         name = self.request.get(PARAM_NAME)
140         dir = self.request.get(PARAM_DIR)
141         test_list_json = self.request.get(PARAM_TEST_LIST_JSON)
142
143         logging.debug(
144             "Getting files, master %s, builder: %s, test_type: %s, name: %s.",
145             master, builder, test_type, name)
146
147         # If parameter "dir" is specified or there is no builder or filename
148         # specified in the request, return list of files, otherwise, return
149         # file content.
150         if dir or not builder or not name:
151             return self._get_file_list(master, builder, test_type, name)
152
153         if name == "results.json" and test_list_json:
154             json = self._get_test_list_json(master, builder, test_type)
155         else:
156             json = self._get_file_content(master, builder, test_type, name)
157
158         if json:
159             self.response.headers["Content-Type"] = "text/plain; charset=utf-8"
160             self.response.out.write(json)
161         else:
162             self.error(404)
163
164 class Upload(webapp.RequestHandler):
165     """Upload test results file to datastore."""
166
167     def post(self):
168         file_params = self.request.POST.getall(PARAM_FILE)
169         if not file_params:
170             self.response.out.write("FAIL: missing upload file field.")
171             return
172
173         builder = self.request.get(PARAM_BUILDER)
174         if not builder:
175             self.response.out.write("FAIL: missing builder parameter.")
176             return
177
178         master = self.request.get(PARAM_MASTER)
179         test_type = self.request.get(PARAM_TEST_TYPE)
180         incremental = self.request.get(PARAM_INCREMENTAL)
181
182         logging.debug(
183             "Processing upload request, master: %s, builder: %s, test_type: %s.",
184             master, builder, test_type)
185
186         # There are two possible types of each file_params in the request:
187         # one file item or a list of file items.
188         # Normalize file_params to a file item list.
189         files = []
190         logging.debug("test: %s, type:%s", file_params, type(file_params))
191         for item in file_params:
192             if not isinstance(item, list) and not isinstance(item, tuple):
193                 item = [item]
194             files.extend(item)
195
196         errors = []
197         for file in files:
198             filename = file.filename.lower()
199             if ((incremental and filename == "results.json") or
200                 (filename == "incremental_results.json")):
201                 # Merge incremental json results.
202                 update_succeeded = JsonResults.update(master, builder, test_type, file.value)
203             else:
204                 update_succeeded = TestFile.update(
205                     master, builder, test_type, file.filename, file.value)
206
207             if not update_succeeded:
208                 errors.append(
209                     "Upload failed, master: %s, builder: %s, test_type: %s, name: %s." %
210                     (master, builder, test_type, file.filename))
211
212         if errors:
213             messages = "FAIL: " + "; ".join(errors)
214             logging.warning(messages)
215             self.response.set_status(500, messages)
216             self.response.out.write("FAIL")
217         else:
218             self.response.set_status(200)
219             self.response.out.write("OK")
220
221
222 class UploadForm(webapp.RequestHandler):
223     """Show a form so user can upload a file."""
224
225     def get(self):
226         template_values = {
227             "upload_url": "/testfile/upload",
228         }
229         self.response.out.write(template.render("templates/uploadform.html",
230                                                 template_values))