Merge lp:~sil2100/unity/autopilot_ibus_improve into lp:unity

Proposed by Łukasz Zemczak
Status: Merged
Approved by: Łukasz Zemczak
Approved revision: no longer in the source branch.
Merged at revision: 3169
Proposed branch: lp:~sil2100/unity/autopilot_ibus_improve
Merge into: lp:unity
Diff against target: 164 lines (+96/-10)
1 file modified
tests/autopilot/unity/tests/test_ibus.py (+96/-10)
To merge this branch: bzr merge lp:~sil2100/unity/autopilot_ibus_improve
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Thomi Richards (community) Approve
Review via email: mp+147951@code.launchpad.net

Commit message

Improve IBus autopilot tests.
With these improvements, asian characters do not need to be hardcoded in the tests anymore. Now, the 'expected' values are taken directly from IBus before each test. We're doing it by using a separate input context and storing it for comparison. Using the existing input context was buggy, so this seemed like the best way to go otherwise.
To do this, I had to work-around the new IBus bindings from GIR, since create_input_context() - which was needed, was not introspectable.

Description of the change

- Problem:

IBus tests are failing frequently. The reason is that we have hard-coded result values for IBus testing, where the results are not always the same - depending on search history and the ibus version. We also cannot easily clear the history.

- Fix:

My proposed fix is: let's poll (query) IBus with the input string, fetch the resulting string, and then start the standard IBus test and check the search entry text against it. We don't want to test IBus accuracy in our integration tests. We want to test if IBus integration works - if when IBus is enabled, that the input fields will have characters coming from IBus. That's why, we just compare if what we get on the search field is what IBus should return.

We do this by creating a new (separate) input context, feed it with the same input and fetch the resulting, committed strings as results. Best way of course would be to simply hook up to the existing input context of nux and the dash and just 'listen in' - this would be the *perfect* solution. Sadly, that didn't seem to be possible, as hooking up on the existing input context's signals did not work. Too bad...

So, this solution seems sufficient. It has some backsides, but in overall it should *finally* fix IBus tests.

Also, well, there are some hacks here too. The problem was - I could not use the old IBus bindings because of the glib version mismatching. The new bindings from GIR, well, those didn't allow introspection of create_input_context method in IBus.Bus(). So, to workaround that, I had to directly do all the things that normally create_input_context() would do. But it works!

- Tests:

N/A

To post a comment you must log in.
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

Hi,

First, when running the tests, I get:

/tmp/autopilot_ibus_improve/tests/autopilot/unity/tests/test_ibus.py:48: PyGIDeprecationWarning: MainLoop is deprecated; use GLib.MainLoop instead
  self._glibloop = GObject.MainLoop()

(autopilot:15226): IBUS-WARNING **: org.freedesktop.IBus.InputContext.GetEngine: GDBus.Error:org.freedesktop.IBus.Error.NoEngine: Input context does not have engine.
/tmp/autopilot_ibus_improve/tests/autopilot/unity/tests/test_ibus.py:79: PyGIDeprecationWarning: timeout_add_seconds is deprecated; use GLib.timeout_add_seconds instead
  GObject.timeout_add_seconds(10, lambda *args: self._glibloop.quit())

So we should fix that. Seconf, they enter an endless loop where they constantly print:

