bluetooth: Add Advertisement Monitor multi-client tests

This patch adds tests to verify working of patterns filter and RSSI
filter with multiple clients and multiple monitors.

BUG=b:162791635
TEST=Run the test batch and verify all tests PASS.
     $ test_that --board=eve-kernelnext --args "btpeer_host_list=100.90.103.30,
       100.90.103.31" 100.90.103.27 bluetooth_AdapterAdvMonitor

Change-Id: I4d9dca62dd60068c9ed93603833f72b46f8fde68
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2527819
Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
Reviewed-by: Yun-Hao Chung <howardchung@google.com>
Commit-Queue: Manish Mandlik <mmandlik@chromium.org>
Tested-by: Manish Mandlik <mmandlik@chromium.org>
diff --git a/server/cros/bluetooth/bluetooth_adapter_adv_monitor_tests.py b/server/cros/bluetooth/bluetooth_adapter_adv_monitor_tests.py
index 90d5d8e..9161d46 100644
--- a/server/cros/bluetooth/bluetooth_adapter_adv_monitor_tests.py
+++ b/server/cros/bluetooth/bluetooth_adapter_adv_monitor_tests.py
@@ -1286,6 +1286,92 @@
         self.test_exit_app(app1)
 
 
+    def advmon_test_multi_client(self):
+        """Test case: MULTI_CLIENT
+
+        Verify working of patterns filter and RSSI filters with multiple
+        clients and multiple monitors.
+
+        """
+        self.test_setup_peer_devices()
+
+        # Create two test app instances.
+        app1 = self.create_app()
+        app2 = self.create_app()
+
+        # Register both apps, should not fail.
+        self.test_register_app(app1)
+        self.test_register_app(app2)
+
+        # Monitors with same pattern and RSSI filter values in both apps.
+        monitor1 = TestMonitor(app1)
+        monitor1.update_type('or_patterns')
+        monitor1.update_patterns([
+                [0, 0x03, [0x12, 0x18]],
+                [0, 0x19, [0xc1, 0x03]],
+        ])
+        monitor1.update_rssi([-60, 3, -80, 3])
+
+        monitor2 = TestMonitor(app2)
+        monitor2.update_type('or_patterns')
+        monitor2.update_patterns([
+                [0, 0x03, [0x12, 0x18]],
+                [0, 0x19, [0xc1, 0x03]],
+        ])
+        monitor2.update_rssi([-60, 3, -80, 3])
+
+        # Activate should get invoked.
+        self.test_add_monitor(monitor1, expected_activate=True)
+        self.test_add_monitor(monitor2, expected_activate=True)
+
+        # DeviceFound should get triggered for keyboard.
+        self.test_start_peer_device_adv(self.peer_keybd, duration=5)
+        self.test_device_found(monitor1, count=1)
+        self.test_device_found(monitor2, count=1)
+        self.test_stop_peer_device_adv(self.peer_keybd)
+
+        # Remove a monitor from one app.
+        self.test_remove_monitor(monitor1)
+
+        # Monitors with same pattern but different RSSI filter values.
+        monitor3 = TestMonitor(app1)
+        monitor3.update_type('or_patterns')
+        monitor3.update_patterns([
+                [0, 0x19, [0xc2, 0x03]],
+        ])
+        monitor3.update_rssi([-60, 3, -80, 3])
+
+        monitor4 = TestMonitor(app2)
+        monitor4.update_type('or_patterns')
+        monitor4.update_patterns([
+                [0, 0x19, [0xc2, 0x03]],
+        ])
+        monitor4.update_rssi([-60, 10, -80, 10])
+
+        # Activate should get invoked.
+        self.test_add_monitor(monitor3, expected_activate=True)
+        self.test_add_monitor(monitor4, expected_activate=True)
+
+        # DeviceFound should get triggered for mouse.
+        self.test_start_peer_device_adv(self.peer_mouse, duration=5)
+        self.test_device_found(monitor2, count=2)
+        self.test_device_found(monitor3, count=1)
+
+        # Since the RSSI timeouts are different for monitor4, DeviceFound
+        # event should get triggered after total of 10 seconds.
+        self.test_device_found(monitor4, count=0)
+        self.test_device_found(monitor4, count=1, delay=5)
+        self.test_stop_peer_device_adv(self.peer_mouse)
+
+        # Unregister both apps, should not fail.
+        self.test_unregister_app(app1)
+        self.test_unregister_app(app2)
+
+        # Terminate the both test app instances.
+        self.test_exit_app(app1)
+        self.test_exit_app(app2)
+
+
     def advmon_test_fg_bg_combination(self):
         """Test case: FG_BG_COMBINATION
 
@@ -1372,6 +1458,7 @@
         # Terminate the test app instance.
         self.test_exit_app(app1)
 
+
     def advmon_test_interleaved_scan(self):
         """ Test cases for verifying interleave scan """
 
diff --git a/server/site_tests/bluetooth_AdapterAdvMonitor/bluetooth_AdapterAdvMonitor.py b/server/site_tests/bluetooth_AdapterAdvMonitor/bluetooth_AdapterAdvMonitor.py
index 6a1e0a5..f14fe97 100644
--- a/server/site_tests/bluetooth_AdapterAdvMonitor/bluetooth_AdapterAdvMonitor.py
+++ b/server/site_tests/bluetooth_AdapterAdvMonitor/bluetooth_AdapterAdvMonitor.py
@@ -43,6 +43,13 @@
         self.advmon_test_rssi_filter_3()
 
 
+    @test_wrapper('Multi Client Tests',
+                  devices={'BLE_KEYBOARD':1, 'BLE_MOUSE':1})
+    def advmon_multi_client_tests(self):
+        """Tests monitor functionality for multiple clients."""
+        self.advmon_test_multi_client()
+
+
     @test_wrapper('Foreground Background Combination Tests',
                   devices={'BLE_KEYBOARD':1, 'BLE_MOUSE':1})
     def advmon_fg_bg_combination_tests(self):
@@ -71,6 +78,7 @@
         """
         self.advmon_monitor_health_tests()
         self.advmon_single_client_tests()
