blob: 3282c374f1132d801dc4d8f52a49c11a1fe7351c [file] [log] [blame]
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Touch firmware test report in html format."""
import os
import urllib
import common_util
import firmware_log
import test_conf as conf
from firmware_utils import get_fw_and_date
from string import Template
from validators import get_base_name_and_segment
class TemplateHtml:
"""An html Template."""
def __init__(self, image_width, image_height, score_colors):
self.score_colors = score_colors
# Define the template of the doc
self.doc = Template('$head $test_version $logs $tail')
self.table = Template('<table border="3" width="100%"> $gestures '
'</table>')
self.gestures = []
# Define a template to show a gesture information including
# the gesture name, variation, prompt, image, and test results.
self.gesture_template = Template('''
<tr>
<td><table>
<tr>
<h3> $gesture_name.$variation </h3>
<h5> $prompt </h5>
</tr>
<tr>
<img src="data:image/png;base64,\n$image"
alt="$filename" width="%d" height="%d" />
</tr>
</table></td>
<td><table>
$vlogs
</table></td>
</tr>
''' % (image_width, image_height))
self.criteria_string = ' criteria: %s'
self.validator_template = Template('''
<tr>
<pre><span style="color:$color"><b>$name</b></span>
$details
$criteria
</pre>
</tr>
''')
self.detail_template = Template('<tr><h5> $detail </h5></tr>')
self._fill_doc()
def _html_head(self):
"""Fill the head of an html document."""
head = '\n'.join(['<!DOCTYPE html>', '<html>', '<body>'])
return head
def _html_tail(self):
"""Fill the tail of an html document."""
tail = '\n'.join(['</body>', '</html>'])
return tail
def _fill_doc(self):
"""Fill in fields into the doc."""
self.doc = Template(self.doc.safe_substitute(head=self._html_head(),
tail=self._html_tail()))
def get_score_color(self, score):
"""Present the score in different colors."""
for s, c in self.score_colors:
if score >= s:
return c
def _insert_details(self, details):
details_content = []
for detail in details:
details_content.append(' ' * 2 + detail.strip())
return '<br>'.join(details_content)
def _insert_vlog(self, vlog):
"""Insert a single vlog."""
base_name, _ = get_base_name_and_segment(vlog.name)
criteria_string = self.criteria_string % vlog.criteria
vlog_content = self.validator_template.safe_substitute(
name=vlog.name,
details=self._insert_details(vlog.details),
criteria=criteria_string,
color='blue',
score=vlog.score)
return vlog_content
def _insert_vlogs(self, vlogs):
"""Insert multiple vlogs."""
vlogs_content = []
for vlog in vlogs:
vlogs_content.append(self._insert_vlog(vlog))
return '<hr>'.join(vlogs_content)
def insert_gesture(self, glog, image, image_filename):
"""Insert glog, image, and vlogs."""
vlogs_content = self._insert_vlogs(glog.vlogs)
gesture = self.gesture_template.safe_substitute(
gesture_name=glog.name,
variation=glog.variation,
prompt=glog.prompt,
image=image,
filename=image_filename,
vlogs=vlogs_content)
self.gestures.append(gesture)
def get_doc(self, test_version):
gestures = ''.join(self.gestures)
new_table = self.table.safe_substitute(gestures=gestures)
new_doc = self.doc.safe_substitute(test_version=test_version,
logs=new_table)
return new_doc
class ReportHtml:
"""Firmware Report in html format."""
def __init__(self, filename, screen_size, touch_device_window_size,
score_colors, test_version):
self.html_filename = filename
self.screen_size = screen_size
self.image_width = self.screen_size[0] * 0.5
touch_width, touch_height = touch_device_window_size
self.image_height = self.image_width / touch_width * touch_height
self.doc = TemplateHtml(self.image_width, self.image_height,
score_colors)
self._reset_content()
self.test_version = test_version
fw_and_date = get_fw_and_date(filename)
self.rlog = firmware_log.RoundLog(test_version, *fw_and_date)
def __del__(self):
self.stop()
def stop(self):
"""Close the file."""
with open(self.html_filename, 'w') as report_file:
report_file.write(self.doc.get_doc(self.test_version))
# Make a copy to /tmp so that it could be viewed in Chrome.
tmp_copy = os.path.join(conf.docroot,
os.path.basename(self.html_filename))
copy_cmd = 'cp %s %s' % (self.html_filename, tmp_copy)
common_util.simple_system(copy_cmd)
# Dump the logs to a byte stream file
log_file_root = os.path.splitext(self.html_filename)[0]
log_filename = os.extsep.join([log_file_root, 'log'])
self.rlog.dump(log_filename)
def _reset_content(self):
self.glog = firmware_log.GestureLog()
self.encoded_image=''
self.image_filename=''
def _get_content(self):
return [self.glog, self.encoded_image, self.image_filename]
def _encode_base64(self, filename):
"""Encode a file in base 64 format."""
if (filename is None) or (not os.path.isfile(filename)):
return None
encoded = urllib.quote(open(filename, "rb").read().encode("base64"))
return encoded
def flush(self):
"""Flush the current gesture including gesture log, image and
validator logs.
"""
content = self._get_content()
# It is ok to flush the gesture log even when there are no mtplot images
if self.glog:
# Write the content to the html file.
self.doc.insert_gesture(*content)
# Write the logs to the round log.
self.rlog.insert_glog(self.glog)
self._reset_content()
def insert_image(self, filename):
"""Insert an image into the document."""
self.encoded_image = self._encode_base64(filename)
self.image_filename = filename
def insert_result(self, text):
"""Insert the text into the document."""
self.result += text
def insert_gesture_log(self, glog):
"""Update the gesture log."""
self.glog = glog
def insert_validator_logs(self, vlogs):
"""Update the validator logs."""
self.glog.vlogs = vlogs