(autopilot:15226): IBUS-WARNING **: org.freedesktop.IBus.InputContext.GetEngine: GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such interface `org.freedesktop.IBus.InputContext' on object at path /org/freedesktop/IBus/InputContext_58

so I can't actually run the tests to verify that they work as expected.

review: Needs Fixing
Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Thanks for checking it out! I will look on what's wrong tomorrow, maybe it has something to do that I'm using quantal for testing - maybe raring has different things going on.

Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Actually! I even came up now with a better idea of dealing with this, I'll try it out tomorrow in the morning (I just ran out of my bed because of this idea ;) ). Maybe we'll be able to deal it without having to create a new input context!

Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Fixed the GObject thing. Sorry about that!

Ok, so, I looked at the existing code...

Thomi, are you sure you have a clean, working ibus environment? All tests work correctly for me and Francis, both on quantal and raring. I also checked the differences between the ibus in quantal and raring and nothing changed regarding this matter. So I have no idea why you get the errors. Is your ibus installation correct? Are the engines installed?

Anyway, even in the working case one (autopilot:15226): IBUS-WARNING **: org.freedesktop.IBus.InputContext.GetEngine warning will be noticable most of the time. This is because I didn't want to do any time.sleep() waits until the engine is set - and IBus prints a warning when a get_engine() is done with no engine set. We use that to make sure that the engine finally gets set.

Can you re-try on a clean raring or quantal system with ibus installed?

Revision history for this message
Łukasz Zemczak (sil2100) wrote :

Ok, so, after the fixes I made now, anthy tests pass properly every time. With hangul, well, it's still broken. I think we'll have to use hard-coded values for hangul still... :( That's because hangul seems to be written in a strange way that I don't get any text (the argument is empty) during update-preedit-text signals. Still asking the IBus guys about it.

Revision history for this message
Thomi Richards (thomir-deactivatedaccount) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Francis Ginther (fginther) wrote :

Build failed due to a launchpad service issue. Re-approving.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'tests/autopilot/unity/tests/test_ibus.py'
--- tests/autopilot/unity/tests/test_ibus.py 2013-02-04 19:54:47 +0000
+++ tests/autopilot/unity/tests/test_ibus.py 2013-02-22 19:04:23 +0000
@@ -1,6 +1,6 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2# Copyright 2012 Canonical2# Copyright 2012 Canonical
3# Author: Thomi Richards, Martin Mrazik3# Authors: Thomi Richards, Martin Mrazik, Łukasz 'sil2100' Zemczak
4#4#
5# This program is free software: you can redistribute it and/or modify it5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published6# under the terms of the GNU General Public License version 3, as published
@@ -23,6 +23,84 @@
2323
24from unity.tests import UnityTestCase24from unity.tests import UnityTestCase
2525
26from gi.repository import GLib
27from gi.repository import IBus
28import time
29import dbus
30import threading
31
32
33# See lp:ibus-query
34class IBusQuery:
35 """A simple class allowing string queries to the IBus engine."""
36
37 def __init__(self):
38 self._bus = IBus.Bus()
39 self._dbusconn = dbus.connection.Connection(IBus.get_address())
40
41 # XXX: the new IBus bindings do not export create_input_context for
42 # introspection. This is troublesome - so, to workaround this problem
43 # we're directly fetching a new input context manually
44 ibus_obj = self._dbusconn.get_object(IBus.SERVICE_IBUS, IBus.PATH_IBUS)
45 self._test = dbus.Interface(ibus_obj, dbus_interface="org.freedesktop.IBus")
46 path = self._test.CreateInputContext("IBusQuery")
47 self._context = IBus.InputContext.new(path, self._bus.get_connection(), None)
48
49 self._glibloop = GLib.MainLoop()
50
51 self._context.connect("commit-text", self.__commit_text_cb)
52 self._context.connect("update-preedit-text", self.__update_preedit_cb)
53 self._context.connect("disabled", self.__disabled_cb)
54
55 self._context.set_capabilities (9)
56
57 def __commit_text_cb(self, context, text):
58 self.result += text.text
59 self._preedit = ''
60
61 def __update_preedit_cb(self, context, text, cursor_pos, visible):
62 if visible:
63 self._preedit = text.text
64
65 def __disabled_cb(self, a):
66 self.result += self._preedit
67 self._glibloop.quit()
68
69 def __abort(self):
70 self._abort = True
71
72 def poll(self, engine, ibus_input):
73 if len(ibus_input) <= 0:
74 return None
75
76 self.result = ''
77 self._preedit = ''
78 self._context.focus_in()
79 self._context.set_engine(engine)
80
81 # Timeout in case of the engine not being installed
82 self._abort = False
83 timeout = threading.Timer(4.0, self.__abort)
84 timeout.start()
85 while self._context.get_engine() is None:
86 if self._abort is True:
87 print "Error! Could not set the engine correctly."
88 return None
89 continue
90 timeout.cancel()
91
92 for c in ibus_input:
93 self._context.process_key_event(ord(c), 0, 0)
94
95 self._context.set_engine('')
96 self._context.focus_out()
97
98 GLib.timeout_add_seconds(5, lambda *args: self._glibloop.quit())
99 self._glibloop.run()
100
101 return unicode(self.result, "UTF-8")
102
103
26104
27class IBusTests(UnityTestCase):105class IBusTests(UnityTestCase):
28 """Base class for IBus tests."""106 """Base class for IBus tests."""
@@ -30,6 +108,7 @@
30 def setUp(self):108 def setUp(self):
31 super(IBusTests, self).setUp()109 super(IBusTests, self).setUp()
32 self.set_correct_ibus_trigger_keys()110 self.set_correct_ibus_trigger_keys()
111 self._ibus_query = None
33112
34 def set_correct_ibus_trigger_keys(self):113 def set_correct_ibus_trigger_keys(self):
35 """Set the correct keys to trigger IBus.114 """Set the correct keys to trigger IBus.
@@ -68,6 +147,8 @@
68147
69 """148 """
70 available_engines = get_available_input_engines()149 available_engines = get_available_input_engines()
150 if self._ibus_query is None:
151 self._ibus_query = IBusQuery()
71 if engine_name in available_engines:152 if engine_name in available_engines:
72 if get_active_input_engines() != [engine_name]:153 if get_active_input_engines() != [engine_name]:
73 IBusTests._old_engines = set_active_engines([engine_name])154 IBusTests._old_engines = set_active_engines([engine_name])
@@ -98,6 +179,11 @@
98179
99 def do_ibus_test(self):180 def do_ibus_test(self):
100 """Do the basic IBus test on self.widget using self.input and self.result."""181 """Do the basic IBus test on self.widget using self.input and self.result."""
182 try:
183 result = self.result
184 except:
185 result = self._ibus_query.poll(self.engine_name, self.input)
186
101 widget = getattr(self.unity, self.widget)187 widget = getattr(self.unity, self.widget)
102 widget.ensure_visible()188 widget.ensure_visible()
103 self.addCleanup(widget.ensure_hidden)189 self.addCleanup(widget.ensure_hidden)
@@ -107,7 +193,7 @@
107 if commit_key:193 if commit_key:
108 self.keyboard.press_and_release(commit_key)194 self.keyboard.press_and_release(commit_key)
109 self.deactivate_ibus(widget.searchbar)195 self.deactivate_ibus(widget.searchbar)
110 self.assertThat(widget.search_string, Eventually(Equals(self.result)))196 self.assertThat(widget.search_string, Eventually(Equals(result)))
111197
112198
113199
@@ -119,11 +205,11 @@
119 scenarios = multiply_scenarios(205 scenarios = multiply_scenarios(
120 IBusWidgetScenariodTests.scenarios,206 IBusWidgetScenariodTests.scenarios,
121 [207 [
122 ('basic', {'input': 'abc1', 'result': u'\u963f\u5e03\u4ece'}),208 ('basic', {'input': 'abc1'}),
123 ('photo', {'input': 'zhaopian ', 'result': u'\u7167\u7247'}),209 ('photo', {'input': 'zhaopian '}),
124 ('internet', {'input': 'hulianwang ', 'result': u'\u4e92\u8054\u7f51'}),210 ('internet', {'input': 'hulianwang '}),
125 ('disk', {'input': 'cipan ', 'result': u'\u78c1\u76d8'}),211 ('disk', {'input': 'cipan '}),
126 ('disk_management', {'input': 'cipan guanli ', 'result': u'\u78c1\u76d8\u7ba1\u7406'}),212 ('disk_management', {'input': 'cipan guanli '}),
127 ]213 ]
128 )214 )
129215
@@ -165,9 +251,9 @@
165 scenarios = multiply_scenarios(251 scenarios = multiply_scenarios(
166 IBusWidgetScenariodTests.scenarios,252 IBusWidgetScenariodTests.scenarios,
167 [253 [
168 ('system', {'input': 'shisutemu ', 'result': u'\u30b7\u30b9\u30c6\u30e0'}),254 ('system', {'input': 'shisutemu '}),
169 ('game', {'input': 'ge-mu ', 'result': u'\u30b2\u30fc\u30e0'}),255 ('game', {'input': 'ge-mu '}),
170 ('user', {'input': 'yu-za- ', 'result': u'\u30e6\u30fc\u30b6\u30fc'}),256 ('user', {'input': 'yu-za- '}),
171 ],257 ],
172 [258 [
173 ('commit_j', {'commit_key': 'Ctrl+j'}),259 ('commit_j', {'commit_key': 'Ctrl+j'}),