Home | History | Annotate | Download | only in handlers
      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))
    231