Home | History | Annotate | Download | only in layout_tests
      1 # Copyright (C) 2014 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 json
     30 import logging
     31 
     32 
     33 class ProcessJsonData(object):
     34 
     35     def __init__(self, current_result_json_dict, old_failing_results_list, old_full_results_list):
     36         self._current_result_json_dict = current_result_json_dict
     37         self._old_failing_results_list = old_failing_results_list
     38         self._old_full_results_list = old_full_results_list
     39         self._final_result = []
     40 
     41     def _get_test_result(self, test_result_data):
     42         actual = test_result_data['actual']
     43         expected = test_result_data['expected']
     44         if actual == 'SKIP':
     45             return actual
     46         if actual == expected:
     47             return 'HASSTDERR' if test_result_data.get('has_stderr') == 'true' else 'PASS'
     48         else:
     49             return actual
     50 
     51     def _recurse_json_object(self, json_object, key_list):
     52         for key in key_list:
     53             try:
     54                 json_object = json_object[key]
     55             except KeyError:
     56                 return 'NOTFOUND'
     57         return self._get_test_result(json_object)
     58 
     59     def _process_previous_json_results(self, key_list):
     60         row = []
     61         length = len(self._old_failing_results_list)
     62         for index in range(0, length):
     63             result = self._recurse_json_object(self._old_failing_results_list[index]["tests"], key_list)
     64             if result == 'NOTFOUND':
     65                 result = self._recurse_json_object(self._old_full_results_list[index]["tests"], key_list)
     66             row.append(result)
     67         return row
     68 
     69     def _add_archived_result(self, json_object, result):
     70         json_object['archived_results'] = result
     71 
     72     def _process_json_object(self, json_object, keyList):
     73         for key, subdict in json_object.iteritems():
     74             if type(subdict) == dict:
     75                 self._process_json_object(subdict, keyList + [key])
     76             else:
     77                 row = [self._get_test_result(json_object)]
     78                 row += self._process_previous_json_results(keyList)
     79                 json_object.clear()
     80                 self._add_archived_result(json_object, row)
     81                 return
     82 
     83     def generate_archived_result(self):
     84         for key in self._current_result_json_dict["tests"]:
     85             self._process_json_object(self._current_result_json_dict["tests"][key], [key])
     86         return self._current_result_json_dict
     87 
     88 
     89 class DashBoardGenerator(object):
     90 
     91     def __init__(self, port):
     92         self._port = port
     93         self._filesystem = port.host.filesystem
     94         self._results_directory = self._port.results_directory()
     95         self._results_directory_path = self._filesystem.dirname(self._results_directory)
     96         self._current_result_json_dict = {}
     97         self._old_failing_results_list = []
     98         self._old_full_results_list = []
     99         self._final_result = []
    100 
    101     def _add_individual_result_links(self, results_directories):
    102         archived_results_file_list = [(file + '/results.html') for file in results_directories]
    103         archived_results_file_list.insert(0, 'results.html')
    104         self._current_result_json_dict['result_links'] = archived_results_file_list
    105 
    106     def _copy_dashboard_html(self):
    107         dashboard_file = self._filesystem.join(self._results_directory, 'dashboard.html')
    108         dashboard_html_file_path = self._filesystem.join(self._port.layout_tests_dir(), 'fast/harness/archived-results-dashboard.html')
    109         if not self._filesystem.exists(dashboard_file):
    110             if self._filesystem.exists(dashboard_html_file_path):
    111                 self._filesystem.copyfile(dashboard_html_file_path, dashboard_file)
    112 
    113     def _initialize(self):
    114         file_list = self._filesystem.listdir(self._results_directory_path)
    115         results_directories = []
    116         for dir in file_list:
    117             full_dir_path = self._filesystem.join(self._results_directory_path, dir)
    118             if self._filesystem.isdir(full_dir_path):
    119                 if self._results_directory in full_dir_path:
    120                     results_directories.append(full_dir_path)
    121         results_directories.sort(reverse=True, key=lambda x: self._filesystem.mtime(x))
    122         current_failing_results_json_file = self._filesystem.join(results_directories[0], 'failing_results.json')
    123         input_json_string = self._filesystem.read_text_file(current_failing_results_json_file)
    124         input_json_string = input_json_string[12:-2]   # Remove preceeding string ADD_RESULTS( and ); at the end
    125         self._current_result_json_dict['tests'] = json.loads(input_json_string)['tests']
    126         results_directories = results_directories[1:]
    127 
    128         # To add hyperlink to individual results.html
    129         self._add_individual_result_links(results_directories)
    130 
    131         # Load the remaining stale layout test results Json's to create the dashboard
    132         for json_file in results_directories:
    133             failing_json_file_path = self._filesystem.join(json_file, 'failing_results.json')
    134             full_json_file_path = self._filesystem.join(json_file, 'full_results.json')
    135             json_string = self._filesystem.read_text_file(failing_json_file_path)
    136             json_string = json_string[12:-2]   # Remove preceeding string ADD_RESULTS( and ); at the end
    137             self._old_failing_results_list.append(json.loads(json_string))
    138             json_string_full_result = self._filesystem.read_text_file(full_json_file_path)
    139             self._old_full_results_list.append(json.loads(json_string_full_result))
    140         self._copy_dashboard_html()
    141 
    142     def generate(self):
    143         self._initialize()
    144 
    145         # There must be atleast one archived result to be processed
    146         if self._current_result_json_dict:
    147             process_json_data = ProcessJsonData(self._current_result_json_dict, self._old_failing_results_list, self._old_full_results_list)
    148             self._final_result = process_json_data.generate_archived_result()
    149             final_json = json.dumps(self._final_result)
    150             final_json = 'ADD_RESULTS(' + final_json + ');'
    151             archived_results_file_path = self._filesystem.join(self._results_directory, 'archived_results.json')
    152             self._filesystem.write_text_file(archived_results_file_path, final_json)
    153