aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitreview4
-rw-r--r--BluetoothTests.apkbin0 -> 21763 bytes
-rw-r--r--COPYING340
-rw-r--r--README26
-rwxr-xr-xaosp-bt-stress-test.sh49
-rw-r--r--bluez-test-scripts/bluezutils.py47
-rwxr-xr-xbluez-test-scripts/simple-agent190
-rwxr-xr-xbluez-test-scripts/test-adapter145
-rwxr-xr-xbluez-test-scripts/test-device202
-rwxr-xr-xdebian-bt-stress-test.py106
-rwxr-xr-xsetup-test-client.sh16
11 files changed, 1125 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..1fd4fa3
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,4 @@
+[gerrit]
+host=review.linaro.org
+port=29418
+project=qa/24h-stress-test
diff --git a/BluetoothTests.apk b/BluetoothTests.apk
new file mode 100644
index 0000000..78d73a3
--- /dev/null
+++ b/BluetoothTests.apk
Binary files differ
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..6d45519
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/README b/README
new file mode 100644
index 0000000..fd147f0
--- /dev/null
+++ b/README
@@ -0,0 +1,26 @@
+o Run stress_ng, stress_network or stress_oom on the following builds
+ - Debian
+ # ./24h-stress-test.sh
+
+ - OE
+ # ./oe-24h-stress-test.sh
+
+ - AOSP, run test script on test client.
+ # ./aosp-bt-stress-test.sh
+
+ Run ./*-stress-test.sh -h for script usage and examples.
+
+o Bluetooth power, discoverable, scan and pairing stress test.
+ - Debian
+ Setup test client that supports bluetooth.
+ # ./setup-test-client.sh
+ Run test on test target
+ # ./debian-bt-stress-test.py client_bt_device_address
+
+ - AOSP, run test on a client that supports bluetooth.
+ # ./aosp-bt-stress-test.sh client_bt_device_address
+
+o Use the following yaml test definitions for test run in LAVA.
+ - Debian 24h-stress-test.yaml
+ - OE oe-24h-stress-test.yaml
+ - AOSP aosp-24h-stress-test.yaml
diff --git a/aosp-bt-stress-test.sh b/aosp-bt-stress-test.sh
new file mode 100755
index 0000000..2a3963a
--- /dev/null
+++ b/aosp-bt-stress-test.sh
@@ -0,0 +1,49 @@
+#!/bin/sh -x
+
+# Client BT device address.
+remote_device_address=$1
+
+if [ "$(id -u)" != "0" ]; then
+ echo "Please run as root."
+ exit 1
+fi
+
+# Config test client.
+echo
+echo "Setup test client"
+./bluez-test-scripts/test-adapter address
+./bluez-test-scripts/test-adapter powered on
+./bluez-test-scripts/test-adapter pairable on
+./bluez-test-scripts/test-adapter pairabletimeout 21600
+./bluez-test-scripts/test-adapter discoverable on
+./bluez-test-scripts/test-adapter discoverabletimeout 21600
+./bluez-test-scripts/test-adapter list
+# Run authentication removed simple-agent.
+pkill simple-agent
+./bluez-test-scripts/simple-agent &
+simple_agent=$!
+
+# Setup test target.
+echo
+echo "Setup test target"
+adb shell logcat -c
+adb shell logcat > logcat.log &
+logcat=$!
+adb shell pm list packages | grep com.android.bluetooth.tests && \
+adb uninstall com.android.bluetooth.tests
+adb install BluetoothTests.apk
+
+# Run tests
+iteration=1000
+for test in enable discoverable scan pair
+do
+ echo
+ echo "Running bluetooth $test test with $iteration iterations"
+ sudo adb shell am instrument \
+ -e device_address $remote_device_address \
+ -e ${test}_iterations $iteration \
+ -w com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner
+done
+
+kill $simple_agent
+kill $logcat
diff --git a/bluez-test-scripts/bluezutils.py b/bluez-test-scripts/bluezutils.py
new file mode 100644
index 0000000..de08cbd
--- /dev/null
+++ b/bluez-test-scripts/bluezutils.py
@@ -0,0 +1,47 @@
+import dbus
+
+SERVICE_NAME = "org.bluez"
+ADAPTER_INTERFACE = SERVICE_NAME + ".Adapter1"
+DEVICE_INTERFACE = SERVICE_NAME + ".Device1"
+
+def get_managed_objects():
+ bus = dbus.SystemBus()
+ manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.freedesktop.DBus.ObjectManager")
+ return manager.GetManagedObjects()
+
+def find_adapter(pattern=None):
+ return find_adapter_in_objects(get_managed_objects(), pattern)
+
+def find_adapter_in_objects(objects, pattern=None):
+ bus = dbus.SystemBus()
+ for path, ifaces in objects.iteritems():
+ adapter = ifaces.get(ADAPTER_INTERFACE)
+ if adapter is None:
+ continue
+ if not pattern or pattern == adapter["Address"] or \
+ path.endswith(pattern):
+ obj = bus.get_object(SERVICE_NAME, path)
+ return dbus.Interface(obj, ADAPTER_INTERFACE)
+ raise Exception("Bluetooth adapter not found")
+
+def find_device(device_address, adapter_pattern=None):
+ return find_device_in_objects(get_managed_objects(), device_address,
+ adapter_pattern)
+
+def find_device_in_objects(objects, device_address, adapter_pattern=None):
+ bus = dbus.SystemBus()
+ path_prefix = ""
+ if adapter_pattern:
+ adapter = find_adapter_in_objects(objects, adapter_pattern)
+ path_prefix = adapter.object_path
+ for path, ifaces in objects.iteritems():
+ device = ifaces.get(DEVICE_INTERFACE)
+ if device is None:
+ continue
+ if (device["Address"] == device_address and
+ path.startswith(path_prefix)):
+ obj = bus.get_object(SERVICE_NAME, path)
+ return dbus.Interface(obj, DEVICE_INTERFACE)
+
+ raise Exception("Bluetooth device not found")
diff --git a/bluez-test-scripts/simple-agent b/bluez-test-scripts/simple-agent
new file mode 100755
index 0000000..287251a
--- /dev/null
+++ b/bluez-test-scripts/simple-agent
@@ -0,0 +1,190 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from optparse import OptionParser
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+try:
+ from gi.repository import GObject
+except ImportError:
+ import gobject as GObject
+import bluezutils
+
+BUS_NAME = 'org.bluez'
+AGENT_INTERFACE = 'org.bluez.Agent1'
+AGENT_PATH = "/test/agent"
+
+bus = None
+device_obj = None
+dev_path = None
+
+def ask(prompt):
+ try:
+ return raw_input(prompt)
+ except:
+ return input(prompt)
+
+def set_trusted(path):
+ props = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.freedesktop.DBus.Properties")
+ props.Set("org.bluez.Device1", "Trusted", True)
+
+def dev_connect(path):
+ dev = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Device1")
+ dev.Connect()
+
+class Rejected(dbus.DBusException):
+ _dbus_error_name = "org.bluez.Error.Rejected"
+
+class Agent(dbus.service.Object):
+ exit_on_release = True
+
+ def set_exit_on_release(self, exit_on_release):
+ self.exit_on_release = exit_on_release
+
+ @dbus.service.method(AGENT_INTERFACE,
+ in_signature="", out_signature="")
+ def Release(self):
+ print("Release")
+ if self.exit_on_release:
+ mainloop.quit()
+
+ @dbus.service.method(AGENT_INTERFACE,
+ in_signature="os", out_signature="")
+ def AuthorizeService(self, device, uuid):
+ print("AuthorizeService (%s, %s)" % (device, uuid))
+ #authorize = ask("Authorize connection (yes/no): ")
+ #if (authorize == "yes"):
+ #return
+ #raise Rejected("Connection rejected by user")
+ print("(%s, %s) connected" % (device, uuid))
+ return
+
+ @dbus.service.method(AGENT_INTERFACE,
+ in_signature="o", out_signature="s")
+ def RequestPinCode(self, device):
+ print("RequestPinCode (%s)" % (device))
+ #set_trusted(device)
+ #return ask("Enter PIN Code: ")
+ print("(%s) pin code confirmed" % (device))
+ return "1234"
+
+ @dbus.service.method(AGENT_INTERFACE,
+ in_signature="o", out_signature="u")
+ def RequestPasskey(self, device):
+ print("RequestPasskey (%s)" % (device))
+ #set_trusted(device)
+ passkey = "123456"
+ return dbus.UInt32(passkey)
+
+ @dbus.service.method(AGENT_INTERFACE,
+ in_signature="ouq", out_signature="")
+ def DisplayPasskey(self, device, passkey, entered):
+ print("DisplayPasskey (%s, %06u entered %u)" %
+ (device, passkey, entered))
+
+ @dbus.service.method(AGENT_INTERFACE,
+ in_signature="os", out_signature="")
+ def DisplayPinCode(self, device, pincode):
+ print("DisplayPinCode (%s, %s)" % (device, pincode))
+
+ @dbus.service.method(AGENT_INTERFACE,
+ in_signature="ou", out_signature="")
+ def RequestConfirmation(self, device, passkey):
+ print("RequestConfirmation (%s, %06d)" % (device, passkey))
+ confirm = ask("Confirm passkey (yes/no): ")
+ if (confirm == "yes"):
+ set_trusted(device)
+ return
+ raise Rejected("Passkey doesn't match")
+
+ @dbus.service.method(AGENT_INTERFACE,
+ in_signature="o", out_signature="")
+ def RequestAuthorization(self, device):
+ print("RequestAuthorization (%s)" % (device))
+ #auth = ask("Authorize? (yes/no): ")
+ #if (auth == "yes"):
+ #return
+ #raise Rejected("Pairing rejected")
+ print("(%s) pairing request accepted" % (device))
+ return
+
+ @dbus.service.method(AGENT_INTERFACE,
+ in_signature="", out_signature="")
+ def Cancel(self):
+ print("Cancel")
+
+def pair_reply():
+ print("Device paired")
+ set_trusted(dev_path)
+ dev_connect(dev_path)
+ mainloop.quit()
+
+def pair_error(error):
+ err_name = error.get_dbus_name()
+ if err_name == "org.freedesktop.DBus.Error.NoReply" and device_obj:
+ print("Timed out. Cancelling pairing")
+ device_obj.CancelPairing()
+ else:
+ print("Creating device failed: %s" % (error))
+
+
+ mainloop.quit()
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ #capability = "KeyboardDisplay"
+ capability = "NoInputNoOutput"
+
+ parser = OptionParser()
+ parser.add_option("-i", "--adapter", action="store",
+ type="string",
+ dest="adapter_pattern",
+ default=None)
+ parser.add_option("-c", "--capability", action="store",
+ type="string", dest="capability")
+ parser.add_option("-t", "--timeout", action="store",
+ type="int", dest="timeout",
+ default=60000)
+ (options, args) = parser.parse_args()
+ if options.capability:
+ capability = options.capability
+
+ path = "/test/agent"
+ agent = Agent(bus, path)
+
+ mainloop = GObject.MainLoop()
+
+ obj = bus.get_object(BUS_NAME, "/org/bluez");
+ manager = dbus.Interface(obj, "org.bluez.AgentManager1")
+ manager.RegisterAgent(path, capability)
+
+ print("Agent registered")
+
+ # Fix-up old style invocation (BlueZ 4)
+ if len(args) > 0 and args[0].startswith("hci"):
+ options.adapter_pattern = args[0]
+ del args[:1]
+
+ if len(args) > 0:
+ device = bluezutils.find_device(args[0],
+ options.adapter_pattern)
+ dev_path = device.object_path
+ agent.set_exit_on_release(False)
+ device.Pair(reply_handler=pair_reply, error_handler=pair_error,
+ timeout=60000)
+ device_obj = device
+ else:
+ manager.RequestDefaultAgent(path)
+
+ mainloop.run()
+
+ #adapter.UnregisterAgent(path)
+ #print("Agent unregistered")
diff --git a/bluez-test-scripts/test-adapter b/bluez-test-scripts/test-adapter
new file mode 100755
index 0000000..959a437
--- /dev/null
+++ b/bluez-test-scripts/test-adapter
@@ -0,0 +1,145 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from optparse import OptionParser, make_option
+import sys
+import time
+import dbus
+import bluezutils
+
+bus = dbus.SystemBus()
+
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+adapter_path = bluezutils.find_adapter(options.dev_id).object_path
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+ "org.freedesktop.DBus.Properties")
+
+if (len(args) < 1):
+ print("Usage: %s <command>" % (sys.argv[0]))
+ print("")
+ print(" address")
+ print(" list")
+ print(" name")
+ print(" alias [alias]")
+ print(" powered [on/off]")
+ print(" pairable [on/off]")
+ print(" pairabletimeout [timeout]")
+ print(" discoverable [on/off]")
+ print(" discoverabletimeout [timeout]")
+ print(" discovering")
+ sys.exit(1)
+
+if (args[0] == "address"):
+ addr = adapter.Get("org.bluez.Adapter1", "Address")
+ print(addr)
+ sys.exit(0)
+
+if (args[0] == "name"):
+ name = adapter.Get("org.bluez.Adapter1", "Name")
+ print(name)
+ sys.exit(0)
+
+if (args[0] == "alias"):
+ if (len(args) < 2):
+ alias = adapter.Get("org.bluez.Adapter1", "Alias")
+ print(alias)
+ else:
+ adapter.Set("org.bluez.Adapter1", "Alias", args[1])
+ sys.exit(0)
+
+if (args[0] == "list"):
+ if (len(args) < 2):
+ om = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.freedesktop.DBus.ObjectManager")
+ objects = om.GetManagedObjects()
+ for path, interfaces in objects.iteritems():
+ if "org.bluez.Adapter1" not in interfaces:
+ continue
+
+ print(" [ %s ]" % (path))
+
+ props = interfaces["org.bluez.Adapter1"]
+
+ for (key, value) in props.items():
+ if (key == "Class"):
+ print(" %s = 0x%06x" % (key, value))
+ else:
+ print(" %s = %s" % (key, value))
+ print()
+ sys.exit(0)
+
+if (args[0] == "powered"):
+ if (len(args) < 2):
+ powered = adapter.Get("org.bluez.Adapter1", "Powered")
+ print(powered)
+ else:
+ if (args[1] == "on"):
+ value = dbus.Boolean(1)
+ elif (args[1] == "off"):
+ value = dbus.Boolean(0)
+ else:
+ value = dbus.Boolean(args[1])
+ adapter.Set("org.bluez.Adapter1", "Powered", value)
+ sys.exit(0)
+
+if (args[0] == "pairable"):
+ if (len(args) < 2):
+ pairable = adapter.Get("org.bluez.Adapter1", "Pairable")
+ print(pairable)
+ else:
+ if (args[1] == "on"):
+ value = dbus.Boolean(1)
+ elif (args[1] == "off"):
+ value = dbus.Boolean(0)
+ else:
+ value = dbus.Boolean(args[1])
+ adapter.Set("org.bluez.Adapter1", "Pairable", value)
+ sys.exit(0)
+
+if (args[0] == "pairabletimeout"):
+ if (len(args) < 2):
+ pt = adapter.Get("org.bluez.Adapter1", "PairableTimeout")
+ print(pt)
+ else:
+ timeout = dbus.UInt32(args[1])
+ adapter.Set("org.bluez.Adapter1", "PairableTimeout", timeout)
+ sys.exit(0)
+
+if (args[0] == "discoverable"):
+ if (len(args) < 2):
+ discoverable = adapter.Get("org.bluez.Adapter1", "Discoverable")
+ print(discoverable)
+ else:
+ if (args[1] == "on"):
+ value = dbus.Boolean(1)
+ elif (args[1] == "off"):
+ value = dbus.Boolean(0)
+ else:
+ value = dbus.Boolean(args[1])
+ adapter.Set("org.bluez.Adapter1", "Discoverable", value)
+ sys.exit(0)
+
+if (args[0] == "discoverabletimeout"):
+ if (len(args) < 2):
+ dt = adapter.Get("org.bluez.Adapter1", "DiscoverableTimeout")
+ print(dt)
+ else:
+ to = dbus.UInt32(args[1])
+ adapter.Set("org.bluez.Adapter1", "DiscoverableTimeout", to)
+ sys.exit(0)
+
+if (args[0] == "discovering"):
+ discovering = adapter.Get("org.bluez.Adapter1", "Discovering")
+ print(discovering)
+ sys.exit(0)
+
+print("Unknown command")
+sys.exit(1)
diff --git a/bluez-test-scripts/test-device b/bluez-test-scripts/test-device
new file mode 100755
index 0000000..b490d53
--- /dev/null
+++ b/bluez-test-scripts/test-device
@@ -0,0 +1,202 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from optparse import OptionParser, make_option
+import re
+import sys
+import dbus
+import dbus.mainloop.glib
+try:
+ from gi.repository import GObject
+except ImportError:
+ import gobject as GObject
+import bluezutils
+
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+bus = dbus.SystemBus()
+mainloop = GObject.MainLoop()
+
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if (len(args) < 1):
+ print("Usage: %s <command>" % (sys.argv[0]))
+ print("")
+ print(" list")
+ print(" create <address>")
+ print(" remove <address|path>")
+ print(" connect <address> [profile]")
+ print(" disconnect <address> [profile]")
+ print(" class <address>")
+ print(" name <address>")
+ print(" alias <address> [alias]")
+ print(" trusted <address> [yes/no]")
+ print(" blocked <address> [yes/no]")
+ sys.exit(1)
+
+if (args[0] == "list"):
+ adapter = bluezutils.find_adapter(options.dev_id)
+ adapter_path = adapter.object_path
+
+ om = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.freedesktop.DBus.ObjectManager")
+ objects = om.GetManagedObjects()
+
+ for path, interfaces in objects.iteritems():
+ if "org.bluez.Device1" not in interfaces:
+ continue
+ properties = interfaces["org.bluez.Device1"]
+ if properties["Adapter"] != adapter_path:
+ continue;
+ print("%s %s" % (properties["Address"], properties["Alias"]))
+
+ sys.exit(0)
+
+def create_device_reply(device):
+ print("New device (%s)" % device)
+ mainloop.quit()
+ sys.exit(0)
+
+def create_device_error(error):
+ print("Creating device failed: %s" % error)
+ mainloop.quit()
+ sys.exit(1)
+
+if (args[0] == "create"):
+ if (len(args) < 2):
+ print("Need address parameter")
+ else:
+ adapter = bluezutils.find_adapter(options.dev_id)
+ adapter.CreateDevice(args[1],
+ reply_handler=create_device_reply,
+ error_handler=create_device_error)
+ mainloop.run()
+
+if (args[0] == "remove"):
+ if (len(args) < 2):
+ print("Need address or object path parameter")
+ else:
+ managed_objects = bluezutils.get_managed_objects()
+ adapter = bluezutils.find_adapter_in_objects(managed_objects,
+ options.dev_id)
+ try:
+ dev = bluezutils.find_device_in_objects(managed_objects,
+ args[1],
+ options.dev_id)
+ path = dev.object_path
+ except:
+ path = args[1]
+ adapter.RemoveDevice(path)
+ sys.exit(0)
+
+if (args[0] == "connect"):
+ if (len(args) < 2):
+ print("Need address parameter")
+ else:
+ device = bluezutils.find_device(args[1], options.dev_id)
+ if (len(args) > 2):
+ device.ConnectProfile(args[2])
+ else:
+ device.Connect()
+ sys.exit(0)
+
+if (args[0] == "disconnect"):
+ if (len(args) < 2):
+ print("Need address parameter")
+ else:
+ device = bluezutils.find_device(args[1], options.dev_id)
+ if (len(args) > 2):
+ device.DisconnectProfile(args[2])
+ else:
+ device.Disconnect()
+ sys.exit(0)
+
+if (args[0] == "class"):
+ if (len(args) < 2):
+ print("Need address parameter")
+ else:
+ device = bluezutils.find_device(args[1], options.dev_id)
+ path = device.object_path
+ props = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.freedesktop.DBus.Properties")
+ cls = props.Get("org.bluez.Device1", "Class")
+ print("0x%06x" % cls)
+ sys.exit(0)
+
+if (args[0] == "name"):
+ if (len(args) < 2):
+ print("Need address parameter")
+ else:
+ device = bluezutils.find_device(args[1], options.dev_id)
+ path = device.object_path
+ props = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.freedesktop.DBus.Properties")
+ name = props.Get("org.bluez.Device1", "Name")
+ print(name)
+ sys.exit(0)
+
+if (args[0] == "alias"):
+ if (len(args) < 2):
+ print("Need address parameter")
+ else:
+ device = bluezutils.find_device(args[1], options.dev_id)
+ path = device.object_path
+ props = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.freedesktop.DBus.Properties")
+ if (len(args) < 3):
+ alias = props.Get("org.bluez.Device1", "Alias")
+ print(alias)
+ else:
+ props.Set("org.bluez.Device1", "Alias", args[2])
+ sys.exit(0)
+
+if (args[0] == "trusted"):
+ if (len(args) < 2):
+ print("Need address parameter")
+ else:
+ device = bluezutils.find_device(args[1], options.dev_id)
+ path = device.object_path
+ props = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.freedesktop.DBus.Properties")
+ if (len(args) < 3):
+ trusted = props.Get("org.bluez.Device1", "Trusted")
+ print(trusted)
+ else:
+ if (args[2] == "yes"):
+ value = dbus.Boolean(1)
+ elif (args[2] == "no"):
+ value = dbus.Boolean(0)
+ else:
+ value = dbus.Boolean(args[2])
+ props.Set("org.bluez.Device1", "Trusted", value)
+ sys.exit(0)
+
+if (args[0] == "blocked"):
+ if (len(args) < 2):
+ print("Need address parameter")
+ else:
+ device = bluezutils.find_device(args[1], options.dev_id)
+ path = device.object_path
+ props = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.freedesktop.DBus.Properties")
+ if (len(args) < 3):
+ blocked = props.Get("org.bluez.Device1", "Blocked")
+ print(blocked)
+ else:
+ if (args[2] == "yes"):
+ value = dbus.Boolean(1)
+ elif (args[2] == "no"):
+ value = dbus.Boolean(0)
+ else:
+ value = dbus.Boolean(args[2])
+ props.Set("org.bluez.Device1", "Blocked", value)
+ sys.exit(0)
+
+print("Unknown command")
+sys.exit(1)
diff --git a/debian-bt-stress-test.py b/debian-bt-stress-test.py
new file mode 100755
index 0000000..da0873c
--- /dev/null
+++ b/debian-bt-stress-test.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import time
+import pexpect
+
+# Test client BT device address
+remote_device_address=sys.argv[1]
+test_case_list = ['power', 'discoverable', 'scan', 'pair']
+iteration = 1000
+output_dict = {
+ 'power on': 'Changing power on succeeded',
+ 'power off': 'Changing power off succeeded',
+ 'discoverable on': 'Changing discoverable on succeeded',
+ 'discoverable off': 'Changing discoverable off succeeded',
+ 'scan on': 'Discovery started',
+ 'scan off': 'Discovery stopped',
+ 'pairable on': 'Changing pairable on succeeded',
+ 'agent on': 'Agent registered',
+ 'pair': 'Pairing successful',
+ 'remove': 'Device has been removed'
+ }
+
+def print_test_result(test_case, test_result, count):
+ test_case = test_case + ' ' + str(count)
+ test_case = test_case.replace(' ', '_')
+ if test_result:
+ print('%s pass\n' % (test_case))
+ else:
+ print('%s fail\n' % (test_case))
+
+class Bluetoothctl:
+ def __init__(self):
+ self.child = pexpect.spawn('bluetoothctl')
+
+ def send_command(self, command, pause=5):
+ self.child.sendline(command)
+ time.sleep(pause)
+
+ def check_output(self, expected_output):
+ while True:
+ try:
+ line=self.child.readline()
+ if expected_output in line:
+ print(line.strip())
+ return True
+ except pexpect.TIMEOUT:
+ return False
+
+ def terminate(self):
+ self.child.terminate()
+
+# Run tests.
+print('Initializing bluetooth...')
+bl = Bluetoothctl()
+
+for test in test_case_list:
+ bl.send_command('power on')
+ if not bl.check_output('Changing power on succeeded'):
+ print('Failed to power on bluetooth adapter, exiting...')
+ sys.exit(1)
+
+ count = 0
+ print('\nRunning %s test for %s interations...' % (test, iteration))
+ print('--------')
+
+ if test in ['power', 'discoverable', 'scan']:
+ sub_tests = [test + ' on', test + ' off']
+ while count <= iteration:
+ for sub_test in sub_tests:
+ bl.send_command(sub_test)
+ expected_output = output_dict[sub_test]
+ test_result = bl.check_output(expected_output)
+ print_test_result(sub_test, test_result, count)
+ count = count + 1
+
+
+ if test is 'pair':
+ print('Test client need to be set to non-interactive pairing mode\n'
+ 'setup-test-client.sh provided in this repo for this purpose')
+ raw_input('Press Enter to continue...')
+ for pre_set in ['pairable on', 'discoverable on', 'agent on']:
+ bl.send_command(pre_set)
+ if not bl.check_output(output_dict[pre_set]):
+ print('Failed to set %s, exiting...' % (pre_set))
+ sys.exit(1)
+ bl.send_command('remove ' + remote_device_address)
+
+ while count <= iteration:
+ bl.send_command('scan on')
+ if not bl.check_output('\r\x1b[K[\x1b[0;92mNEW\x1b[0m] Device ' + remote_device_address):
+ print('%s NOT found, retrying...' % (remote_device_address))
+ continue
+
+ bl.send_command('pair ' + remote_device_address)
+ test_result = bl.check_output(output_dict['pair'])
+ print_test_result('pair', test_result, count)
+
+ bl.send_command('remove ' + remote_device_address)
+ test_result = bl.check_output(output_dict['remove'])
+ print_test_result('unpair', test_result, count)
+
+ count = count + 1
+
+bl.terminate()
diff --git a/setup-test-client.sh b/setup-test-client.sh
new file mode 100755
index 0000000..d626724
--- /dev/null
+++ b/setup-test-client.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+apt-get install -y python-dbus python-gobject
+# Config test client.
+echo
+echo "Setup test client"
+./bluez-test-scripts/test-adapter address
+./bluez-test-scripts/test-adapter powered on
+./bluez-test-scripts/test-adapter pairable on
+./bluez-test-scripts/test-adapter pairabletimeout 21600
+./bluez-test-scripts/test-adapter discoverable on
+./bluez-test-scripts/test-adapter discoverabletimeout 21600
+./bluez-test-scripts/test-adapter list
+# Run authentication removed simple-agent.
+pkill simple-agent
+./bluez-test-scripts/simple-agent