bluetooth: Add Advertisement Monitor pattern filter tests

This patch adds tests to verify working of patterns filter (without RSSI
filtering) around multiple monitors, multiple clients and suspend/resume
scenarios.

BUG=b:175746099
TEST=Run the advmon_pattern_filter_tests test batch and verify all tests
     PASS.

Change-Id: If267fa76d867effe7d98a008540dddec0ef93a67
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2593722
Reviewed-by: Yun-Hao Chung <howardchung@google.com>
Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
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 be557a0..e07c6ad 100644
--- a/server/cros/bluetooth/bluetooth_adapter_adv_monitor_tests.py
+++ b/server/cros/bluetooth/bluetooth_adapter_adv_monitor_tests.py
@@ -1122,6 +1122,110 @@
         self.test_exit_app(app1)
 
 
+    def advmon_test_pattern_filter_only(self):
+        """Test case: PATTERN_FILTER_ONLY
+
+        Verify matching of advertisements w.r.t. various pattern values and
+        different AD Data Types - Local Name Service UUID and Device Type.
+        Test working of patterns filter matching with multiple clients,
+        multiple monitors and suspend/resume, without RSSI filtering.
+
+        """
+        self.test_is_adv_monitoring_supported()
+        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)
+
+        # Add monitors in both apps.
+        monitor1 = TestMonitor(app1)
+        monitor1.update_type('or_patterns')
+        monitor1.update_patterns([
+                [5, 0x09, '_REF'],
+        ])
+        monitor1.update_rssi([127, 0, 127, 0])
+
+        monitor2 = TestMonitor(app1)
+        monitor2.update_type('or_patterns')
+        monitor2.update_patterns([
+                [0, 0x03, [0x12, 0x18]],
+        ])
+        monitor2.update_rssi([127, 0, 127, 0])
+
+        monitor3 = TestMonitor(app2)
+        monitor3.update_type('or_patterns')
+        monitor3.update_patterns([
+                [0, 0x19, [0xc1, 0x03]],
+                [0, 0x09, 'MOUSE'],
+        ])
+        monitor3.update_rssi([127, 0, 127, 0])
+
+        monitor4 = TestMonitor(app2)
+        monitor4.update_type('or_patterns')
+        monitor4.update_patterns([
+                [0, 0x19, [0xc1, 0x03]],
+                [0, 0x19, [0xc3, 0x03]],
+        ])
+        monitor4.update_rssi([127, 0, 127, 0])
+
+        # Activate should get invoked.
+        self.test_add_monitor(monitor1, expected_activate=True)
+        self.test_add_monitor(monitor2, expected_activate=True)
+        self.test_add_monitor(monitor3, expected_activate=True)
+        self.test_add_monitor(monitor4, expected_activate=True)
+
+        # DeviceFound for mouse should get triggered only for monitors
+        # matching the adv pattern filter.
+        self.test_start_peer_device_adv(self.peer_mouse, duration=5)
+        self.test_device_found(monitor1, count=self.MULTIPLE_EVENTS)
+        self.test_device_found(monitor2, count=self.MULTIPLE_EVENTS)
+        self.test_device_found(monitor3, count=self.MULTIPLE_EVENTS)
+        # Device type 0xc203 should not match.
+        self.test_device_found(monitor4, count=0)
+        self.test_stop_peer_device_adv(self.peer_mouse)
+
+        # Initiate suspend/resume.
+        self.suspend_resume()
+
+        # Remove a monitor from one app, shouldn't affect working of other
+        # monitors or apps.
+        self.test_remove_monitor(monitor1)
+
+        # Reset event counts before next test.
+        self.test_reset_event_count(monitor2)
+        self.test_reset_event_count(monitor3)
+
+        # DeviceFound for mouse should get triggered again for monitors
+        # matching the adv pattern filter.
+        self.test_start_peer_device_adv(self.peer_mouse, duration=5)
+        self.test_device_found(monitor2, count=self.MULTIPLE_EVENTS)
+        self.test_device_found(monitor3, count=self.MULTIPLE_EVENTS)
+        self.test_stop_peer_device_adv(self.peer_mouse)
+
+        # Terminate an app, shouldn't affect working of monitors in other apps.
+        self.test_exit_app(app1)
+
+        # Reset event counts before next test.
+        self.test_reset_event_count(monitor3)
+
+        # DeviceFound should get triggered for keyboard.
+        self.test_start_peer_device_adv(self.peer_keybd, duration=5)
+        self.test_device_found(monitor3, count=self.MULTIPLE_EVENTS)
+        self.test_device_found(monitor4, count=self.MULTIPLE_EVENTS)
+        self.test_stop_peer_device_adv(self.peer_keybd)
+
+        # Unregister the running app, should not fail.
+        self.test_unregister_app(app2)
+
+        # Terminate the running test app instance.
+        self.test_exit_app(app2)
+
+
     def advmon_test_pattern_filter_1(self):
         """Test case: PATTERN_FILTER_1
 
diff --git a/server/site_tests/bluetooth_AdapterAdvMonitor/bluetooth_AdapterAdvMonitor.py b/server/site_tests/bluetooth_AdapterAdvMonitor/bluetooth_AdapterAdvMonitor.py
index 727b2d8..a4f94ac 100644
--- a/server/site_tests/bluetooth_AdapterAdvMonitor/bluetooth_AdapterAdvMonitor.py
+++ b/server/site_tests/bluetooth_AdapterAdvMonitor/bluetooth_AdapterAdvMonitor.py
@@ -35,6 +35,13 @@
         self.advmon_test_monitor_validity()
 
 
+    @test_wrapper('Pattern Filter Tests',
+                  devices={'BLE_KEYBOARD':1, 'BLE_MOUSE':1})
+    def advmon_pattern_filter_tests(self):
+        """Tests monitor functionality for pattern filter only."""
+        self.advmon_test_pattern_filter_only()
+
+
     @test_wrapper('Single Client Tests',
                   devices={'BLE_KEYBOARD':1, 'BLE_MOUSE':1})
     def advmon_single_client_tests(self):
@@ -98,6 +105,7 @@
 
         """
         self.advmon_monitor_health_tests()
+        self.advmon_pattern_filter_tests()
         self.advmon_single_client_tests()
         self.advmon_multi_client_tests()
         self.advmon_fg_bg_combination_tests()
diff --git a/server/site_tests/bluetooth_AdapterAdvMonitor/control.advmon_pattern_filter_tests b/server/site_tests/bluetooth_AdapterAdvMonitor/control.advmon_pattern_filter_tests
new file mode 100644
index 0000000..0844a8a
--- /dev/null
+++ b/server/site_tests/bluetooth_AdapterAdvMonitor/control.advmon_pattern_filter_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_pattern_filter_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 with patterns filter only. """
+
+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)