Home | History | Annotate | Download | only in RebaselineLogServer
      1 # Copyright (C) 2013 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 datetime
     30 import logging
     31 import webapp2
     32 
     33 from google.appengine.ext import ndb
     34 from google.appengine.ext.webapp import template
     35 from google.appengine.ext.db import BadRequestError
     36 
     37 # A simple log server for rebaseline-o-matic.
     38 #
     39 # Accepts updates to the same log entry and shows a simple status page.
     40 # Has a special state for the case where there are no NeedsRebaseline
     41 # lines in TestExpectations to avoid cluttering the log with useless
     42 # entries every 30 seconds.
     43 #
     44 # Other than that, new updatelog calls append to the most recent log
     45 # entry until they have the newentry parameter, in which case, it
     46 # starts a new log entry.
     47 
     48 LOG_PARAM = "log"
     49 NEW_ENTRY_PARAM = "newentry"
     50 # FIXME: no_needs_rebaseline is never used anymore. Remove support for it.
     51 # Instead, add UI to logs.html to collapse short entries.
     52 NO_NEEDS_REBASELINE_PARAM = "noneedsrebaseline"
     53 NUM_LOGS_PARAM = "numlogs"
     54 BEFORE_PARAM = "before"
     55 
     56 
     57 class LogEntry(ndb.Model):
     58     content = ndb.TextProperty()
     59     date = ndb.DateTimeProperty(auto_now_add=True)
     60     is_no_needs_rebaseline = ndb.BooleanProperty()
     61 
     62 
     63 def logs_query():
     64     return LogEntry.query().order(-LogEntry.date)
     65 
     66 
     67 class UpdateLog(webapp2.RequestHandler):
     68     def post(self):
     69         new_log_data = self.request.POST.get(LOG_PARAM)
     70         # This entry is set to on whenever a new auto-rebaseline run is going to
     71         # start logging entries. If this is not on, then the log will get appended
     72         # to the most recent log entry.
     73         new_entry = self.request.POST.get(NEW_ENTRY_PARAM) == "on"
     74         # The case of no NeedsRebaseline lines in TestExpectations is special-cased
     75         # to always overwrite the previous noneedsrebaseline entry in the log to
     76         # avoid cluttering the log with useless empty posts. It just updates the
     77         # date of the entry so that users can see that rebaseline-o-matic is still
     78         # running.
     79         # FIXME: no_needs_rebaseline is never used anymore. Remove support for it.
     80         no_needs_rebaseline = self.request.POST.get(NO_NEEDS_REBASELINE_PARAM) == "on"
     81 
     82         out = "Wrote new log entry."
     83         if not new_entry or no_needs_rebaseline:
     84             log_entries = logs_query().fetch(1)
     85             if log_entries:
     86                 log_entry = log_entries[0]
     87                 log_entry.date = datetime.datetime.now()
     88                 if no_needs_rebaseline:
     89                     # Don't write out a new log entry for repeated no_needs_rebaseline cases.
     90                     # The repeated entries just add noise to the logs.
     91                     if log_entry.is_no_needs_rebaseline:
     92                         out = "Overwrote existing no needs rebaseline log."
     93                     else:
     94                         out = "Wrote new no needs rebaseline log."
     95                         new_entry = True
     96                         new_log_data = ""
     97                 elif log_entry.is_no_needs_rebaseline:
     98                     out = "Previous entry was a no need rebaseline log. Writing a new log."
     99                     new_entry = True
    100                 else:
    101                     out = "Added to existing log entry."
    102                     log_entry.content = log_entry.content + "\n" + new_log_data
    103 
    104         if new_entry or not log_entries:
    105             log_entry = LogEntry(content=new_log_data, is_no_needs_rebaseline=no_needs_rebaseline)
    106 
    107         try:
    108             log_entry.put()
    109         except BadRequestError:
    110             out = "Created new log entry because the previous one exceeded the max length."
    111             LogEntry(content=new_log_data, is_no_needs_rebaseline=no_needs_rebaseline).put()
    112 
    113         self.response.out.write(out)
    114 
    115 
    116 class UploadForm(webapp2.RequestHandler):
    117     def get(self):
    118         self.response.out.write(template.render("uploadform.html", {
    119             "update_log_url": "/updatelog",
    120             "set_no_needs_rebaseline_url": "/noneedsrebaselines",
    121             "log_param": LOG_PARAM,
    122             "new_entry_param": NEW_ENTRY_PARAM,
    123             "no_needs_rebaseline_param": NO_NEEDS_REBASELINE_PARAM,
    124         }))
    125 
    126 
    127 class ShowLatest(webapp2.RequestHandler):
    128     def get(self):
    129         query = logs_query()
    130 
    131         before = self.request.get(BEFORE_PARAM)
    132         if before:
    133             date = datetime.datetime.strptime(before, "%Y-%m-%dT%H:%M:%SZ")
    134             query = query.filter(LogEntry.date < date)
    135 
    136         num_logs = self.request.get(NUM_LOGS_PARAM)
    137         logs = query.fetch(int(num_logs) if num_logs else 3)
    138 
    139         self.response.out.write(template.render("logs.html", {
    140             "logs": logs,
    141             "num_logs_param": NUM_LOGS_PARAM,
    142             "before_param": BEFORE_PARAM,
    143         }))
    144 
    145 
    146 routes = [
    147     ('/uploadform', UploadForm),
    148     ('/updatelog', UpdateLog),
    149     ('/', ShowLatest),
    150 ]
    151 
    152 app = webapp2.WSGIApplication(routes, debug=True)
    153