xref: /aosp_15_r20/external/bazelbuild-rules_android/test/bashunit/unittest_test.py (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
1*9e965d6fSRomain Jobredeaux# Copyright 2020 The Bazel Authors. All rights reserved.
2*9e965d6fSRomain Jobredeaux#
3*9e965d6fSRomain Jobredeaux# Licensed under the Apache License, Version 2.0 (the "License");
4*9e965d6fSRomain Jobredeaux# you may not use this file except in compliance with the License.
5*9e965d6fSRomain Jobredeaux# You may obtain a copy of the License at
6*9e965d6fSRomain Jobredeaux#
7*9e965d6fSRomain Jobredeaux#    http://www.apache.org/licenses/LICENSE-2.0
8*9e965d6fSRomain Jobredeaux#
9*9e965d6fSRomain Jobredeaux# Unless required by applicable law or agreed to in writing, software
10*9e965d6fSRomain Jobredeaux# distributed under the License is distributed on an "AS IS" BASIS,
11*9e965d6fSRomain Jobredeaux# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9e965d6fSRomain Jobredeaux# See the License for the specific language governing permissions and
13*9e965d6fSRomain Jobredeaux# limitations under the License.
14*9e965d6fSRomain Jobredeaux
15*9e965d6fSRomain Jobredeaux"""Tests for unittest.bash."""
16*9e965d6fSRomain Jobredeaux
17*9e965d6fSRomain Jobredeauxfrom __future__ import absolute_import
18*9e965d6fSRomain Jobredeauxfrom __future__ import division
19*9e965d6fSRomain Jobredeauxfrom __future__ import print_function
20*9e965d6fSRomain Jobredeaux
21*9e965d6fSRomain Jobredeauximport os
22*9e965d6fSRomain Jobredeauximport re
23*9e965d6fSRomain Jobredeauximport shutil
24*9e965d6fSRomain Jobredeauximport stat
25*9e965d6fSRomain Jobredeauximport subprocess
26*9e965d6fSRomain Jobredeauximport tempfile
27*9e965d6fSRomain Jobredeauximport textwrap
28*9e965d6fSRomain Jobredeauximport unittest
29*9e965d6fSRomain Jobredeaux
30*9e965d6fSRomain Jobredeaux# The test setup for this external test is forwarded to the internal bash test.
31*9e965d6fSRomain Jobredeaux# This allows the internal test to use the same runfiles to load unittest.bash.
32*9e965d6fSRomain Jobredeaux_TEST_PREAMBLE = """
33*9e965d6fSRomain Jobredeaux#!/bin/bash
34*9e965d6fSRomain Jobredeaux# --- begin runfiles.bash initialization ---
35*9e965d6fSRomain Jobredeauxif [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
36*9e965d6fSRomain Jobredeaux  source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash"
37*9e965d6fSRomain Jobredeauxelse
38*9e965d6fSRomain Jobredeaux  echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash"
39*9e965d6fSRomain Jobredeaux  exit 1
40*9e965d6fSRomain Jobredeauxfi
41*9e965d6fSRomain Jobredeaux# --- end runfiles.bash initialization ---
42*9e965d6fSRomain Jobredeaux
43*9e965d6fSRomain Jobredeauxecho "Writing XML to ${XML_OUTPUT_FILE}"
44*9e965d6fSRomain Jobredeaux
45*9e965d6fSRomain Jobredeauxsource "$(rlocation "rules_android/test/bashunit/unittest.bash")" \
46*9e965d6fSRomain Jobredeaux  || { echo "Could not source unittest.bash" >&2; exit 1; }
47*9e965d6fSRomain Jobredeaux"""
48*9e965d6fSRomain Jobredeaux
49*9e965d6fSRomain JobredeauxANSI_ESCAPE = re.compile(r"(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]")
50*9e965d6fSRomain Jobredeaux
51*9e965d6fSRomain Jobredeaux
52*9e965d6fSRomain Jobredeauxdef remove_ansi(line):
53*9e965d6fSRomain Jobredeaux  """Remove ANSI-style escape sequences from the input."""
54*9e965d6fSRomain Jobredeaux  return ANSI_ESCAPE.sub("", line)
55*9e965d6fSRomain Jobredeaux
56*9e965d6fSRomain Jobredeaux
57*9e965d6fSRomain Jobredeauxclass TestResult(object):
58*9e965d6fSRomain Jobredeaux  """Save test results for easy checking."""
59*9e965d6fSRomain Jobredeaux
60*9e965d6fSRomain Jobredeaux  def __init__(self, asserter, return_code, output, xmlfile):
61*9e965d6fSRomain Jobredeaux    self._asserter = asserter
62*9e965d6fSRomain Jobredeaux    self._return_code = return_code
63*9e965d6fSRomain Jobredeaux    self._output = remove_ansi(output)
64*9e965d6fSRomain Jobredeaux
65*9e965d6fSRomain Jobredeaux    # Read in the XML result file.
66*9e965d6fSRomain Jobredeaux    if os.path.isfile(xmlfile):
67*9e965d6fSRomain Jobredeaux      with open(xmlfile, "r") as f:
68*9e965d6fSRomain Jobredeaux        self._xml = f.read()
69*9e965d6fSRomain Jobredeaux    else:
70*9e965d6fSRomain Jobredeaux      # Unable to read the file, errors will be reported later.
71*9e965d6fSRomain Jobredeaux      self._xml = ""
72*9e965d6fSRomain Jobredeaux
73*9e965d6fSRomain Jobredeaux  # Methods to assert on the state of the results.
74*9e965d6fSRomain Jobredeaux
75*9e965d6fSRomain Jobredeaux  def assertLogMessage(self, message):
76*9e965d6fSRomain Jobredeaux    self.assertExactlyOneMatch(self._output, message)
77*9e965d6fSRomain Jobredeaux
78*9e965d6fSRomain Jobredeaux  def assertNotLogMessage(self, message):
79*9e965d6fSRomain Jobredeaux    self._asserter.assertNotRegex(self._output, message)
80*9e965d6fSRomain Jobredeaux
81*9e965d6fSRomain Jobredeaux  def assertXmlMessage(self, message):
82*9e965d6fSRomain Jobredeaux    self.assertExactlyOneMatch(self._xml, message)
83*9e965d6fSRomain Jobredeaux
84*9e965d6fSRomain Jobredeaux  def assertNotXmlMessage(self, message):
85*9e965d6fSRomain Jobredeaux    self._asserter.assertNotRegex(self._xml, message)
86*9e965d6fSRomain Jobredeaux
87*9e965d6fSRomain Jobredeaux  def assertSuccess(self, suite_name):
88*9e965d6fSRomain Jobredeaux    self._asserter.assertEqual(0, self._return_code,
89*9e965d6fSRomain Jobredeaux                               f"Script failed unexpectedly:\n{self._output}")
90*9e965d6fSRomain Jobredeaux    self.assertLogMessage(suite_name)
91*9e965d6fSRomain Jobredeaux    self.assertXmlMessage("<testsuites [^/]*failures=\"0\"")
92*9e965d6fSRomain Jobredeaux    self.assertXmlMessage("<testsuites [^/]*errors=\"0\"")
93*9e965d6fSRomain Jobredeaux
94*9e965d6fSRomain Jobredeaux  def assertNotSuccess(self, suite_name, failures=0, errors=0):
95*9e965d6fSRomain Jobredeaux    self._asserter.assertNotEqual(0, self._return_code)
96*9e965d6fSRomain Jobredeaux    self.assertLogMessage(suite_name)
97*9e965d6fSRomain Jobredeaux    if failures:
98*9e965d6fSRomain Jobredeaux      self.assertXmlMessage(f'<testsuites [^/]*failures="{failures}"')
99*9e965d6fSRomain Jobredeaux    if errors:
100*9e965d6fSRomain Jobredeaux      self.assertXmlMessage(f'<testsuites [^/]*errors="{errors}"')
101*9e965d6fSRomain Jobredeaux
102*9e965d6fSRomain Jobredeaux  def assertTestPassed(self, test_name):
103*9e965d6fSRomain Jobredeaux    self.assertLogMessage(f"PASSED: {test_name}")
104*9e965d6fSRomain Jobredeaux
105*9e965d6fSRomain Jobredeaux  def assertTestFailed(self, test_name, message=""):
106*9e965d6fSRomain Jobredeaux    self.assertLogMessage(f"{test_name} FAILED: {message}")
107*9e965d6fSRomain Jobredeaux
108*9e965d6fSRomain Jobredeaux  def assertExactlyOneMatch(self, text, pattern):
109*9e965d6fSRomain Jobredeaux    self._asserter.assertRegex(text, pattern)
110*9e965d6fSRomain Jobredeaux    self._asserter.assertEqual(
111*9e965d6fSRomain Jobredeaux        len(re.findall(pattern, text)),
112*9e965d6fSRomain Jobredeaux        1,
113*9e965d6fSRomain Jobredeaux        msg=f"Found more than 1 match of '{pattern}' in '{text}'")
114*9e965d6fSRomain Jobredeaux
115*9e965d6fSRomain Jobredeaux
116*9e965d6fSRomain Jobredeauxclass UnittestTest(unittest.TestCase):
117*9e965d6fSRomain Jobredeaux
118*9e965d6fSRomain Jobredeaux  def setUp(self):
119*9e965d6fSRomain Jobredeaux    """Create a working directory under our temp dir."""
120*9e965d6fSRomain Jobredeaux    super(UnittestTest, self).setUp()
121*9e965d6fSRomain Jobredeaux    self.work_dir = tempfile.mkdtemp(dir=os.environ["TEST_TMPDIR"])
122*9e965d6fSRomain Jobredeaux
123*9e965d6fSRomain Jobredeaux  def tearDown(self):
124*9e965d6fSRomain Jobredeaux    """Clean up the working directory."""
125*9e965d6fSRomain Jobredeaux    super(UnittestTest, self).tearDown()
126*9e965d6fSRomain Jobredeaux    shutil.rmtree(self.work_dir)
127*9e965d6fSRomain Jobredeaux
128*9e965d6fSRomain Jobredeaux  def write_file(self, filename, contents=""):
129*9e965d6fSRomain Jobredeaux    """Write the contents to a file in the workdir."""
130*9e965d6fSRomain Jobredeaux
131*9e965d6fSRomain Jobredeaux    filepath = os.path.join(self.work_dir, filename)
132*9e965d6fSRomain Jobredeaux    with open(filepath, "w") as f:
133*9e965d6fSRomain Jobredeaux      f.write(_TEST_PREAMBLE.strip())
134*9e965d6fSRomain Jobredeaux      f.write(contents)
135*9e965d6fSRomain Jobredeaux    os.chmod(filepath, stat.S_IEXEC | stat.S_IWRITE | stat.S_IREAD)
136*9e965d6fSRomain Jobredeaux
137*9e965d6fSRomain Jobredeaux  def find_runfiles(self):
138*9e965d6fSRomain Jobredeaux    if "RUNFILES_DIR" in os.environ:
139*9e965d6fSRomain Jobredeaux      return os.environ["RUNFILES_DIR"]
140*9e965d6fSRomain Jobredeaux
141*9e965d6fSRomain Jobredeaux    # Fall back to being based on the srcdir.
142*9e965d6fSRomain Jobredeaux    if "TEST_SRCDIR" in os.environ:
143*9e965d6fSRomain Jobredeaux      return os.environ["TEST_SRCDIR"]
144*9e965d6fSRomain Jobredeaux
145*9e965d6fSRomain Jobredeaux    # Base on the current dir
146*9e965d6fSRomain Jobredeaux    return f"{os.getcwd()}/.."
147*9e965d6fSRomain Jobredeaux
148*9e965d6fSRomain Jobredeaux  def execute_test(self, filename, env=None, args=()):
149*9e965d6fSRomain Jobredeaux    """Executes the file and stores the results."""
150*9e965d6fSRomain Jobredeaux
151*9e965d6fSRomain Jobredeaux    filepath = os.path.join(self.work_dir, filename)
152*9e965d6fSRomain Jobredeaux    xmlfile = os.path.join(self.work_dir, "dummy-testlog.xml")
153*9e965d6fSRomain Jobredeaux    test_env = {
154*9e965d6fSRomain Jobredeaux        "TEST_TMPDIR": self.work_dir,
155*9e965d6fSRomain Jobredeaux        "RUNFILES_DIR": self.find_runfiles(),
156*9e965d6fSRomain Jobredeaux        "TEST_SRCDIR": os.environ["TEST_SRCDIR"],
157*9e965d6fSRomain Jobredeaux        "XML_OUTPUT_FILE": xmlfile,
158*9e965d6fSRomain Jobredeaux    }
159*9e965d6fSRomain Jobredeaux    # Add in env, forcing everything to be a string.
160*9e965d6fSRomain Jobredeaux    if env:
161*9e965d6fSRomain Jobredeaux      for k, v in env.items():
162*9e965d6fSRomain Jobredeaux        test_env[k] = str(v)
163*9e965d6fSRomain Jobredeaux    completed = subprocess.run(
164*9e965d6fSRomain Jobredeaux        [filepath, *args],
165*9e965d6fSRomain Jobredeaux        env=test_env,
166*9e965d6fSRomain Jobredeaux        stdout=subprocess.PIPE,
167*9e965d6fSRomain Jobredeaux        stderr=subprocess.STDOUT,
168*9e965d6fSRomain Jobredeaux    )
169*9e965d6fSRomain Jobredeaux    return TestResult(self, completed.returncode,
170*9e965d6fSRomain Jobredeaux                      completed.stdout.decode("utf-8"), xmlfile)
171*9e965d6fSRomain Jobredeaux
172*9e965d6fSRomain Jobredeaux  # Actual test cases.
173*9e965d6fSRomain Jobredeaux
174*9e965d6fSRomain Jobredeaux  def test_success(self):
175*9e965d6fSRomain Jobredeaux    self.write_file(
176*9e965d6fSRomain Jobredeaux        "thing.sh", """
177*9e965d6fSRomain Jobredeauxfunction test_success() {
178*9e965d6fSRomain Jobredeaux  echo foo >&${TEST_log} || fail "expected echo to succeed"
179*9e965d6fSRomain Jobredeaux  expect_log "foo"
180*9e965d6fSRomain Jobredeaux}
181*9e965d6fSRomain Jobredeaux
182*9e965d6fSRomain Jobredeauxrun_suite "success tests"
183*9e965d6fSRomain Jobredeaux""")
184*9e965d6fSRomain Jobredeaux
185*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
186*9e965d6fSRomain Jobredeaux    result.assertSuccess("success tests")
187*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_success")
188*9e965d6fSRomain Jobredeaux
189*9e965d6fSRomain Jobredeaux  def test_timestamp(self):
190*9e965d6fSRomain Jobredeaux    self.write_file(
191*9e965d6fSRomain Jobredeaux        "thing.sh", """
192*9e965d6fSRomain Jobredeauxfunction test_timestamp() {
193*9e965d6fSRomain Jobredeaux  local ts=$(timestamp)
194*9e965d6fSRomain Jobredeaux  [[ $ts =~ ^[0-9]{13}$ ]] || fail "timestamp wan't valid: $ts"
195*9e965d6fSRomain Jobredeaux
196*9e965d6fSRomain Jobredeaux  local time_diff=$(get_run_time 100000 223456)
197*9e965d6fSRomain Jobredeaux  assert_equals $time_diff 123.456
198*9e965d6fSRomain Jobredeaux}
199*9e965d6fSRomain Jobredeaux
200*9e965d6fSRomain Jobredeauxrun_suite "timestamp tests"
201*9e965d6fSRomain Jobredeaux""")
202*9e965d6fSRomain Jobredeaux
203*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
204*9e965d6fSRomain Jobredeaux    result.assertSuccess("timestamp tests")
205*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_timestamp")
206*9e965d6fSRomain Jobredeaux
207*9e965d6fSRomain Jobredeaux  def test_failure(self):
208*9e965d6fSRomain Jobredeaux    self.write_file(
209*9e965d6fSRomain Jobredeaux        "thing.sh", """
210*9e965d6fSRomain Jobredeauxfunction test_failure() {
211*9e965d6fSRomain Jobredeaux  fail "I'm a failure with <>&\\" escaped symbols"
212*9e965d6fSRomain Jobredeaux}
213*9e965d6fSRomain Jobredeaux
214*9e965d6fSRomain Jobredeauxrun_suite "failure tests"
215*9e965d6fSRomain Jobredeaux""")
216*9e965d6fSRomain Jobredeaux
217*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
218*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("failure tests", failures=0, errors=1)
219*9e965d6fSRomain Jobredeaux    result.assertTestFailed("test_failure")
220*9e965d6fSRomain Jobredeaux    result.assertXmlMessage(
221*9e965d6fSRomain Jobredeaux        "message=\"I'm a failure with &lt;&gt;&amp;&quot; escaped symbols\"")
222*9e965d6fSRomain Jobredeaux    result.assertXmlMessage("I'm a failure with <>&\" escaped symbols")
223*9e965d6fSRomain Jobredeaux
224*9e965d6fSRomain Jobredeaux  def test_set_bash_errexit_prints_stack_trace(self):
225*9e965d6fSRomain Jobredeaux    self.write_file(
226*9e965d6fSRomain Jobredeaux        "thing.sh", """
227*9e965d6fSRomain Jobredeauxset -euo pipefail
228*9e965d6fSRomain Jobredeaux
229*9e965d6fSRomain Jobredeauxfunction helper() {
230*9e965d6fSRomain Jobredeaux  echo before
231*9e965d6fSRomain Jobredeaux  false
232*9e965d6fSRomain Jobredeaux  echo after
233*9e965d6fSRomain Jobredeaux}
234*9e965d6fSRomain Jobredeaux
235*9e965d6fSRomain Jobredeauxfunction test_failure_in_helper() {
236*9e965d6fSRomain Jobredeaux  helper
237*9e965d6fSRomain Jobredeaux}
238*9e965d6fSRomain Jobredeaux
239*9e965d6fSRomain Jobredeauxrun_suite "bash errexit tests"
240*9e965d6fSRomain Jobredeaux""")
241*9e965d6fSRomain Jobredeaux
242*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
243*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("bash errexit tests")
244*9e965d6fSRomain Jobredeaux    result.assertTestFailed("test_failure_in_helper")
245*9e965d6fSRomain Jobredeaux    result.assertLogMessage(r"./thing.sh:\d*: in call to helper")
246*9e965d6fSRomain Jobredeaux    result.assertLogMessage(
247*9e965d6fSRomain Jobredeaux        r"./thing.sh:\d*: in call to test_failure_in_helper")
248*9e965d6fSRomain Jobredeaux
249*9e965d6fSRomain Jobredeaux  def test_set_bash_errexit_runs_tear_down(self):
250*9e965d6fSRomain Jobredeaux    self.write_file(
251*9e965d6fSRomain Jobredeaux        "thing.sh", """
252*9e965d6fSRomain Jobredeauxset -euo pipefail
253*9e965d6fSRomain Jobredeaux
254*9e965d6fSRomain Jobredeauxfunction tear_down() {
255*9e965d6fSRomain Jobredeaux  echo "Running tear_down"
256*9e965d6fSRomain Jobredeaux}
257*9e965d6fSRomain Jobredeaux
258*9e965d6fSRomain Jobredeauxfunction testenv_tear_down() {
259*9e965d6fSRomain Jobredeaux  echo "Running testenv_tear_down"
260*9e965d6fSRomain Jobredeaux}
261*9e965d6fSRomain Jobredeaux
262*9e965d6fSRomain Jobredeauxfunction test_failure_in_helper() {
263*9e965d6fSRomain Jobredeaux  wrong_command
264*9e965d6fSRomain Jobredeaux}
265*9e965d6fSRomain Jobredeaux
266*9e965d6fSRomain Jobredeauxrun_suite "bash errexit tests"
267*9e965d6fSRomain Jobredeaux""")
268*9e965d6fSRomain Jobredeaux
269*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
270*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("bash errexit tests")
271*9e965d6fSRomain Jobredeaux    result.assertTestFailed("test_failure_in_helper")
272*9e965d6fSRomain Jobredeaux    result.assertLogMessage("Running tear_down")
273*9e965d6fSRomain Jobredeaux    result.assertLogMessage("Running testenv_tear_down")
274*9e965d6fSRomain Jobredeaux
275*9e965d6fSRomain Jobredeaux  def test_set_bash_errexit_pipefail_propagates_failure_through_pipe(self):
276*9e965d6fSRomain Jobredeaux    self.write_file(
277*9e965d6fSRomain Jobredeaux        "thing.sh", """
278*9e965d6fSRomain Jobredeauxset -euo pipefail
279*9e965d6fSRomain Jobredeaux
280*9e965d6fSRomain Jobredeauxfunction test_pipefail() {
281*9e965d6fSRomain Jobredeaux  wrong_command | cat
282*9e965d6fSRomain Jobredeaux  echo after
283*9e965d6fSRomain Jobredeaux}
284*9e965d6fSRomain Jobredeaux
285*9e965d6fSRomain Jobredeauxrun_suite "bash errexit tests"
286*9e965d6fSRomain Jobredeaux""")
287*9e965d6fSRomain Jobredeaux
288*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
289*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("bash errexit tests")
290*9e965d6fSRomain Jobredeaux    result.assertTestFailed("test_pipefail")
291*9e965d6fSRomain Jobredeaux    result.assertLogMessage("wrong_command: command not found")
292*9e965d6fSRomain Jobredeaux    result.assertNotLogMessage("after")
293*9e965d6fSRomain Jobredeaux
294*9e965d6fSRomain Jobredeaux  def test_set_bash_errexit_no_pipefail_ignores_failure_before_pipe(self):
295*9e965d6fSRomain Jobredeaux    self.write_file(
296*9e965d6fSRomain Jobredeaux        "thing.sh", """
297*9e965d6fSRomain Jobredeauxset -eu
298*9e965d6fSRomain Jobredeauxset +o pipefail
299*9e965d6fSRomain Jobredeaux
300*9e965d6fSRomain Jobredeauxfunction test_nopipefail() {
301*9e965d6fSRomain Jobredeaux  wrong_command | cat
302*9e965d6fSRomain Jobredeaux  echo after
303*9e965d6fSRomain Jobredeaux}
304*9e965d6fSRomain Jobredeaux
305*9e965d6fSRomain Jobredeauxrun_suite "bash errexit tests"
306*9e965d6fSRomain Jobredeaux""")
307*9e965d6fSRomain Jobredeaux
308*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
309*9e965d6fSRomain Jobredeaux    result.assertSuccess("bash errexit tests")
310*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_nopipefail")
311*9e965d6fSRomain Jobredeaux    result.assertLogMessage("wrong_command: command not found")
312*9e965d6fSRomain Jobredeaux    result.assertLogMessage("after")
313*9e965d6fSRomain Jobredeaux
314*9e965d6fSRomain Jobredeaux  def test_set_bash_errexit_pipefail_long_testname_succeeds(self):
315*9e965d6fSRomain Jobredeaux    test_name = "x" * 1000
316*9e965d6fSRomain Jobredeaux    self.write_file(
317*9e965d6fSRomain Jobredeaux        "thing.sh", """
318*9e965d6fSRomain Jobredeauxset -euo pipefail
319*9e965d6fSRomain Jobredeaux
320*9e965d6fSRomain Jobredeauxfunction test_%s() {
321*9e965d6fSRomain Jobredeaux  :
322*9e965d6fSRomain Jobredeaux}
323*9e965d6fSRomain Jobredeaux
324*9e965d6fSRomain Jobredeauxrun_suite "bash errexit tests"
325*9e965d6fSRomain Jobredeaux""" % test_name)
326*9e965d6fSRomain Jobredeaux
327*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
328*9e965d6fSRomain Jobredeaux    result.assertSuccess("bash errexit tests")
329*9e965d6fSRomain Jobredeaux
330*9e965d6fSRomain Jobredeaux  def test_empty_test_fails(self):
331*9e965d6fSRomain Jobredeaux    self.write_file("thing.sh", """
332*9e965d6fSRomain Jobredeaux# No tests present.
333*9e965d6fSRomain Jobredeaux
334*9e965d6fSRomain Jobredeauxrun_suite "empty test suite"
335*9e965d6fSRomain Jobredeaux""")
336*9e965d6fSRomain Jobredeaux
337*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
338*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("empty test suite")
339*9e965d6fSRomain Jobredeaux    result.assertLogMessage("No tests found.")
340*9e965d6fSRomain Jobredeaux
341*9e965d6fSRomain Jobredeaux  def test_empty_test_succeeds_sharding(self):
342*9e965d6fSRomain Jobredeaux    self.write_file(
343*9e965d6fSRomain Jobredeaux        "thing.sh", """
344*9e965d6fSRomain Jobredeaux# Only one test.
345*9e965d6fSRomain Jobredeauxfunction test_thing() {
346*9e965d6fSRomain Jobredeaux  echo
347*9e965d6fSRomain Jobredeaux}
348*9e965d6fSRomain Jobredeaux
349*9e965d6fSRomain Jobredeauxrun_suite "empty test suite"
350*9e965d6fSRomain Jobredeaux""")
351*9e965d6fSRomain Jobredeaux
352*9e965d6fSRomain Jobredeaux    # First shard.
353*9e965d6fSRomain Jobredeaux    result = self.execute_test(
354*9e965d6fSRomain Jobredeaux        "thing.sh", env={
355*9e965d6fSRomain Jobredeaux            "TEST_TOTAL_SHARDS": 2,
356*9e965d6fSRomain Jobredeaux            "TEST_SHARD_INDEX": 0,
357*9e965d6fSRomain Jobredeaux        })
358*9e965d6fSRomain Jobredeaux    result.assertSuccess("empty test suite")
359*9e965d6fSRomain Jobredeaux    result.assertLogMessage("No tests executed due to sharding")
360*9e965d6fSRomain Jobredeaux
361*9e965d6fSRomain Jobredeaux    # Second shard.
362*9e965d6fSRomain Jobredeaux    result = self.execute_test(
363*9e965d6fSRomain Jobredeaux        "thing.sh", env={
364*9e965d6fSRomain Jobredeaux            "TEST_TOTAL_SHARDS": 2,
365*9e965d6fSRomain Jobredeaux            "TEST_SHARD_INDEX": 1,
366*9e965d6fSRomain Jobredeaux        })
367*9e965d6fSRomain Jobredeaux    result.assertSuccess("empty test suite")
368*9e965d6fSRomain Jobredeaux    result.assertNotLogMessage("No tests")
369*9e965d6fSRomain Jobredeaux
370*9e965d6fSRomain Jobredeaux  def test_filter_runs_only_matching_test(self):
371*9e965d6fSRomain Jobredeaux    self.write_file(
372*9e965d6fSRomain Jobredeaux        "thing.sh",
373*9e965d6fSRomain Jobredeaux        textwrap.dedent("""
374*9e965d6fSRomain Jobredeaux        function test_abc() {
375*9e965d6fSRomain Jobredeaux          :
376*9e965d6fSRomain Jobredeaux        }
377*9e965d6fSRomain Jobredeaux
378*9e965d6fSRomain Jobredeaux        function test_def() {
379*9e965d6fSRomain Jobredeaux          echo "running def"
380*9e965d6fSRomain Jobredeaux        }
381*9e965d6fSRomain Jobredeaux
382*9e965d6fSRomain Jobredeaux        run_suite "tests to filter"
383*9e965d6fSRomain Jobredeaux        """))
384*9e965d6fSRomain Jobredeaux
385*9e965d6fSRomain Jobredeaux    result = self.execute_test(
386*9e965d6fSRomain Jobredeaux        "thing.sh", env={"TESTBRIDGE_TEST_ONLY": "test_a*"})
387*9e965d6fSRomain Jobredeaux
388*9e965d6fSRomain Jobredeaux    result.assertSuccess("tests to filter")
389*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_abc")
390*9e965d6fSRomain Jobredeaux    result.assertNotLogMessage("running def")
391*9e965d6fSRomain Jobredeaux
392*9e965d6fSRomain Jobredeaux  def test_filter_prefix_match_only_skips_test(self):
393*9e965d6fSRomain Jobredeaux    self.write_file(
394*9e965d6fSRomain Jobredeaux        "thing.sh",
395*9e965d6fSRomain Jobredeaux        textwrap.dedent("""
396*9e965d6fSRomain Jobredeaux        function test_abc() {
397*9e965d6fSRomain Jobredeaux          echo "running abc"
398*9e965d6fSRomain Jobredeaux        }
399*9e965d6fSRomain Jobredeaux
400*9e965d6fSRomain Jobredeaux        run_suite "tests to filter"
401*9e965d6fSRomain Jobredeaux        """))
402*9e965d6fSRomain Jobredeaux
403*9e965d6fSRomain Jobredeaux    result = self.execute_test(
404*9e965d6fSRomain Jobredeaux        "thing.sh", env={"TESTBRIDGE_TEST_ONLY": "test_a"})
405*9e965d6fSRomain Jobredeaux
406*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("tests to filter")
407*9e965d6fSRomain Jobredeaux    result.assertLogMessage("No tests found.")
408*9e965d6fSRomain Jobredeaux
409*9e965d6fSRomain Jobredeaux  def test_filter_multiple_globs_runs_tests_matching_any(self):
410*9e965d6fSRomain Jobredeaux    self.write_file(
411*9e965d6fSRomain Jobredeaux        "thing.sh",
412*9e965d6fSRomain Jobredeaux        textwrap.dedent("""
413*9e965d6fSRomain Jobredeaux        function test_abc() {
414*9e965d6fSRomain Jobredeaux          echo "running abc"
415*9e965d6fSRomain Jobredeaux        }
416*9e965d6fSRomain Jobredeaux
417*9e965d6fSRomain Jobredeaux        function test_def() {
418*9e965d6fSRomain Jobredeaux          echo "running def"
419*9e965d6fSRomain Jobredeaux        }
420*9e965d6fSRomain Jobredeaux
421*9e965d6fSRomain Jobredeaux        run_suite "tests to filter"
422*9e965d6fSRomain Jobredeaux        """))
423*9e965d6fSRomain Jobredeaux
424*9e965d6fSRomain Jobredeaux    result = self.execute_test(
425*9e965d6fSRomain Jobredeaux        "thing.sh", env={"TESTBRIDGE_TEST_ONLY": "donotmatch:*a*"})
426*9e965d6fSRomain Jobredeaux
427*9e965d6fSRomain Jobredeaux    result.assertSuccess("tests to filter")
428*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_abc")
429*9e965d6fSRomain Jobredeaux    result.assertNotLogMessage("running def")
430*9e965d6fSRomain Jobredeaux
431*9e965d6fSRomain Jobredeaux  def test_filter_character_group_runs_only_matching_tests(self):
432*9e965d6fSRomain Jobredeaux    self.write_file(
433*9e965d6fSRomain Jobredeaux        "thing.sh",
434*9e965d6fSRomain Jobredeaux        textwrap.dedent("""
435*9e965d6fSRomain Jobredeaux        function test_aaa() {
436*9e965d6fSRomain Jobredeaux          :
437*9e965d6fSRomain Jobredeaux        }
438*9e965d6fSRomain Jobredeaux
439*9e965d6fSRomain Jobredeaux        function test_daa() {
440*9e965d6fSRomain Jobredeaux          :
441*9e965d6fSRomain Jobredeaux        }
442*9e965d6fSRomain Jobredeaux
443*9e965d6fSRomain Jobredeaux        function test_zaa() {
444*9e965d6fSRomain Jobredeaux          echo "running zaa"
445*9e965d6fSRomain Jobredeaux        }
446*9e965d6fSRomain Jobredeaux
447*9e965d6fSRomain Jobredeaux        run_suite "tests to filter"
448*9e965d6fSRomain Jobredeaux        """))
449*9e965d6fSRomain Jobredeaux
450*9e965d6fSRomain Jobredeaux    result = self.execute_test(
451*9e965d6fSRomain Jobredeaux        "thing.sh", env={"TESTBRIDGE_TEST_ONLY": "test_[a-f]aa"})
452*9e965d6fSRomain Jobredeaux
453*9e965d6fSRomain Jobredeaux    result.assertSuccess("tests to filter")
454*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_aaa")
455*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_daa")
456*9e965d6fSRomain Jobredeaux    result.assertNotLogMessage("running zaa")
457*9e965d6fSRomain Jobredeaux
458*9e965d6fSRomain Jobredeaux  def test_filter_sharded_runs_subset_of_filtered_tests(self):
459*9e965d6fSRomain Jobredeaux    for index in range(2):
460*9e965d6fSRomain Jobredeaux      with self.subTest(index=index):
461*9e965d6fSRomain Jobredeaux        self.__filter_sharded_runs_subset_of_filtered_tests(index)
462*9e965d6fSRomain Jobredeaux
463*9e965d6fSRomain Jobredeaux  def __filter_sharded_runs_subset_of_filtered_tests(self, index):
464*9e965d6fSRomain Jobredeaux    self.write_file(
465*9e965d6fSRomain Jobredeaux        "thing.sh",
466*9e965d6fSRomain Jobredeaux        textwrap.dedent("""
467*9e965d6fSRomain Jobredeaux        function test_a0() {
468*9e965d6fSRomain Jobredeaux          echo "running a0"
469*9e965d6fSRomain Jobredeaux        }
470*9e965d6fSRomain Jobredeaux
471*9e965d6fSRomain Jobredeaux        function test_a1() {
472*9e965d6fSRomain Jobredeaux          echo "running a1"
473*9e965d6fSRomain Jobredeaux        }
474*9e965d6fSRomain Jobredeaux
475*9e965d6fSRomain Jobredeaux        function test_bb() {
476*9e965d6fSRomain Jobredeaux          echo "running bb"
477*9e965d6fSRomain Jobredeaux        }
478*9e965d6fSRomain Jobredeaux
479*9e965d6fSRomain Jobredeaux        run_suite "tests to filter"
480*9e965d6fSRomain Jobredeaux        """))
481*9e965d6fSRomain Jobredeaux
482*9e965d6fSRomain Jobredeaux    result = self.execute_test(
483*9e965d6fSRomain Jobredeaux        "thing.sh",
484*9e965d6fSRomain Jobredeaux        env={
485*9e965d6fSRomain Jobredeaux            "TESTBRIDGE_TEST_ONLY": "test_a*",
486*9e965d6fSRomain Jobredeaux            "TEST_TOTAL_SHARDS": 2,
487*9e965d6fSRomain Jobredeaux            "TEST_SHARD_INDEX": index
488*9e965d6fSRomain Jobredeaux        })
489*9e965d6fSRomain Jobredeaux
490*9e965d6fSRomain Jobredeaux    result.assertSuccess("tests to filter")
491*9e965d6fSRomain Jobredeaux    # The sharding logic is shifted by 1, starts with 2nd shard.
492*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_a" + str(index ^ 1))
493*9e965d6fSRomain Jobredeaux    result.assertLogMessage("running a" + str(index ^ 1))
494*9e965d6fSRomain Jobredeaux    result.assertNotLogMessage("running a" + str(index))
495*9e965d6fSRomain Jobredeaux    result.assertNotLogMessage("running bb")
496*9e965d6fSRomain Jobredeaux
497*9e965d6fSRomain Jobredeaux  def test_arg_runs_only_matching_test_and_issues_warning(self):
498*9e965d6fSRomain Jobredeaux    self.write_file(
499*9e965d6fSRomain Jobredeaux        "thing.sh",
500*9e965d6fSRomain Jobredeaux        textwrap.dedent("""
501*9e965d6fSRomain Jobredeaux        function test_abc() {
502*9e965d6fSRomain Jobredeaux          :
503*9e965d6fSRomain Jobredeaux        }
504*9e965d6fSRomain Jobredeaux
505*9e965d6fSRomain Jobredeaux        function test_def() {
506*9e965d6fSRomain Jobredeaux          echo "running def"
507*9e965d6fSRomain Jobredeaux        }
508*9e965d6fSRomain Jobredeaux
509*9e965d6fSRomain Jobredeaux        run_suite "tests to filter"
510*9e965d6fSRomain Jobredeaux        """))
511*9e965d6fSRomain Jobredeaux
512*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh", args=["test_abc"])
513*9e965d6fSRomain Jobredeaux
514*9e965d6fSRomain Jobredeaux    result.assertSuccess("tests to filter")
515*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_abc")
516*9e965d6fSRomain Jobredeaux    result.assertNotLogMessage("running def")
517*9e965d6fSRomain Jobredeaux    result.assertLogMessage(
518*9e965d6fSRomain Jobredeaux        r"WARNING: Passing test names in arguments \(--test_arg\) is "
519*9e965d6fSRomain Jobredeaux        "deprecated, please use --test_filter='test_abc' instead.")
520*9e965d6fSRomain Jobredeaux
521*9e965d6fSRomain Jobredeaux  def test_arg_multiple_tests_issues_warning_with_test_filter_command(self):
522*9e965d6fSRomain Jobredeaux    self.write_file(
523*9e965d6fSRomain Jobredeaux        "thing.sh",
524*9e965d6fSRomain Jobredeaux        textwrap.dedent("""
525*9e965d6fSRomain Jobredeaux        function test_abc() {
526*9e965d6fSRomain Jobredeaux          :
527*9e965d6fSRomain Jobredeaux        }
528*9e965d6fSRomain Jobredeaux
529*9e965d6fSRomain Jobredeaux        function test_def() {
530*9e965d6fSRomain Jobredeaux          :
531*9e965d6fSRomain Jobredeaux        }
532*9e965d6fSRomain Jobredeaux
533*9e965d6fSRomain Jobredeaux        run_suite "tests to filter"
534*9e965d6fSRomain Jobredeaux        """))
535*9e965d6fSRomain Jobredeaux
536*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh", args=["test_abc", "test_def"])
537*9e965d6fSRomain Jobredeaux
538*9e965d6fSRomain Jobredeaux    result.assertSuccess("tests to filter")
539*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_abc")
540*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_def")
541*9e965d6fSRomain Jobredeaux    result.assertLogMessage(
542*9e965d6fSRomain Jobredeaux        r"WARNING: Passing test names in arguments \(--test_arg\) is "
543*9e965d6fSRomain Jobredeaux        "deprecated, please use --test_filter='test_abc:test_def' instead.")
544*9e965d6fSRomain Jobredeaux
545*9e965d6fSRomain Jobredeaux  def test_arg_and_filter_ignores_arg(self):
546*9e965d6fSRomain Jobredeaux    self.write_file(
547*9e965d6fSRomain Jobredeaux        "thing.sh",
548*9e965d6fSRomain Jobredeaux        textwrap.dedent("""
549*9e965d6fSRomain Jobredeaux        function test_abc() {
550*9e965d6fSRomain Jobredeaux          :
551*9e965d6fSRomain Jobredeaux        }
552*9e965d6fSRomain Jobredeaux
553*9e965d6fSRomain Jobredeaux        function test_def() {
554*9e965d6fSRomain Jobredeaux          echo "running def"
555*9e965d6fSRomain Jobredeaux        }
556*9e965d6fSRomain Jobredeaux
557*9e965d6fSRomain Jobredeaux        run_suite "tests to filter"
558*9e965d6fSRomain Jobredeaux        """))
559*9e965d6fSRomain Jobredeaux
560*9e965d6fSRomain Jobredeaux    result = self.execute_test(
561*9e965d6fSRomain Jobredeaux        "thing.sh", args=["test_def"], env={"TESTBRIDGE_TEST_ONLY": "test_a*"})
562*9e965d6fSRomain Jobredeaux
563*9e965d6fSRomain Jobredeaux    result.assertSuccess("tests to filter")
564*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_abc")
565*9e965d6fSRomain Jobredeaux    result.assertNotLogMessage("running def")
566*9e965d6fSRomain Jobredeaux    result.assertLogMessage(
567*9e965d6fSRomain Jobredeaux        "WARNING: Both --test_arg and --test_filter specified, ignoring --test_arg"
568*9e965d6fSRomain Jobredeaux    )
569*9e965d6fSRomain Jobredeaux
570*9e965d6fSRomain Jobredeaux  def test_custom_ifs_variable_finds_and_runs_test(self):
571*9e965d6fSRomain Jobredeaux    for sharded in (False, True):
572*9e965d6fSRomain Jobredeaux      for ifs in (r"\t", "t"):
573*9e965d6fSRomain Jobredeaux        with self.subTest(ifs=ifs, sharded=sharded):
574*9e965d6fSRomain Jobredeaux          self.__custom_ifs_variable_finds_and_runs_test(ifs, sharded)
575*9e965d6fSRomain Jobredeaux
576*9e965d6fSRomain Jobredeaux  def __custom_ifs_variable_finds_and_runs_test(self, ifs, sharded):
577*9e965d6fSRomain Jobredeaux    self.write_file(
578*9e965d6fSRomain Jobredeaux        "thing.sh",
579*9e965d6fSRomain Jobredeaux        textwrap.dedent(r"""
580*9e965d6fSRomain Jobredeaux        set -euo pipefail
581*9e965d6fSRomain Jobredeaux        IFS=$'%s'
582*9e965d6fSRomain Jobredeaux        function test_foo() {
583*9e965d6fSRomain Jobredeaux          :
584*9e965d6fSRomain Jobredeaux        }
585*9e965d6fSRomain Jobredeaux
586*9e965d6fSRomain Jobredeaux        run_suite "custom IFS test"
587*9e965d6fSRomain Jobredeaux        """ % ifs))
588*9e965d6fSRomain Jobredeaux
589*9e965d6fSRomain Jobredeaux    result = self.execute_test(
590*9e965d6fSRomain Jobredeaux        "thing.sh",
591*9e965d6fSRomain Jobredeaux        env={} if not sharded else {
592*9e965d6fSRomain Jobredeaux            "TEST_TOTAL_SHARDS": 2,
593*9e965d6fSRomain Jobredeaux            "TEST_SHARD_INDEX": 1
594*9e965d6fSRomain Jobredeaux        })
595*9e965d6fSRomain Jobredeaux
596*9e965d6fSRomain Jobredeaux    result.assertSuccess("custom IFS test")
597*9e965d6fSRomain Jobredeaux    result.assertTestPassed("test_foo")
598*9e965d6fSRomain Jobredeaux
599*9e965d6fSRomain Jobredeaux  def test_fail_in_teardown_reports_failure(self):
600*9e965d6fSRomain Jobredeaux    self.write_file(
601*9e965d6fSRomain Jobredeaux        "thing.sh",
602*9e965d6fSRomain Jobredeaux        textwrap.dedent(r"""
603*9e965d6fSRomain Jobredeaux        function tear_down() {
604*9e965d6fSRomain Jobredeaux          echo "tear_down log" >"${TEST_log}"
605*9e965d6fSRomain Jobredeaux          fail "tear_down failure"
606*9e965d6fSRomain Jobredeaux        }
607*9e965d6fSRomain Jobredeaux
608*9e965d6fSRomain Jobredeaux        function test_foo() {
609*9e965d6fSRomain Jobredeaux          :
610*9e965d6fSRomain Jobredeaux        }
611*9e965d6fSRomain Jobredeaux
612*9e965d6fSRomain Jobredeaux        run_suite "Failure in tear_down test"
613*9e965d6fSRomain Jobredeaux        """))
614*9e965d6fSRomain Jobredeaux
615*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
616*9e965d6fSRomain Jobredeaux
617*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("Failure in tear_down test", errors=1)
618*9e965d6fSRomain Jobredeaux    result.assertTestFailed("test_foo", "tear_down failure")
619*9e965d6fSRomain Jobredeaux    result.assertXmlMessage('message="tear_down failure"')
620*9e965d6fSRomain Jobredeaux    result.assertLogMessage("tear_down log")
621*9e965d6fSRomain Jobredeaux
622*9e965d6fSRomain Jobredeaux  def test_fail_in_teardown_after_test_failure_reports_both_failures(self):
623*9e965d6fSRomain Jobredeaux    self.write_file(
624*9e965d6fSRomain Jobredeaux        "thing.sh",
625*9e965d6fSRomain Jobredeaux        textwrap.dedent(r"""
626*9e965d6fSRomain Jobredeaux        function tear_down() {
627*9e965d6fSRomain Jobredeaux          echo "tear_down log" >"${TEST_log}"
628*9e965d6fSRomain Jobredeaux          fail "tear_down failure"
629*9e965d6fSRomain Jobredeaux        }
630*9e965d6fSRomain Jobredeaux
631*9e965d6fSRomain Jobredeaux        function test_foo() {
632*9e965d6fSRomain Jobredeaux          echo "test_foo log" >"${TEST_log}"
633*9e965d6fSRomain Jobredeaux          fail "Test failure"
634*9e965d6fSRomain Jobredeaux        }
635*9e965d6fSRomain Jobredeaux
636*9e965d6fSRomain Jobredeaux        run_suite "Failure in tear_down test"
637*9e965d6fSRomain Jobredeaux        """))
638*9e965d6fSRomain Jobredeaux
639*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
640*9e965d6fSRomain Jobredeaux
641*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("Failure in tear_down test", errors=1)
642*9e965d6fSRomain Jobredeaux    result.assertTestFailed("test_foo", "Test failure")
643*9e965d6fSRomain Jobredeaux    result.assertTestFailed("test_foo", "tear_down failure")
644*9e965d6fSRomain Jobredeaux    result.assertXmlMessage('message="Test failure"')
645*9e965d6fSRomain Jobredeaux    result.assertNotXmlMessage('message="tear_down failure"')
646*9e965d6fSRomain Jobredeaux    result.assertXmlMessage("test_foo log")
647*9e965d6fSRomain Jobredeaux    result.assertXmlMessage("tear_down log")
648*9e965d6fSRomain Jobredeaux    result.assertLogMessage("Test failure")
649*9e965d6fSRomain Jobredeaux    result.assertLogMessage("tear_down failure")
650*9e965d6fSRomain Jobredeaux    result.assertLogMessage("test_foo log")
651*9e965d6fSRomain Jobredeaux    result.assertLogMessage("tear_down log")
652*9e965d6fSRomain Jobredeaux
653*9e965d6fSRomain Jobredeaux  def test_errexit_in_teardown_reports_failure(self):
654*9e965d6fSRomain Jobredeaux    self.write_file(
655*9e965d6fSRomain Jobredeaux        "thing.sh",
656*9e965d6fSRomain Jobredeaux        textwrap.dedent(r"""
657*9e965d6fSRomain Jobredeaux        set -euo pipefail
658*9e965d6fSRomain Jobredeaux
659*9e965d6fSRomain Jobredeaux        function tear_down() {
660*9e965d6fSRomain Jobredeaux          invalid_command
661*9e965d6fSRomain Jobredeaux        }
662*9e965d6fSRomain Jobredeaux
663*9e965d6fSRomain Jobredeaux        function test_foo() {
664*9e965d6fSRomain Jobredeaux          :
665*9e965d6fSRomain Jobredeaux        }
666*9e965d6fSRomain Jobredeaux
667*9e965d6fSRomain Jobredeaux        run_suite "errexit in tear_down test"
668*9e965d6fSRomain Jobredeaux        """))
669*9e965d6fSRomain Jobredeaux
670*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
671*9e965d6fSRomain Jobredeaux
672*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("errexit in tear_down test")
673*9e965d6fSRomain Jobredeaux    result.assertLogMessage("invalid_command: command not found")
674*9e965d6fSRomain Jobredeaux    result.assertXmlMessage('message="No failure message"')
675*9e965d6fSRomain Jobredeaux    result.assertXmlMessage("invalid_command: command not found")
676*9e965d6fSRomain Jobredeaux
677*9e965d6fSRomain Jobredeaux  def test_fail_in_tear_down_after_errexit_reports_both_failures(self):
678*9e965d6fSRomain Jobredeaux    self.write_file(
679*9e965d6fSRomain Jobredeaux        "thing.sh",
680*9e965d6fSRomain Jobredeaux        textwrap.dedent(r"""
681*9e965d6fSRomain Jobredeaux        set -euo pipefail
682*9e965d6fSRomain Jobredeaux
683*9e965d6fSRomain Jobredeaux        function tear_down() {
684*9e965d6fSRomain Jobredeaux          echo "tear_down log" >"${TEST_log}"
685*9e965d6fSRomain Jobredeaux          fail "tear_down failure"
686*9e965d6fSRomain Jobredeaux        }
687*9e965d6fSRomain Jobredeaux
688*9e965d6fSRomain Jobredeaux        function test_foo() {
689*9e965d6fSRomain Jobredeaux          invalid_command
690*9e965d6fSRomain Jobredeaux        }
691*9e965d6fSRomain Jobredeaux
692*9e965d6fSRomain Jobredeaux        run_suite "fail after failure"
693*9e965d6fSRomain Jobredeaux        """))
694*9e965d6fSRomain Jobredeaux
695*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
696*9e965d6fSRomain Jobredeaux
697*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("fail after failure")
698*9e965d6fSRomain Jobredeaux    result.assertTestFailed(
699*9e965d6fSRomain Jobredeaux        "test_foo",
700*9e965d6fSRomain Jobredeaux        "terminated because this command returned a non-zero status")
701*9e965d6fSRomain Jobredeaux    result.assertTestFailed("test_foo", "tear_down failure")
702*9e965d6fSRomain Jobredeaux    result.assertLogMessage("invalid_command: command not found")
703*9e965d6fSRomain Jobredeaux    result.assertLogMessage("tear_down log")
704*9e965d6fSRomain Jobredeaux    result.assertXmlMessage('message="No failure message"')
705*9e965d6fSRomain Jobredeaux    result.assertXmlMessage("invalid_command: command not found")
706*9e965d6fSRomain Jobredeaux
707*9e965d6fSRomain Jobredeaux  def test_errexit_in_tear_down_after_errexit_reports_both_failures(self):
708*9e965d6fSRomain Jobredeaux    self.write_file(
709*9e965d6fSRomain Jobredeaux        "thing.sh",
710*9e965d6fSRomain Jobredeaux        textwrap.dedent(r"""
711*9e965d6fSRomain Jobredeaux        set -euo pipefail
712*9e965d6fSRomain Jobredeaux
713*9e965d6fSRomain Jobredeaux        function tear_down() {
714*9e965d6fSRomain Jobredeaux          invalid_command_tear_down
715*9e965d6fSRomain Jobredeaux        }
716*9e965d6fSRomain Jobredeaux
717*9e965d6fSRomain Jobredeaux        function test_foo() {
718*9e965d6fSRomain Jobredeaux          invalid_command_test
719*9e965d6fSRomain Jobredeaux        }
720*9e965d6fSRomain Jobredeaux
721*9e965d6fSRomain Jobredeaux        run_suite "fail after failure"
722*9e965d6fSRomain Jobredeaux        """))
723*9e965d6fSRomain Jobredeaux
724*9e965d6fSRomain Jobredeaux    result = self.execute_test("thing.sh")
725*9e965d6fSRomain Jobredeaux
726*9e965d6fSRomain Jobredeaux    result.assertNotSuccess("fail after failure")
727*9e965d6fSRomain Jobredeaux    result.assertTestFailed(
728*9e965d6fSRomain Jobredeaux        "test_foo",
729*9e965d6fSRomain Jobredeaux        "terminated because this command returned a non-zero status")
730*9e965d6fSRomain Jobredeaux    result.assertLogMessage("invalid_command_test: command not found")
731*9e965d6fSRomain Jobredeaux    result.assertLogMessage("invalid_command_tear_down: command not found")
732*9e965d6fSRomain Jobredeaux    result.assertXmlMessage('message="No failure message"')
733*9e965d6fSRomain Jobredeaux    result.assertXmlMessage("invalid_command_test: command not found")
734*9e965d6fSRomain Jobredeaux    result.assertXmlMessage("invalid_command_tear_down: command not found")
735*9e965d6fSRomain Jobredeaux
736*9e965d6fSRomain Jobredeaux
737*9e965d6fSRomain Jobredeauxif __name__ == "__main__":
738*9e965d6fSRomain Jobredeaux  unittest.main()
739