1# Copyright (c) 2010 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
5import os
6import logging
7
8from autotest_lib.client.bin import utils
9from autotest_lib.client.common_lib import error
10from autotest_lib.client.common_lib.cros import chrome
11from autotest_lib.client.cros import service_stopper
12from autotest_lib.client.cros.graphics import graphics_utils
13
14# to run this test manually on a test target
15# ssh root@machine
16# cd /usr/local/autotest/deps/glbench
17# stop ui
18# ./windowmanagertest --screenshot1_sec 2 --screenshot2_sec 1 --cooldown_sec 1 \
19#    --screenshot1_cmd \
20#        "/usr/local/autotest/bin/screenshot.py screenshot1_generated.png" \
21#    --screenshot2_cmd \
22#        "/usr/local/autotest/bin/screenshot.py screenshot2_generated.png"
23# start ui
24
25
26class graphics_Sanity(graphics_utils.GraphicsTest):
27    """
28    This test is meant to be used as a quick sanity check for GL/GLES.
29    """
30    version = 1
31
32    # None-init vars used by cleanup() here, in case setup() fails
33    _services = None
34
35    def setup(self):
36        self.job.setup_dep(['glbench'])
37        dep = 'glbench'
38        dep_dir = os.path.join(self.autodir, 'deps', dep)
39        self.job.install_pkg(dep, 'dep', dep_dir)
40
41    def cleanup(self):
42        super(graphics_Sanity, self).cleanup()
43        if self._services:
44            self._services.restore_services()
45
46    def test_something_on_screen(self):
47        """Check if something is drawn on screen: i.e. not a black screen.
48
49        @raises TestFail if we cannot determine there was something on screen.
50        """
51
52        def can_take_screenshot():
53            """Check that taking a screenshot can succeed.
54
55            There are cases when trying to take a screenshot on the device
56            fails. e.g. the display has gone to sleep, we have logged out and
57            the UI has not come back up yet etc.
58            """
59            try:
60                graphics_utils.take_screenshot(self.resultsdir,
61                                               'temp screenshot', '.png')
62                return True
63            except:
64                return False
65
66        utils.poll_for_condition(
67            can_take_screenshot,
68            sleep_interval=1,
69            desc='Failed to take a screenshot. There may be an issue with this '
70            'ChromeOS image.')
71
72        w, h = graphics_utils.get_internal_resolution()
73        megapixels = (w * h) / 1000000
74        filesize_threshold = 25 * megapixels
75        screenshot1 = graphics_utils.take_screenshot(self.resultsdir,
76                                                     'oobe or signin', '.png')
77
78        with chrome.Chrome() as cr:
79            tab = cr.browser.tabs[0]
80            tab.Navigate('chrome://settings')
81            tab.WaitForDocumentReadyStateToBeComplete()
82
83            screenshot2 = graphics_utils.take_screenshot(
84                self.resultsdir, 'settings page', '.png')
85
86        for screenshot in [screenshot1, screenshot2]:
87            file_size_kb = os.path.getsize(screenshot) / 1000
88
89            # Use compressed file size to tell if anything is on screen.
90            if file_size_kb > filesize_threshold:
91                return
92
93        raise error.TestFail(
94            'Screenshot filesize is very small. This indicates that '
95            'there is nothing on screen. This ChromeOS image could be '
96            'unusable. Check the screenshot in the results folder.')
97
98    def test_generated_screenshots_match_expectation(self):
99        """Draws a texture with a soft ellipse twice and captures each image.
100        Compares the output fuzzily against reference images.
101        """
102        self._services = service_stopper.ServiceStopper(['ui'])
103        self._services.stop_services()
104
105        screenshot1_reference = os.path.join(self.bindir,
106                                             'screenshot1_reference.png')
107        screenshot1_generated = os.path.join(self.resultsdir,
108                                             'screenshot1_generated.png')
109        screenshot1_resized = os.path.join(self.resultsdir,
110                                           'screenshot1_generated_resized.png')
111        screenshot2_reference = os.path.join(self.bindir,
112                                             'screenshot2_reference.png')
113        screenshot2_generated = os.path.join(self.resultsdir,
114                                             'screenshot2_generated.png')
115        screenshot2_resized = os.path.join(self.resultsdir,
116                                           'screenshot2_generated_resized.png')
117
118        exefile = os.path.join(self.autodir, 'deps/glbench/windowmanagertest')
119
120        # Delay before screenshot: 1 second has caused failures.
121        options = ' --screenshot1_sec 2'
122        options += ' --screenshot2_sec 1'
123        options += ' --cooldown_sec 1'
124        # perceptualdiff can handle only 8 bit images.
125        screenshot_cmd = ' "/usr/local/autotest/bin/screenshot.py %s"'
126        options += ' --screenshot1_cmd' + screenshot_cmd % screenshot1_generated
127        options += ' --screenshot2_cmd' + screenshot_cmd % screenshot2_generated
128
129        cmd = exefile + ' ' + options
130        utils.run(
131            cmd, stdout_tee=utils.TEE_TO_LOGS, stderr_tee=utils.TEE_TO_LOGS)
132
133        convert_cmd = ('convert -channel RGB -colorspace RGB -depth 8'
134                       " -resize '100x100!' %s %s")
135        utils.system(convert_cmd % (screenshot1_generated, screenshot1_resized))
136        utils.system(convert_cmd % (screenshot2_generated, screenshot2_resized))
137        os.remove(screenshot1_generated)
138        os.remove(screenshot2_generated)
139
140        diff_cmd = 'perceptualdiff -verbose %s %s'
141        utils.system(diff_cmd % (screenshot1_reference, screenshot1_resized))
142        utils.system(diff_cmd % (screenshot2_reference, screenshot2_resized))
143
144    def run_once(self):
145        if graphics_utils.get_display_resolution() is None:
146            logging.warning('Skipping test because there is no screen')
147            return
148        self.add_failures('graphics_Sanity')
149        self.wake_screen_with_keyboard()
150        self.test_something_on_screen()
151        self.test_generated_screenshots_match_expectation()
152        self.remove_failures('graphics_Sanity')
153