1a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley# Copyright 2016 The Chromium OS Authors. All rights reserved.
2a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley# Use of this source code is governed by a BSD-style license that can be
3a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley# found in the LICENSE file.
4a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley
5a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wileyimport collections
6a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wileyimport re
7a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley
8a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wileyfrom autotest_lib.client.common_lib import error
9a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wileyfrom autotest_lib.client.common_lib import utils
10a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley
11a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher WileyLogcatLine = collections.namedtuple('LogcatLine', ['pid', 'tag', 'message'])
12a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley
13a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wileydef wait_for_logcat_log(message_tag, message_pattern,
14a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley                        process_id=None, timeout_seconds=30, host=None):
15a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    """Wait for a line to show up in logcat.
16a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley
17a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    @param message_tag: string "tag" of the line, as understood by logcat.
18a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    @param message_pattern: regular expression pattern that describes the
19a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley            entire text of the message to look for (e.g. '.*' matches all
20a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley            messages).  This is in grep's regex language.
21a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    @param process_id: optional integer process id to match on.
22a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    @param timeout_seconds: number of seconds to wait for the log line.
23a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    @param host: host object to look for the log line on.  Defaults to
24a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley            our local host.
25a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley
26a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    """
27a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    run = host.run if host is not None else utils.run
28b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin
29b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin    process_id_option = ''
30a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    if process_id is not None:
31b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin        process_id_option = '--pid %d' % process_id
32b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin
33b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin    result = run('logcat %s --format=process -e %s -m 1' % (
34b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin                         process_id_option, message_pattern),
35a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley                 timeout=timeout_seconds,
36a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley                 ignore_timeout=True)
37a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    if result is None:
38a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley        raise error.TestFail('Timed out waiting for a log with message "%s"' %
39a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley                             message_pattern)
40a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley
41b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin    lines = result.stdout.strip().splitlines()
42b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin
43b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin    if len(lines) == 0:
44b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin        raise error.TestError('Logcat did not return any lines')
45b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin
46b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin    line = lines[-1]
47b677c10dd0597d6ce15c95d65d96595ff6bd39c3Casey Dahlin
48bb469d685a3829f08605fe2c861357c7f0e11010Casey Dahlin    match = re.match(r'^.\( *(\d+)\) (.*) \(([^(]+)\)$', line)
49a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    if match:
50a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley        return LogcatLine(pid=match.group(1),
51a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley                          message=match.group(2),
52a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley                          tag=match.group(3))
53a35a9c9dbd506d6cee618499d72a731fb6bfa37eChristopher Wiley    raise error.TestError('Failed to match logcat line "%s"' % line)
54