1# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""Touch firmware test report in html format.""" 6 7import os 8import urllib 9 10import common_util 11import firmware_log 12import test_conf as conf 13 14from firmware_utils import get_fw_and_date 15from string import Template 16from validators import get_base_name_and_segment 17 18 19class TemplateHtml: 20 """An html Template.""" 21 22 def __init__(self, image_width, image_height, score_colors): 23 self.score_colors = score_colors 24 25 # Define the template of the doc 26 self.doc = Template('$head $test_version $logs $tail') 27 self.table = Template('<table border="3" width="100%"> $gestures ' 28 '</table>') 29 self.gestures = [] 30 31 # Define a template to show a gesture information including 32 # the gesture name, variation, prompt, image, and test results. 33 self.gesture_template = Template(''' 34 <tr> 35 <td><table> 36 <tr> 37 <h3> $gesture_name.$variation </h3> 38 <h5> $prompt </h5> 39 </tr> 40 <tr> 41 <img src="data:image/png;base64,\n$image" 42 alt="$filename" width="%d" height="%d" /> 43 </tr> 44 </table></td> 45 <td><table> 46 $vlogs 47 </table></td> 48 </tr> 49 ''' % (image_width, image_height)) 50 51 self.criteria_string = ' criteria: %s' 52 self.validator_template = Template(''' 53 <tr> 54<pre><span style="color:$color"><b>$name</b></span> 55$details 56$criteria 57</pre> 58 </tr> 59 ''') 60 61 self.detail_template = Template('<tr><h5> $detail </h5></tr>') 62 self._fill_doc() 63 64 def _html_head(self): 65 """Fill the head of an html document.""" 66 head = '\n'.join(['<!DOCTYPE html>', '<html>', '<body>']) 67 return head 68 69 def _html_tail(self): 70 """Fill the tail of an html document.""" 71 tail = '\n'.join(['</body>', '</html>']) 72 return tail 73 74 def _fill_doc(self): 75 """Fill in fields into the doc.""" 76 self.doc = Template(self.doc.safe_substitute(head=self._html_head(), 77 tail=self._html_tail())) 78 79 def get_score_color(self, score): 80 """Present the score in different colors.""" 81 for s, c in self.score_colors: 82 if score >= s: 83 return c 84 85 def _insert_details(self, details): 86 details_content = [] 87 for detail in details: 88 details_content.append(' ' * 2 + detail.strip()) 89 return '<br>'.join(details_content) 90 91 def _insert_vlog(self, vlog): 92 """Insert a single vlog.""" 93 base_name, _ = get_base_name_and_segment(vlog.name) 94 criteria_string = self.criteria_string % vlog.criteria 95 vlog_content = self.validator_template.safe_substitute( 96 name=vlog.name, 97 details=self._insert_details(vlog.details), 98 criteria=criteria_string, 99 color='blue', 100 score=vlog.score) 101 return vlog_content 102 103 def _insert_vlogs(self, vlogs): 104 """Insert multiple vlogs.""" 105 vlogs_content = [] 106 for vlog in vlogs: 107 vlogs_content.append(self._insert_vlog(vlog)) 108 return '<hr>'.join(vlogs_content) 109 110 def insert_gesture(self, glog, image, image_filename): 111 """Insert glog, image, and vlogs.""" 112 vlogs_content = self._insert_vlogs(glog.vlogs) 113 gesture = self.gesture_template.safe_substitute( 114 gesture_name=glog.name, 115 variation=glog.variation, 116 prompt=glog.prompt, 117 image=image, 118 filename=image_filename, 119 vlogs=vlogs_content) 120 self.gestures.append(gesture) 121 122 def get_doc(self, test_version): 123 gestures = ''.join(self.gestures) 124 new_table = self.table.safe_substitute(gestures=gestures) 125 new_doc = self.doc.safe_substitute(test_version=test_version, 126 logs=new_table) 127 return new_doc 128 129 130class ReportHtml: 131 """Firmware Report in html format.""" 132 133 def __init__(self, filename, screen_size, touch_device_window_size, 134 score_colors, test_version): 135 self.html_filename = filename 136 self.screen_size = screen_size 137 self.image_width = self.screen_size[0] * 0.5 138 touch_width, touch_height = touch_device_window_size 139 self.image_height = self.image_width / touch_width * touch_height 140 self.doc = TemplateHtml(self.image_width, self.image_height, 141 score_colors) 142 self._reset_content() 143 self.test_version = test_version 144 fw_and_date = get_fw_and_date(filename) 145 self.rlog = firmware_log.RoundLog(test_version, *fw_and_date) 146 147 def __del__(self): 148 self.stop() 149 150 def stop(self): 151 """Close the file.""" 152 with open(self.html_filename, 'w') as report_file: 153 report_file.write(self.doc.get_doc(self.test_version)) 154 # Make a copy to /tmp so that it could be viewed in Chrome. 155 tmp_copy = os.path.join(conf.docroot, 156 os.path.basename(self.html_filename)) 157 copy_cmd = 'cp %s %s' % (self.html_filename, tmp_copy) 158 common_util.simple_system(copy_cmd) 159 160 # Dump the logs to a byte stream file 161 log_file_root = os.path.splitext(self.html_filename)[0] 162 log_filename = os.extsep.join([log_file_root, 'log']) 163 self.rlog.dump(log_filename) 164 165 def _reset_content(self): 166 self.glog = firmware_log.GestureLog() 167 self.encoded_image='' 168 self.image_filename='' 169 170 def _get_content(self): 171 return [self.glog, self.encoded_image, self.image_filename] 172 173 def _encode_base64(self, filename): 174 """Encode a file in base 64 format.""" 175 if (filename is None) or (not os.path.isfile(filename)): 176 return None 177 encoded = urllib.quote(open(filename, "rb").read().encode("base64")) 178 return encoded 179 180 def flush(self): 181 """Flush the current gesture including gesture log, image and 182 validator logs. 183 """ 184 content = self._get_content() 185 # It is ok to flush the gesture log even when there are no mtplot images 186 if self.glog: 187 # Write the content to the html file. 188 self.doc.insert_gesture(*content) 189 # Write the logs to the round log. 190 self.rlog.insert_glog(self.glog) 191 self._reset_content() 192 193 def insert_image(self, filename): 194 """Insert an image into the document.""" 195 self.encoded_image = self._encode_base64(filename) 196 self.image_filename = filename 197 198 def insert_result(self, text): 199 """Insert the text into the document.""" 200 self.result += text 201 202 def insert_gesture_log(self, glog): 203 """Update the gesture log.""" 204 self.glog = glog 205 206 def insert_validator_logs(self, vlogs): 207 """Update the validator logs.""" 208 self.glog.vlogs = vlogs 209