Merge lp:~cypressyew/checkbox/bt4-HOGP into lp:checkbox

Proposed by Po-Hsu Lin
Status: Rejected
Rejected by: Po-Hsu Lin
Proposed branch: lp:~cypressyew/checkbox/bt4-HOGP
Merge into: lp:checkbox
Diff against target: 283 lines (+267/-0)
2 files modified
providers/plainbox-provider-checkbox/bin/bt_connect (+221/-0)
providers/plainbox-provider-checkbox/jobs/bluetooth.txt.in (+46/-0)
To merge this branch: bzr merge lp:~cypressyew/checkbox/bt4-HOGP
Reviewer Review Type Date Requested Status
Yung Shen (community) Abstain
Ara Pulido (community) Needs Fixing
Chris Wayne Pending
Review via email: mp+288612@code.launchpad.net

Description of the change

Add a manifest request for asking tester about BT 4.x capability of this system.
Add a BT 4.x specific test case for HID devices (keyboard / mouse)

To post a comment you must log in.
Revision history for this message
Po-Hsu Lin (cypressyew) wrote :

The reason why we're only adding a new test case for HID is that, this HID Over GATT Profile is a new feature for Bluetooth 4.x devices. For those old profiles like obex, they are not a new stuff, so leave it as-is for back-ward compatibility test.

Revision history for this message
Ara Pulido (ara) wrote :

Can we do the test more automated, please?

Things that we can automate: The name of the device may be configurable, enabling bluetooth and selecting the configured BT device should be automated.

Thanks,
Ara.

review: Needs Fixing
Revision history for this message
Yung Shen (kaxing) wrote :

About the job naming with 4.x, there is a small quirk between versions: 4.1 is software upgrade but for 4.2 some feature requires hardware upgrade. It might be better to left the x for the future job.

Revision history for this message
Yung Shen (kaxing) wrote :

About automation, a note for HOGP devices, at least the two mouses that I've handed on, they will changing MAC address from each pairing reset.

And since this set of bluetooth jobs will be used on Desktop releases, I think the interactive part of testing would be more closer to real-life scenario.

Revision history for this message
Ara Pulido (ara) wrote :

We don't want to mimic real-life scenario. We want to be efficient in our testing.

lp:~cypressyew/checkbox/bt4-HOGP updated
4265. By Po-Hsu Lin

p-p-c: Add BT automated script for mouse, and corresponding test case.

Add BT automated script, which will ask tester to enter MAC address,
Split the BT4 HOGP test cases into 2, mouse and keyboard.
Improve the term "BT 4.x" with "Bluetooth Smart".

4266. By Po-Hsu Lin

p-p-c: Convert bt_connect script to python3.

Apply to try statement to convert this script to python3,
add some docstrings and change the todo list

4267. By Po-Hsu Lin

Merging Yung's patch to align Bluetooth Smart naming.

Aligning bluetooth 4.x naming

4268. By Po-Hsu Lin

Add scanning feature and improve the keyboard test case.

Add scanning feature and class code dictionary to determine which device to connect.
Improve the keyboard test case.

Revision history for this message
Po-Hsu Lin (cypressyew) wrote :

Hi Yung, please modify the executable base on Maciej's bt_helper
https://github.com/kissiel/bt_helper

