summaryrefslogtreecommitdiff
path: root/chromium/mojo/tools/mopy/gtest.py
blob: 1cde8ecee2306429c37e649db6958de4a7a44cf7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging
import os
import re
import sys

from mopy import test_util
from mopy.print_process_error import print_process_error


_logger = logging.getLogger()


def set_color():
  """Run gtests with color if we're on a TTY (and we're not being told
  explicitly what to do)."""
  if sys.stdout.isatty() and "GTEST_COLOR" not in os.environ:
    _logger.debug("Setting GTEST_COLOR=yes")
    os.environ["GTEST_COLOR"] = "yes"

# TODO(vtl): The return value is bizarre. Should just make it either return
# True/False, or a list of failing fixtures. But the dart_apptest runner would
# also need to be updated in the same way.
def run_fixtures(config, shell, apptest_dict, apptest, isolate, test_args,
                 shell_args):
  """Run the gtest fixtures in isolation."""

  if not isolate:
    if not RunApptestInShell(config, shell, apptest, test_args, shell_args):
      return "Failed test(s) in %r" % apptest_dict
    return "Succeeded"

  # List the apptest fixtures so they can be run independently for isolation.
  fixtures = get_fixtures(config, shell, shell_args, apptest)

  if not fixtures:
    return "Failed with no tests found."

  apptest_result = "Succeeded"
  for fixture in fixtures:
    apptest_args = test_args + ["--gtest_filter=%s" % fixture]
    success = RunApptestInShell(config, shell, apptest, apptest_args,
                                shell_args)

    if not success:
      apptest_result = "Failed test(s) in %r" % apptest_dict

  return apptest_result


def run_test(config, shell, shell_args, apps_and_args=None):
  """Runs a command line and checks the output for signs of gtest failure.

  Args:
    config: The mopy.config.Config object for the build.
    shell_args: The arguments for mojo_shell.
    apps_and_args: A Dict keyed by application URL associated to the
        application's specific arguments.
  """
  apps_and_args = apps_and_args or {}
  output = test_util.try_run_test(config, shell, shell_args, apps_and_args)
  # Fail on output with gtest's "[  FAILED  ]" or a lack of "[  PASSED  ]".
  # The latter condition ensures failure on broken command lines or output.
  # Check output instead of exit codes because mojo_shell always exits with 0.
  if (output is None or
      (output.find("[  FAILED  ]") != -1 or output.find("[  PASSED  ]") == -1)):
    print "Failed test:"
    print_process_error(
        test_util.build_command_line(config, shell_args, apps_and_args),
        output)
    return False
  _logger.debug("Succeeded with output:\n%s" % output)
  return True


def get_fixtures(config, shell, shell_args, apptest):
  """Returns the "Test.Fixture" list from an apptest using mojo_shell.

  Tests are listed by running the given apptest in mojo_shell and passing
  --gtest_list_tests. The output is parsed and reformatted into a list like
  [TestSuite.TestFixture, ... ]
  An empty list is returned on failure, with errors logged.

  Args:
    config: The mopy.config.Config object for the build.
    apptest: The URL of the test application to run.
  """
  try:
    apps_and_args = {apptest: ["--gtest_list_tests"]}
    list_output = test_util.run_test(config, shell, shell_args, apps_and_args)
    _logger.debug("Tests listed:\n%s" % list_output)
    return _gtest_list_tests(list_output)
  except Exception as e:
    print "Failed to get test fixtures:"
    print_process_error(
        test_util.build_command_line(config, shell_args, apps_and_args), e)
  return []


def _gtest_list_tests(gtest_list_tests_output):
  """Returns a list of strings formatted as TestSuite.TestFixture from the
  output of running --gtest_list_tests on a GTEST application."""

  # Remove log lines.
  gtest_list_tests_output = re.sub("^(\[|WARNING: linker:).*\n",
                                   "",
                                   gtest_list_tests_output,
                                   flags=re.MULTILINE)

  if not re.match("^(\w*\.\r?\n(  \w*\r?\n)+)+", gtest_list_tests_output):
    raise Exception("Unrecognized --gtest_list_tests output:\n%s" %
                    gtest_list_tests_output)

  output_lines = gtest_list_tests_output.split("\n")

  test_list = []
  for line in output_lines:
    if not line:
      continue
    if line[0] != " ":
      suite = line.strip()
      continue
    test_list.append(suite + line.strip())

  return test_list


def RunApptestInShell(config, shell, application, application_args, shell_args):
  return run_test(config, shell, shell_args, {application: application_args})