blob: 829ade6dbca4f994e0078abe4bbad0fe685dc6e0 [file] [log] [blame]
# Copyright 2015 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.
import base64
import mock_lorgnette
import os
from autotest_lib.client.cros import touch_playback_test_base
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib.cros import chrome
class documentscan_AppTestWithFakeLorgnette(
touch_playback_test_base.touch_playback_test_base):
""" Test that an extension using the DocumentScan Chrome API can
successfully retrieve a scanned document from a mocked version
of the lorgnette daemon.
"""
version = 1
# Application ID of the test scan application.
_APP_ID = 'mljeglgkknlanoeffbeehogdhkhnaidk'
# Document to open in order to launch the scan application.
_APP_DOCUMENT = 'scan.html'
# Window ID that references the scan application window.
_APP_WINDOW_ID = 'ChromeApps-Sample-Document-Scan'
# Element within the scan application document that contains image scans.
_APP_SCANNED_IMAGE_ELEMENT = 'scannedImages'
# Description of the fake mouse we add to the system.
_MOUSE_DESCRIPTION = 'amazon_mouse.prop'
# This input file was created as follows:
# - Insert USB mouse (in this case the Amazon mouse)
# - head /sys/class/input/*/name | grep -iB1 mouse
# This will give you the /sys/class/inputXX for the mouse.
# - evemu-record /dev/input/eventXX -1 > /tmp/button_click.event
# Move the mouse diagonally upwards to the upper left, move
# down and right a bit then click.
_PLAYBACK_FILE = 'button_click.event'
# Image file to serve up to Chrome in response to a scan request.
_IMAGE_FILENAME = 'lorgnette-test.png'
# Expected prefix for the SRC tag of the scanned images.
_BASE64_IMAGE_HEADER = 'data:image/png;base64,'
def _play_events(self, event_filename):
"""Simulate mouse events since the Chrome API enforces that
the scan action come from a user gesture.
@param event_filename string filename containing events to play back
"""
file_path = os.path.join(self.bindir, event_filename)
self._blocking_playback(file_path, touch_type='mouse')
def _launch_app(self, chrome_instance):
"""Launches the sample scanner Chrome app.
@param chrome_instance object of type chrome.Chrome
"""
self._extension = chrome_instance.get_extension(self._extension_path)
# TODO(pstew): chrome.management.launchApp() would have been
# ideal here, but is not available even after adding the
# "management" permission to the app. Instead, we perform
# the launch action of the extension directly.
cmd = '''
chrome.app.window.create('%s', {
singleton: true,
id: '%s',
state: 'fullscreen'
});
''' % (self._APP_DOCUMENT, self._APP_WINDOW_ID)
self._extension.ExecuteJavaScript(cmd)
def _query_scan_element(self, query):
"""Queries the "scannedImages" element within the app window.
@param query string javascript query to execute on the DIV element.
"""
cmd = '''
app_window = chrome.app.window.get('%s');
element = app_window.contentWindow.document.getElementById('%s');
element.%s;
''' % (self._APP_WINDOW_ID, self._APP_SCANNED_IMAGE_ELEMENT, query)
return self._extension.EvaluateJavaScript(cmd)
def _get_scan_count(self):
"""Counts the number of successful scanned images displayed.
@param chrome_instance object of type chrome.Chrome
"""
result = self._query_scan_element('childNodes.length')
# Subtract 1 for the text node member of the DIV element.
return int(result) - 1
def _validate_image_data(self, expected_image_data):
"""Validates that the scanned image displayed by the app is the same
as the image provided by the fake lorgnette daemon.
"""
image_src = self._query_scan_element('childNodes[0].src')
if not image_src.startswith(self._BASE64_IMAGE_HEADER):
raise error.TestError(
'Image SRC does not start with base64 data header: %s' %
image_src)
base64_data = image_src[len(self._BASE64_IMAGE_HEADER):]
data = base64.b64decode(base64_data)
if expected_image_data != data:
raise error.TestError('Image data from tag is not the same as '
'the test image data')
def _validate_mock_method_calls(self, calls):
"""Validate the method calls made on the lorgnette mock instance.
@param calls list of MethodCall named tuples from mock lorgnette.
"""
if len(calls) != 2:
raise error.TestError('Expected 2 method calls but got: %r' % calls)
for index, method_name in enumerate(['ListScanners', 'ScanImage']):
if calls[index].method != method_name:
raise error.TestError('Call #%d was %s instead of expected %s' %
(index, calls[index].method, method_name))
def run_once(self):
"""Entry point of this test."""
mouse_file = os.path.join(self.bindir, self._MOUSE_DESCRIPTION)
self._emulate_mouse(property_file=mouse_file)
self._extension_path = os.path.join(os.path.dirname(__file__),
'document_scan_test_app')
with chrome.Chrome(extension_paths=[self._extension_path],
init_network_controller=True) as cr:
img = os.path.join(self.bindir, self._IMAGE_FILENAME)
with mock_lorgnette.MockLorgnette(img) as lorgnette_instance:
self._launch_app(cr)
self._play_events(self._PLAYBACK_FILE)
scan_count = self._get_scan_count()
if scan_count != 1:
raise error.TestError('Scan count is %d instead of 1' %
scan_count)
self._validate_image_data(lorgnette_instance.image_data)
self._validate_mock_method_calls(
lorgnette_instance.get_method_calls())