1# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6
7from autotest_lib.client.bin import utils
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.cros.bluetooth import bluetooth_semiauto_helper
10
11
12class bluetooth_AdapterHealth(
13        bluetooth_semiauto_helper.BluetoothSemiAutoHelper):
14    """Checks whether the Bluetooth adapter is present and working."""
15    version = 1
16
17    def _find_kernel_errors(self):
18        """Fail test for any suspicious log entries from kernel.
19
20        Ignore some known errors in order to find new ones.
21
22        """
23        fail_terms = ['[^a-z]err[^a-z]']
24        ignore_terms = ['RFKILL control',
25                        '"Service Changed" characteristic',
26                        'Unknown Evt ID: 19',
27                        'Failed to set privacy: Rejected']
28
29        log_cmd = 'grep -i bluetooth /var/log/messages'
30        for term in ignore_terms:
31            log_cmd += ' | grep -v \'%s\'' % term
32
33        for term in fail_terms:
34            search_cmd = '%s | grep -i \'%s\'' % (log_cmd, term)
35            log_entries = utils.run(search_cmd, ignore_status=True).stdout
36            if len(log_entries) > 0:
37                log_entries = [l for l in log_entries.split('\n') if l != '']
38                logging.info(log_entries)
39                self.collect_logs('Bluetooth kernel error')
40
41                # Add snippet of the log to the error message
42                # unless there are many errors (>5)
43                # This is helpful when looking at stainless results
44                error_str = 'Bluetooth kernel error found!'
45                if len(log_entries) <= 5:
46                    error_str = error_str + ' | '
47                    for l in log_entries:
48                        error_str = error_str +  l.split('ERR')[1] + ' | '
49
50                raise error.TestFail(error_str)
51
52    def warmup(self):
53        """Overwrite parent warmup; no need to log in."""
54        pass
55
56    def run_once(self):
57        """Entry point of this test."""
58        if not self.supports_bluetooth():
59            return
60
61        # Start btmon running.
62        self.start_dump()
63
64        self.poll_adapter_presence()
65
66        # Enable then disable adapter.
67        self.set_adapter_power(True)
68        self.set_adapter_power(False)
69
70        # Check for errors in logs.
71        self._find_kernel_errors()
72