• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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