+        self.advmon_multi_client_tests()
         self.advmon_fg_bg_combination_tests()
         self.advmon_interleaved_scan()
 
diff --git a/server/site_tests/bluetooth_AdapterAdvMonitor/control.advmon_multi_client_tests b/server/site_tests/bluetooth_AdapterAdvMonitor/control.advmon_multi_client_tests
new file mode 100644
index 0000000..1fee2a9
--- /dev/null
+++ b/server/site_tests/bluetooth_AdapterAdvMonitor/control.advmon_multi_client_tests
@@ -0,0 +1,30 @@
+# Copyright 2020 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.
+
+from autotest_lib.server import utils
+
+AUTHOR = 'chromeos-bluetooth'
+NAME = 'bluetooth_AdapterAdvMonitor.advmon_multi_client_tests'
+PURPOSE = ('batch of Bluetooth Advertisement Monitor tests')
+CRITERIA = 'All tests should pass'
+TIME = 'MEDIUM'
+TEST_CATEGORY = 'Functional'
+ATTRIBUTES = 'suite:bluetooth_flaky'
+TEST_CLASS = 'bluetooth'
+TEST_TYPE = 'server'
+DEPENDENCIES = 'bluetooth, working_bluetooth_btpeer:2'
+
+DOC = """ Tests monitor functionality for multiple clients. """
+
+args_dict = utils.args_to_dict(args)
+
+def run(machine):
+    host = hosts.create_host(machine)
+    job.run_test('bluetooth_AdapterAdvMonitor',
+                 host=host,
+                 num_iterations=1,
+                 args_dict=args_dict,
+                 test_name=NAME.split('.')[1])
+
+parallel_simple(run, machines)