def test_pantsd_run(self): with self.pantsd_successful_run_context(log_level="debug") as ctx: ctx.runner(["list", "3rdparty:"]) ctx.checker.assert_started() ctx.runner(["list", ":"]) ctx.checker.assert_running() ctx.runner(["list", "::"]) ctx.checker.assert_running() # And again using the cached BuildGraph. ctx.runner(["list", "::"]) ctx.checker.assert_running() # Assert there were no warnings or errors thrown in the pantsd log. full_log = "\n".join(read_pantsd_log(ctx.workdir)) for line in read_pantsd_log(ctx.workdir): # Ignore deprecation warning emissions. if "DeprecationWarning" in line: continue # Check if the line begins with W or E to check if it is a warning or error line. self.assertNotRegex( line, r"^[WE].*", f"error message detected in log:\n{full_log}")
def test_pantsd_run(self): extra_config = { 'GLOBAL': { # Muddies the logs with warnings: once all of the warnings in the repository # are fixed, this can be removed. 'glob_expansion_failure': 'ignore', } } with self.pantsd_successful_run_context( 'debug', extra_config=extra_config ) as (pantsd_run, checker, workdir, _): pantsd_run(['list', '3rdparty:']) checker.assert_started() pantsd_run(['list', ':']) checker.assert_running() pantsd_run(['list', '::']) checker.assert_running() # And again using the cached BuildGraph. pantsd_run(['list', '::']) checker.assert_running() # Assert there were no warnings or errors thrown in the pantsd log. full_log = '\n'.join(read_pantsd_log(workdir)) for line in read_pantsd_log(workdir): # Ignore deprecation warning emissions. if 'DeprecationWarning' in line: continue # Check if the line begins with W or E to check if it is a warning or error line. self.assertNotRegex(line, r'^[WE].*', f'error message detected in log:\n{full_log}')
def pantsd_test_context( self, *, log_level: str = "info", extra_config: Optional[Dict[str, Any]] = None ) -> Iterator[Tuple[str, Dict[str, Any], PantsDaemonMonitor]]: with temporary_dir(root_dir=os.getcwd()) as workdir_base: pid_dir = os.path.join(workdir_base, ".pids") workdir = os.path.join(workdir_base, ".workdir.pants.d") print(f"\npantsd log is {workdir}/pantsd/pantsd.log") pantsd_config = { "GLOBAL": { "pantsd": True, "level": log_level, "pants_subprocessdir": pid_dir, } } if extra_config: recursively_update(pantsd_config, extra_config) print(f">>> config: \n{pantsd_config}\n") checker = PantsDaemonMonitor(pid_dir) kill_daemon(pid_dir) try: yield (workdir, pantsd_config, checker) kill_daemon(pid_dir) checker.assert_stopped() finally: banner("BEGIN pantsd.log") for line in read_pantsd_log(workdir): print(line) banner("END pantsd.log")
def test_pantsd_stacktrace_dump(self): with self.pantsd_successful_run_context() as ctx: ctx.runner(["-ldebug", "help"]) ctx.checker.assert_started() os.kill(ctx.checker.pid, signal.SIGUSR2) # Wait for log flush. time.sleep(2) self.assertIn("Current thread 0x", "\n".join(read_pantsd_log(ctx.workdir)))
def test_pantsd_stacktrace_dump(self): with self.pantsd_successful_run_context() as (pantsd_run, checker, workdir, _): pantsd_run(['-ldebug', 'help']) checker.assert_started() os.kill(checker.pid, signal.SIGUSR2) # Wait for log flush. time.sleep(2) self.assertIn('Current thread 0x', '\n'.join(read_pantsd_log(workdir)))
def test_sigint_kills_request_waiting_for_lock(self): """ Test that, when a pailgun request is blocked waiting for another one to end, sending SIGINT to the blocked run will kill it. Regression test for issue: #7920 """ config = {'GLOBAL': { 'pantsd_timeout_when_multiple_invocations': -1, 'level': 'debug' }} with self.pantsd_test_context(extra_config=config) as (workdir, config, checker): # Run a repl, so that any other run waiting to acquire the daemon lock waits forever. first_run_handle = self.run_pants_with_workdir_without_waiting( command=['repl', 'examples/src/python/example/hello::'], workdir=workdir, config=config ) checker.assert_started() checker.assert_running() blocking_run_handle = self.run_pants_with_workdir_without_waiting( command=['goals'], workdir=workdir, config=config ) # Block until the second request is waiting for the lock. blocked = True while blocked: log = '\n'.join(read_pantsd_log(workdir)) if "didn't aquire the lock on the first try, polling." in log: blocked = False # NB: This sleep is totally deterministic, it's just so that we don't spend too many cycles # busy waiting. time.sleep(0.1) # Sends SIGINT to the run that is waiting. blocking_run_client_pid = blocking_run_handle.process.pid os.kill(blocking_run_client_pid, signal.SIGINT) blocking_run_handle.join() # Check that pantsd is still serving the other request. checker.assert_running() # Send exit() to the repl, and exit it. result = first_run_handle.join(stdin_data='exit()') self.assert_success(result) checker.assert_running()
def pantsd_test_context( self, *, log_level: str = "info", extra_config: Optional[Dict[str, Any]] = None ) -> Iterator[Tuple[str, Dict[str, Any], PantsDaemonMonitor]]: with no_lingering_process_by_command( "pantsd") as runner_process_context: with self.temporary_workdir() as workdir_base: pid_dir = os.path.join(workdir_base, ".pids") workdir = os.path.join(workdir_base, ".workdir.pants.d") print(f"\npantsd log is {workdir}/pantsd/pantsd.log") pantsd_config = { "GLOBAL": { "enable_pantsd": True, "shutdown_pantsd_after_run": False, # The absolute paths in CI can exceed the UNIX socket path limitation # (>104-108 characters), so we override that here with a shorter path. "watchman_socket_path": f"/tmp/watchman.{os.getpid()}.sock", "level": log_level, "pants_subprocessdir": pid_dir, } } if extra_config: recursively_update(pantsd_config, extra_config) print(f">>> config: \n{pantsd_config}\n") checker = PantsDaemonMonitor(runner_process_context, pid_dir) self.assert_runner(workdir, pantsd_config, ["kill-pantsd"]) try: yield workdir, pantsd_config, checker self.assert_runner( workdir, pantsd_config, ["kill-pantsd"], ) checker.assert_stopped() finally: banner("BEGIN pantsd.log") for line in read_pantsd_log(workdir): print(line) banner("END pantsd.log")
def test_pantsd_file_logging(self): with self.pantsd_successful_run_context("debug") as ctx: daemon_run = ctx.runner(["list", "3rdparty::"]) ctx.checker.assert_started() self.assert_run_contains_log( "connecting to pantsd on port", "DEBUG", "pants.bin.remote_pants_runner", daemon_run, ) pantsd_log = "\n".join(read_pantsd_log(ctx.workdir)) self.assert_contains_log( "logging initialized", "DEBUG", "pants.pantsd.pants_daemon", pantsd_log, )
def test_pantsd_file_logging(self): with self.pantsd_successful_run_context('debug') as (pantsd_run, checker, workdir, _): daemon_run = pantsd_run(["list", "3rdparty::"]) checker.assert_started() self.assert_run_contains_log( "connecting to pantsd on port", "DEBUG", "pants.bin.remote_pants_runner", daemon_run, ) pantsd_log = '\n'.join(read_pantsd_log(workdir)) self.assert_contains_log( "logging initialized", "DEBUG", "pants.pantsd.pants_daemon", pantsd_log, )
def pantsd_test_context(self, log_level='info', extra_config=None): with no_lingering_process_by_command( 'pantsd') as runner_process_context: with self.temporary_workdir() as workdir_base: pid_dir = os.path.join(workdir_base, '.pids') workdir = os.path.join(workdir_base, '.workdir.pants.d') print(f'\npantsd log is {workdir}/pantsd/pantsd.log') pantsd_config = { 'GLOBAL': { 'enable_pantsd': True, 'shutdown_pantsd_after_run': False, # The absolute paths in CI can exceed the UNIX socket path limitation # (>104-108 characters), so we override that here with a shorter path. 'watchman_socket_path': f'/tmp/watchman.{os.getpid()}.sock', 'level': log_level, 'pants_subprocessdir': pid_dir, } } if extra_config: recursively_update(pantsd_config, extra_config) print(f'>>> config: \n{pantsd_config}\n') checker = PantsDaemonMonitor(runner_process_context, pid_dir) self.assert_runner(workdir, pantsd_config, ['kill-pantsd'], expected_runs=1) try: yield workdir, pantsd_config, checker self.assert_runner( workdir, pantsd_config, ['kill-pantsd'], expected_runs=1, ) checker.assert_stopped() finally: banner('BEGIN pantsd.log') for line in read_pantsd_log(workdir): print(line) banner('END pantsd.log')
def full_pantsd_log(): return "\n".join(read_pantsd_log(ctx.workdir))
def full_pantsd_log(): return '\n'.join(read_pantsd_log(workdir))