blob: 07ea67896eee04cb93f473a592a2cfd3e74ad9e4 [file] [log] [blame]
# Copyright (c) 2010 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 logging, os, re, string, time
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.cros import cros_ui, cros_ui_test
class desktopui_IBusTest(cros_ui_test.UITest):
version = 1
preserve_srcdir = True
def setup(self):
self._ibus_job = None
self.job.setup_dep(['ibusclient'])
def run_ibusclient(self, options):
cmd = cros_ui.xcommand_as('%s %s' % (self.exefile, options), 'chronos')
return utils.system_output(cmd, retain_output=True)
def test_reachable(self):
out = self.run_ibusclient('check_reachable')
if not 'YES' in out:
raise error.TestFail('ibus-daemon is not reachable')
def test_supported_engines(self):
out = self.run_ibusclient('list_engines')
engine_names = out.splitlines()
# We expect these engines to exist.
expected_engine_names = ['mozc-chewing', 'mozc-hangul', 'pinyin',
'm17n:ar:kbd']
for expected_engine_name in expected_engine_names:
if not expected_engine_name in engine_names:
raise error.TestFail('Engine not found: ' +
expected_engine_name)
def test_config(self, type_name):
wrong_type_name = 'string'
if type_name == 'string':
wrong_type_name = 'int'
# First, write a dummy value which is not |type_name| type to make sure
# the second set_config overwrites this |wrong_type_name| value.
out = self.run_ibusclient('set_config %s' % wrong_type_name)
if not 'OK' in out:
raise error.TestFail('Failed to set %s value to '
'the ibus config service' % wrong_type_name)
# Then overwrite a value of |type_name| type.
out = self.run_ibusclient('set_config %s' % type_name)
if not 'OK' in out:
raise error.TestFail('Failed to set %s value to '
'the ibus config service' % type_name)
out = self.run_ibusclient('get_config %s' % type_name)
if not 'OK' in out:
raise error.TestFail('Failed to get %s value from '
'the ibus config service' % type_name)
out = self.run_ibusclient('unset_config')
if not 'OK' in out:
raise error.TestFail('Failed to unset %s value from '
'the ibus config service' % type_name)
# TODO(yusukes): Add a get_config test here to make sure the value is
# actually removed. See also http://crosbug.com/2801/.
def test_check_unused_ibus_values(self):
engine_list = ['mozc-hangul', 'pinyin', 'mozc', 'mozc-chewing']
expected_unread = set(['engine/PinyinCorrectPinyin_UEN_UN',
'engine/PinyinFuzzyPinyin_Z_ZH',
'engine/PinyinFuzzyPinyin_CH_C',
'engine/PinyinFuzzyPinyin_S_SH',
'engine/PinyinFuzzyPinyin_EN_ENG',
'engine/PinyinFuzzyPinyin_AN_ANG',
'engine/PinyinFuzzyPinyin_IANG_IAN',
'engine/PinyinSpecialPhrases',
'engine/PinyinFuzzyPinyin_UAN_UANG',
'engine/PinyinFuzzyPinyin_IN_ING',
'engine/PinyinFuzzyPinyin_G_K',
'engine/PinyinCorrectPinyin_UEI_UI',
'engine/PinyinCorrectPinyin_UE_VE',
'engine/PinyinFuzzyPinyin_F_H',
'engine/PinyinFuzzyPinyin_SH_S',
'engine/PinyinIncompletePinyin',
'engine/PinyinFuzzyPinyin_L_R',
'engine/PinyinFuzzyPinyin_K_G',
'engine/PinyinFuzzyPinyin_ANG_AN',
'engine/PinyinFuzzyPinyin_C_CH',
'engine/PinyinCorrectPinyin_MG_NG',
'engine/PinyinLookupTableOrientation',
'engine/PinyinFuzzyPinyin_L_N',
'engine/PinyinFuzzyPinyin_ING_IN',
'engine/PinyinFuzzyPinyin_IAN_IANG',
'engine/PinyinFuzzyPinyin_N_L',
'engine/PinyinCorrectPinyin_IOU_IU',
'engine/PinyinFuzzyPinyin_ENG_EN',
'engine/PinyinCorrectPinyin_VE_UE',
'engine/PinyinCorrectPinyin_V_U',
'engine/PinyinFuzzyPinyin_UANG_UAN',
'engine/PinyinDoublePinyinShowRaw',
'engine/PinyinFuzzyPinyin_H_F',
'engine/PinyinFuzzyPinyin_ZH_Z',
'engine/PinyinFuzzyPinyin_R_L',
# TODO: Uncomment these when mozc loads config
# values from ibus.
'engine/Mozchistory_learning_level',
'engine/Mozcincognito_mode',
'engine/Mozcnumpad_character_form',
'engine/Mozcpreedit_method',
'engine/Mozcpunctuation_method',
'engine/Mozcsession_keymap',
'engine/Mozcshift_key_mode_switch',
'engine/Mozcspace_character_form',
'engine/Mozcsuggestions_size',
'engine/Mozcsymbol_method',
'engine/Mozcuse_auto_ime_turn_off',
'engine/Mozcuse_dictionary_suggest',
'engine/Mozcuse_history_suggest',
'engine/Mozcuse_number_conversion',
'engine/Mozcuse_single_kanji_conversion',
'engine/Mozcuse_symbol_conversion',
'engine/Mozcuse_date_conversion',
# These preferences are actually read, but
# ibus-daemon reads them before chrome connects,
# so they show up as a false failure.
'general/hotkeynext_engine_in_menu',
'general/hotkeyprevious_engine',
'generalglobal_engine',
'generalglobal_previous_engine'])
expected_unwritten = set(['engine/ChewingsyncCapsLockLocal',
'engine/ChewingnumpadAlwaysNumber',
'engine/ChewinginputStyle',
'engine/PinyinCorrectPinyin_GN_NG',
'engine/PinyinCorrectPinyin_IOU_IU',
'engine/PinyinCorrectPinyin_MG_NG',
'engine/PinyinCorrectPinyin_UEN_UN',
'engine/PinyinCorrectPinyin_UE_VE',
'engine/PinyinCorrectPinyin_VE_UE',
'engine/PinyinCorrectPinyin_V_U',
'engine/PinyinDoublePinyinShowRaw',
'engine/PinyinFuzzyPinyin_ANG_AN',
'engine/PinyinFuzzyPinyin_AN_ANG',
'engine/PinyinFuzzyPinyin_CH_C',
'engine/PinyinFuzzyPinyin_C_CH',
'engine/PinyinFuzzyPinyin_ENG_EN',
'engine/PinyinFuzzyPinyin_EN_ENG',
'engine/PinyinFuzzyPinyin_F_H',
'engine/PinyinFuzzyPinyin_G_K',
'engine/PinyinFuzzyPinyin_H_F',
'engine/PinyinFuzzyPinyin_IANG_IAN',
'engine/PinyinFuzzyPinyin_IAN_IANG',
'engine/PinyinFuzzyPinyin_ING_IN',
'engine/PinyinFuzzyPinyin_IN_ING',
'engine/PinyinFuzzyPinyin_K_G',
'engine/PinyinFuzzyPinyin_L_N',
'engine/PinyinFuzzyPinyin_L_R',
'engine/PinyinFuzzyPinyin_N_L',
'engine/PinyinFuzzyPinyin_R_L',
'engine/PinyinFuzzyPinyin_SH_S',
'engine/PinyinFuzzyPinyin_S_SH',
'engine/PinyinFuzzyPinyin_UANG_UAN',
'engine/PinyinFuzzyPinyin_UAN_UANG',
'engine/PinyinFuzzyPinyin_ZH_Z',
'engine/PinyinFuzzyPinyin_Z_ZH',
'engine/PinyinCorrectPinyin_UEI_UI',
'engine/PinyinIncompletePinyin',
'engine/PinyinLookupTableOrientation',
'engine/PinyinSpecialPhrases',
# We don't set these prefernces.
'general/hotkeytrigger',
'generalembed_preedit_text',
'generalenable_by_default',
'generalpreload_engines',
'generaluse_global_engine',
'generaluse_system_keyboard_layout'])
# We ignore preload_engines since ibus-daemon in ibus-1.3 sometimes
# reads it, but the daemon in ibus-1.4 does not. The preference is not
# important for this test anyway.
ignored_unread = set(['generalpreload_engines'])
# These preferences are actually written, but due to a race condition
# on startup, they can be read by ibus-daemon before chrome connects,
# and so sometimes they show up as a false failure.
ignored_unwritten = set(['general/hotkeynext_engine_in_menu',
'general/hotkeyprevious_engine',
'generalglobal_engine'])
self.preload_engines(engine_list)
# ibus takes some time to preload the engines, and they can't be
# activated until they are done loading. Since we don't get notified
# when they are ready, we have to wait here to give them time.
time.sleep(2)
# Send a ctrl+l to enter a text field.
ax = self.get_autox()
ax.send_hotkey('Ctrl-l')
for engine_name in engine_list:
self.activate_engine(engine_name)
out = self.run_ibusclient('get_unused')
match = re.match(r"Unread:(.*)Unwritten:(.*)", out, re.DOTALL)
if not match:
raise error.TestFail('Could not read unused values from ibus')
actual_unread = set(re.split('\n', match.group(1).strip()))
actual_unwritten = set(re.split('\n', match.group(2).strip()))
# Filter out any preferences we're ignoring
actual_unread.difference_update(ignored_unread)
actual_unwritten.difference_update(ignored_unwritten)
new_unread = actual_unread.difference(expected_unread)
now_read = expected_unread.difference(actual_unread)
new_unwritten = actual_unwritten.difference(expected_unwritten)
now_written = expected_unwritten.difference(actual_unwritten)
if new_unread or now_read or new_unwritten or now_written:
message = ['iBus config has changed:']
if new_unread:
message.append('New unread values:')
for key in new_unread:
message.append(key)
if now_read:
message.append('No longer unread values:')
for key in now_read:
message.append(key)
if new_unwritten:
message.append('New unwritten values:')
for key in new_unwritten:
message.append(key)
if now_written:
message.append('No longer unwritten values:')
for key in now_written:
message.append(key)
raise error.TestFail(string.join(message, '\n'))
def preload_engines(self, engine_list):
engine_names = string.join(engine_list, " ")
out = self.run_ibusclient('preload_engines %s' % engine_names)
if not 'OK' in out:
raise error.TestFail('Failed to preload engines: %s' % engine_names)
def activate_engine(self, engine_name):
out = self.run_ibusclient('activate_engine %s' % engine_name)
if not 'OK' in out:
raise error.TestFail('Failed to activate engine: %s' % engine_name)
def run_once(self):
self.start_ibus_daemon_or_die()
dep = 'ibusclient'
dep_dir = os.path.join(self.autodir, 'deps', dep)
self.job.install_pkg(dep, 'dep', dep_dir)
self.exefile = os.path.join(self.autodir,
'deps/ibusclient/ibusclient')
self.test_reachable()
self.test_supported_engines()
for type_name in ['boolean', 'int', 'double', 'string', 'boolean_list',
'int_list', 'double_list', 'string_list']:
self.test_config(type_name)
# TODO: re-enable this test.
# Since the async changes to ibus, this has become less deterministic.
# It is temporarily disabled to make the console more useful.
# self.test_check_unused_ibus_values()
self._ibus_job = None
utils.system_output("kill -9 `pgrep ^ibus-daemon$`")
def start_ibus_daemon_or_die(self, timeout=10):
self._ibus_job = utils.BgJob(
"su chronos -c '%s'" %
"/usr/bin/ibus-daemon --panel=disable --cache=none --restart")
time.sleep(2)
start_time = time.time()
while time.time() - start_time < timeout:
if os.system('pgrep ^ibus-daemon$') == 0:
return
time.sleep(1)
raise error.TestFail('ibus-daemon is not running')