Revision history for this message
Yung Shen (kaxing) wrote :
review: Abstain

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'providers/plainbox-provider-checkbox/bin/bt_connect'
2--- providers/plainbox-provider-checkbox/bin/bt_connect 1970-01-01 00:00:00 +0000
3+++ providers/plainbox-provider-checkbox/bin/bt_connect 2016-03-17 10:36:36 +0000
4@@ -0,0 +1,221 @@
5+#!/usr/bin/env python3
6+# -*- coding: utf-8 -*-
7+#
8+# This file is part of Checkbox.
9+#
10+# Copyright 2016 Canonical Ltd.
11+#
12+# Authors:
13+# Po-Hsu Lin <po-hsu.lin@canonical.com>
14+# Yung Shen <yung.shen@canonical.com>
15+#
16+# Checkbox is free software: you can redistribute it and/or modify
17+# it under the terms of the GNU General Public License version 3,
18+# as published by the Free Software Foundation.
19+#
20+# Checkbox is distributed in the hope that it will be useful,
21+# but WITHOUT ANY WARRANTY; without even the implied warranty of
22+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23+# GNU General Public License for more details.
24+#
25+# You should have received a copy of the GNU General Public License
26+# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
27+
28+# possibility to lockup, if it times out
29+# TODO: 5. better exception handling (wrong PIN, authentication rejected)
30+# 6. different PIN selection
31+# 7. MAC address validator
32+# 8. Use logging for information
33+# 9. PEP8
34+try:
35+ from gi.repository import GObject
36+except ImportError:
37+ import gobject as GObject
38+
39+import time
40+import dbus
41+import dbus.service
42+from dbus.mainloop.glib import DBusGMainLoop
43+from argparse import ArgumentParser
44+
45+PIN = '0000'
46+CLASS_CODE = {'mouse': [0x580, 0x2580], 'keyboard': [0x540, 0x2540]}
47+mainloop = GObject.MainLoop()
48+
49+
50+class Rejected(dbus.DBusException):
51+ _dbus_error_name = "org.bluez.Error.Rejected"
52+
53+
54+class Agent(dbus.service.Object):
55+ exit_on_release = True
56+
57+ def set_exit_on_release(self, exit_on_release):
58+ self.exit_on_release = exit_on_release
59+
60+ @dbus.service.method("org.bluez.Agent",
61+ in_signature="", out_signature="")
62+ def Release(self):
63+ if self.exit_on_release:
64+ mainloop.quit()
65+
66+ @dbus.service.method("org.bluez.Agent",
67+ in_signature="os", out_signature="")
68+ def Authorize(self, device, uuid):
69+ print("Authorize {}, {}".format(device, uuid))
70+ authorize = raw_input("Authorize connection (yes/no): ")
71+ if (authorize == "yes"):
72+ return
73+ raise Rejected("Connection rejected by user")
74+
75+ @dbus.service.method("org.bluez.Agent",
76+ in_signature="o", out_signature="s")
77+ def RequestPinCode(self, device):
78+ print("Sending PIN: {} to your device.".format(PIN))
79+ if TARGET is not 'mouse':
80+ print("For keyboard, please type this PIN on it and hit Enter.")
81+ # need to figure out how to send 0000 / 1111 / 1234
82+ return PIN
83+ # return raw_input("Enter PIN Code: ")
84+
85+ @dbus.service.method("org.bluez.Agent",
86+ in_signature="o", out_signature="u")
87+ def RequestPasskey(self, device):
88+ print("RequestPasskey {}".format(device))
89+ passkey = raw_input("Enter passkey: ")
90+ return dbus.UInt32(passkey)
91+
92+ @dbus.service.method("org.bluez.Agent",
93+ in_signature="ou", out_signature="")
94+ def DisplayPasskey(self, device, passkey):
95+ print("Please enter the passkey: {} on your device".format(passkey))
96+
97+ @dbus.service.method("org.bluez.Agent",
98+ in_signature="ou", out_signature="")
99+ def RequestConfirmation(self, device, passkey):
100+ print("RequestConfirmation {}, {})".format(device, passkey))
101+ confirm = raw_input("Confirm passkey (yes/no): ")
102+ if (confirm == "yes"):
103+ return
104+ raise Rejected("Passkey doesn't match")
105+
106+ @dbus.service.method("org.bluez.Agent",
107+ in_signature="s", out_signature="")
108+ def ConfirmModeChange(self, mode):
109+ print("ConfirmModeChange {}".format(mode))
110+ authorize = raw_input("Authorize mode change (yes/no): ")
111+ if (authorize == "yes"):
112+ return
113+ raise Rejected("Mode change by user")
114+
115+ @dbus.service.method("org.bluez.Agent",
116+ in_signature="", out_signature="")
117+ def Cancel(self):
118+ print("Cancel")
119+
120+
121+def create_device_reply(device):
122+ print("New device {}".format(device))
123+ mainloop.quit()
124+
125+
126+def create_device_error(error):
127+ if error._dbus_error_name == 'org.bluez.Error.AuthenticationFailed':
128+ print("ERROR: Passcode Authentication Failed, wrong passcode?")
129+ else:
130+ print("Creating device failed: {}".format(error))
131+ mainloop.quit()
132+
133+
134+def property_changed(name, value):
135+ """handler function for "PropertyChanged" signal."""
136+ if (name == "Discovering" and not value):
137+ mainloop.quit()
138+
139+
140+def device_found(address, properties):
141+ global DEVICE_MAC
142+ """handler function for "DeviceFound" signal."""
143+ if properties['Class'] in CLASS_CODE[TARGET]:
144+ print("Device found: {}".format(properties['Name']))
145+ print("MAC address: {}".format(properties['Address']))
146+ DEVICE_MAC = properties['Address']
147+
148+
149+def main():
150+ """Add argument parser here and do most of the job."""
151+ global TARGET
152+ global DEVICE_MAC
153+ DEVICE_MAC = None
154+ parser = ArgumentParser(description="Bluetooth auto paring and connect. Please select one option.")
155+ group = parser.add_mutually_exclusive_group(required=True)
156+ group.add_argument("--mac", type=str,
157+ help="Pair with a given MAC, not using scan result,")
158+ group.add_argument("--mouse", action="store_const",
159+ const="mouse", dest='target',
160+ help="Pair with the last mouse found from scan result.")
161+ group.add_argument("--keyboard", action="store_const",
162+ const="keyboard", dest='target',
163+ help="Pair with the last keyboard found from scan result.")
164+ parser.add_argument("-i", "--interface", type=str,
165+ help="Device interface, e.g. hci0")
166+ parser.add_argument("-c", "--capability", type=str, default="DisplayYesNo")
167+ args = parser.parse_args()
168+
169+ DBusGMainLoop(set_as_default=True)
170+ bus = dbus.SystemBus()
171+ manager = dbus.Interface(bus.get_object("org.bluez", "/"),
172+ "org.bluez.Manager")
173+ if args.interface:
174+ path = manager.FindAdapter(args.interface)
175+ else:
176+ path = manager.DefaultAdapter()
177+
178+ adapter = dbus.Interface(bus.get_object("org.bluez", path),
179+ "org.bluez.Adapter")
180+
181+ path = "/test/agent"
182+ agent = Agent(bus, path)
183+ if not args.mac:
184+ # Activate scan and auto pairing
185+ TARGET = args.target
186+ print("Trying to scan and pair with a {}.".format(TARGET))
187+ bus.add_signal_receiver(device_found,
188+ signal_name="DeviceFound",
189+ dbus_interface="org.bluez.Adapter")
190+ bus.add_signal_receiver(property_changed,
191+ signal_name="PropertyChanged",
192+ dbus_interface="org.bluez.Adapter")
193+ adapter.StartDiscovery()
194+ mainloop.run()
195+ adapter.StopDiscovery()
196+ if not DEVICE_MAC:
197+ print("ERROR: No pairable device found, terminating")
198+ return 1
199+ else:
200+ DEVICE_MAC = args.mac
201+
202+ # Try to remove the Device entry if exist
203+ try:
204+ device = adapter.FindDevice(DEVICE_MAC)
205+ print("Device already exist, remove it first")
206+ adapter.RemoveDevice(device)
207+ except dbus.exceptions.DBusException:
208+ print("Creating device entry")
209+ agent.set_exit_on_release(False)
210+ print("Paring device")
211+ adapter.CreatePairedDevice(DEVICE_MAC, path, args.capability,
212+ reply_handler=create_device_reply,
213+ error_handler=create_device_error)
214+
215+ mainloop.run()
216+
217+ time.sleep(3)
218+ print("Connecting device...")
219+ device = adapter.FindDevice(DEVICE_MAC)
220+ hid = dbus.Interface(bus.get_object("org.bluez", device),
221+ "org.bluez.Input")
222+ hid.Connect()
223+
224+if __name__ == "__main__":
225+ main()
226
227=== modified file 'providers/plainbox-provider-checkbox/jobs/bluetooth.txt.in'
228--- providers/plainbox-provider-checkbox/jobs/bluetooth.txt.in 2016-01-12 10:28:35 +0000
229+++ providers/plainbox-provider-checkbox/jobs/bluetooth.txt.in 2016-03-17 10:36:36 +0000
230@@ -1,3 +1,10 @@
231+unit: manifest entry
232+id: has_bt_smart
233+_name: Bluetooth Smart (4.0 or later) Support
234+requires:
235+ device.category == 'BLUETOOTH'
236+value-type: bool
237+
238 plugin: shell
239 category_id: 2013.com.canonical.plainbox::bluetooth
240 id: bluetooth/detect-output
241@@ -157,3 +164,42 @@
242 retrieves it again using Bluetooth and verifies the checksum to ensure the
243 transfer didn't corrupt the file.
244
245+plugin: user-interact-verify
246+category_id: 2013.com.canonical.plainbox::bluetooth
247+id: bluetooth4/HOGP-mouse
248+depends: bluetooth/detect-output
249+requires:
250+ manifest.has_bt_smart == 'True'
251+ package.name == 'zenity'
252+estimated_duration: 30.0
253+command: bt_connect --mac `zenity --entry --title="device MAC" --text="Please enter the MAC address for testing"`
254+_description:
255+ PURPOSE:
256+ This test will check that you can use a HID Over GATT Profile (HOGP) with your Bluetooth Smart mouse.
257+ STEPS:
258+ 1. Enable a Bluetooth smart mouse, and put it into paring mode.
259+ 2. Use "hcitool scan" command in another terminal to get the MAC address of it.
260+ 3. Commence the test to do the auto-pairing, you will be asked to enter the MAC address.
261+ 4. After it's paired and connected, perform actions such as moving the pointer, right and left button clicks and double clicks.
262+ VERIFICATION:
263+ Did the Bluetooth Smart mouse work as expected?
264+
265+plugin: user-interact-verify
266+category_id: 2013.com.canonical.plainbox::bluetooth
267+id: bluetooth4/HOGP-keyboard
268+depends: bluetooth/detect-output
269+requires:
270+ manifest.has_bt_smart == 'True'
271+ package.name == 'zenity'
272+estimated_duration: 30.0
273+command: bt_connect --mac `zenity --entry --title="device MAC" --text="Please enter the MAC address for testing"` && keyboard_test
274+_description:
275+ PURPOSE:
276+ This test will check that you can use a HID Over GATT Profile (HOGP) with your Bluetooth Smart keyboard.
277+ STEPS:
278+ 1. Enable a Bluetooth Smart keyboard, and put it into paring mode.
279+ 2. Use "hcitool scan" command in another terminal to get the MAC address of it.
280+ 3. Commence the test to do the auto-pairing, you will be asked to enter the MAC address and PIN code.
281+ 4. After it's paired and connected, enter some text with your keyboard and close the small input test tool.
282+ VERIFICATION:
283+ Did the Bluetooth Smart keyboard work as expected?

Subscribers

People subscribed via source and target branches