Summary: Moves lldbsuite tests to lldb/test/API.
This is a largely mechanical change, moved with the following steps:
```
rm lldb/test/API/testcases
mkdir -p lldb/test/API/{test_runner/test,tools/lldb-{server,vscode}}
mv lldb/packages/Python/lldbsuite/test/test_runner/test lldb/test/API/test_runner
for d in $(find lldb/packages/Python/lldbsuite/test/* -maxdepth 0 -type d | egrep -v "make|plugins|test_runner|tools"); do mv $d lldb/test/API; done
for d in $(find lldb/packages/Python/lldbsuite/test/tools/lldb-vscode -maxdepth 1 -mindepth 1 | grep -v ".py"); do mv $d lldb/test/API/tools/lldb-vscode; done
for d in $(find lldb/packages/Python/lldbsuite/test/tools/lldb-server -maxdepth 1 -mindepth 1 | egrep -v "gdbremote_testcase.py|lldbgdbserverutils.py|socket_packet_pump.py"); do mv $d lldb/test/API/tools/lldb-server; done
```
lldb/packages/Python/lldbsuite/__init__.py and lldb/test/API/lit.cfg.py were also updated with the new directory structure.
Reviewers: labath, JDevlieghere
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D71151
241 lines
8.2 KiB
Python
Executable File
241 lines
8.2 KiB
Python
Executable File
#!/usr/bin/env python
|
|
"""
|
|
Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
See https://llvm.org/LICENSE.txt for license information.
|
|
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
Provides classes used by the test results reporting infrastructure
|
|
within the LLDB test suite.
|
|
|
|
|
|
Tests the process_control module.
|
|
"""
|
|
|
|
|
|
# System imports.
|
|
import os
|
|
import os.path
|
|
import unittest
|
|
import sys
|
|
import threading
|
|
|
|
# Our imports.
|
|
from test_runner import process_control
|
|
|
|
|
|
class TestInferiorDriver(process_control.ProcessDriver):
|
|
|
|
def __init__(self, soft_terminate_timeout=None):
|
|
super(TestInferiorDriver, self).__init__(
|
|
soft_terminate_timeout=soft_terminate_timeout)
|
|
self.started_event = threading.Event()
|
|
self.started_event.clear()
|
|
|
|
self.completed_event = threading.Event()
|
|
self.completed_event.clear()
|
|
|
|
self.was_timeout = False
|
|
self.returncode = None
|
|
self.output = None
|
|
|
|
def write(self, content):
|
|
# We'll swallow this to keep tests non-noisy.
|
|
# Uncomment the following line if you want to see it.
|
|
# sys.stdout.write(content)
|
|
pass
|
|
|
|
def on_process_started(self):
|
|
self.started_event.set()
|
|
|
|
def on_process_exited(self, command, output, was_timeout, exit_status):
|
|
self.returncode = exit_status
|
|
self.was_timeout = was_timeout
|
|
self.output = output
|
|
self.returncode = exit_status
|
|
self.completed_event.set()
|
|
|
|
|
|
class ProcessControlTests(unittest.TestCase):
|
|
|
|
@classmethod
|
|
def _suppress_soft_terminate(cls, command):
|
|
# Do the right thing for your platform here.
|
|
# Right now only POSIX-y systems are reporting
|
|
# soft terminate support, so this is set up for
|
|
# those.
|
|
helper = process_control.ProcessHelper.process_helper()
|
|
signals = helper.soft_terminate_signals()
|
|
if signals is not None:
|
|
for signum in helper.soft_terminate_signals():
|
|
command.extend(["--ignore-signal", str(signum)])
|
|
|
|
@classmethod
|
|
def inferior_command(
|
|
cls,
|
|
ignore_soft_terminate=False,
|
|
options=None):
|
|
|
|
# Base command.
|
|
script_name = "{}/inferior.py".format(os.path.dirname(__file__))
|
|
if not os.path.exists(script_name):
|
|
raise Exception(
|
|
"test inferior python script not found: {}".format(script_name))
|
|
command = ([sys.executable, script_name])
|
|
|
|
if ignore_soft_terminate:
|
|
cls._suppress_soft_terminate(command)
|
|
|
|
# Handle options as string or list.
|
|
if isinstance(options, str):
|
|
command.extend(options.split())
|
|
elif isinstance(options, list):
|
|
command.extend(options)
|
|
|
|
# Return full command.
|
|
return command
|
|
|
|
|
|
class ProcessControlNoTimeoutTests(ProcessControlTests):
|
|
"""Tests the process_control module."""
|
|
|
|
def test_run_completes(self):
|
|
"""Test that running completes and gets expected stdout/stderr."""
|
|
driver = TestInferiorDriver()
|
|
driver.run_command(self.inferior_command())
|
|
self.assertTrue(
|
|
driver.completed_event.wait(5), "process failed to complete")
|
|
self.assertEqual(driver.returncode, 0, "return code does not match")
|
|
|
|
def test_run_completes_with_code(self):
|
|
"""Test that running completes and gets expected stdout/stderr."""
|
|
driver = TestInferiorDriver()
|
|
driver.run_command(self.inferior_command(options="-r10"))
|
|
self.assertTrue(
|
|
driver.completed_event.wait(5), "process failed to complete")
|
|
self.assertEqual(driver.returncode, 10, "return code does not match")
|
|
|
|
|
|
class ProcessControlTimeoutTests(ProcessControlTests):
|
|
|
|
def test_run_completes(self):
|
|
"""Test that running completes and gets expected return code."""
|
|
driver = TestInferiorDriver()
|
|
timeout_seconds = 5
|
|
driver.run_command_with_timeout(
|
|
self.inferior_command(),
|
|
"{}s".format(timeout_seconds),
|
|
False)
|
|
self.assertTrue(
|
|
driver.completed_event.wait(2 * timeout_seconds),
|
|
"process failed to complete")
|
|
self.assertEqual(driver.returncode, 0)
|
|
|
|
def _soft_terminate_works(self, with_core):
|
|
# Skip this test if the platform doesn't support soft ti
|
|
helper = process_control.ProcessHelper.process_helper()
|
|
if not helper.supports_soft_terminate():
|
|
self.skipTest("soft terminate not supported by platform")
|
|
|
|
driver = TestInferiorDriver()
|
|
timeout_seconds = 5
|
|
|
|
driver.run_command_with_timeout(
|
|
# Sleep twice as long as the timeout interval. This
|
|
# should force a timeout.
|
|
self.inferior_command(
|
|
options="--sleep {}".format(timeout_seconds * 2)),
|
|
"{}s".format(timeout_seconds),
|
|
with_core)
|
|
|
|
# We should complete, albeit with a timeout.
|
|
self.assertTrue(
|
|
driver.completed_event.wait(2 * timeout_seconds),
|
|
"process failed to complete")
|
|
|
|
# Ensure we received a timeout.
|
|
self.assertTrue(driver.was_timeout, "expected to end with a timeout")
|
|
|
|
self.assertTrue(
|
|
helper.was_soft_terminate(driver.returncode, with_core),
|
|
("timeout didn't return expected returncode "
|
|
"for soft terminate with core: {}").format(driver.returncode))
|
|
|
|
def test_soft_terminate_works_core(self):
|
|
"""Driver uses soft terminate (with core request) when process times out.
|
|
"""
|
|
self._soft_terminate_works(True)
|
|
|
|
def test_soft_terminate_works_no_core(self):
|
|
"""Driver uses soft terminate (no core request) when process times out.
|
|
"""
|
|
self._soft_terminate_works(False)
|
|
|
|
def test_hard_terminate_works(self):
|
|
"""Driver falls back to hard terminate when soft terminate is ignored.
|
|
"""
|
|
|
|
driver = TestInferiorDriver(soft_terminate_timeout=2.0)
|
|
timeout_seconds = 1
|
|
|
|
driver.run_command_with_timeout(
|
|
# Sleep much longer than the timeout interval,forcing a
|
|
# timeout. Do whatever is needed to have the inferior
|
|
# ignore soft terminate calls.
|
|
self.inferior_command(
|
|
ignore_soft_terminate=True,
|
|
options="--never-return"),
|
|
"{}s".format(timeout_seconds),
|
|
True)
|
|
|
|
# We should complete, albeit with a timeout.
|
|
self.assertTrue(
|
|
driver.completed_event.wait(60),
|
|
"process failed to complete")
|
|
|
|
# Ensure we received a timeout.
|
|
self.assertTrue(driver.was_timeout, "expected to end with a timeout")
|
|
|
|
helper = process_control.ProcessHelper.process_helper()
|
|
self.assertTrue(
|
|
helper.was_hard_terminate(driver.returncode),
|
|
("timeout didn't return expected returncode "
|
|
"for hard teriminate: {} ({})").format(
|
|
driver.returncode,
|
|
driver.output))
|
|
|
|
def test_inferior_exits_with_live_child_shared_handles(self):
|
|
"""inferior exit detected when inferior children are live with shared
|
|
stdout/stderr handles.
|
|
"""
|
|
# Requires review D13362 or equivalent to be implemented.
|
|
self.skipTest("http://reviews.llvm.org/D13362")
|
|
|
|
driver = TestInferiorDriver()
|
|
|
|
# Create the inferior (I1), and instruct it to create a child (C1)
|
|
# that shares the stdout/stderr handles with the inferior.
|
|
# C1 will then loop forever.
|
|
driver.run_command_with_timeout(
|
|
self.inferior_command(
|
|
options="--launch-child-share-handles --return-code 3"),
|
|
"5s",
|
|
False)
|
|
|
|
# We should complete without a timetout. I1 should end
|
|
# immediately after launching C1.
|
|
self.assertTrue(
|
|
driver.completed_event.wait(5),
|
|
"process failed to complete")
|
|
|
|
# Ensure we didn't receive a timeout.
|
|
self.assertFalse(
|
|
driver.was_timeout, "inferior should have completed normally")
|
|
|
|
self.assertEqual(
|
|
driver.returncode, 3,
|
|
"expected inferior process to end with expected returncode")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|