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. assertNotRegex(self, line, r'^[WE].*', 'error message detected in log:\n{}'.format(full_log))
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='info', extra_config=None, expected_runs=1): with no_lingering_process_by_command( 'pantsd-runner') 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('\npantsd log is {}/pantsd/pantsd.log'.format(workdir)) pantsd_config = { 'GLOBAL': { 'enable_pantsd': True, # 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': '/tmp/watchman.{}.sock'.format(os.getpid()), 'level': log_level, 'pants_subprocessdir': pid_dir, } } if extra_config: recursively_update(pantsd_config, extra_config) print('>>> config: \n{}\n'.format(pantsd_config)) checker = PantsDaemonMonitor(runner_process_context, pid_dir) # TODO(#6574): this should be 1, but when we kill pantsd with a signal it doesn't make sure # to close the run tracker -- we can easily address this by moving that cleanup into the # Exiter. self.assert_runner(workdir, pantsd_config, ['kill-pantsd'], expected_runs=1) try: yield workdir, pantsd_config, checker finally: banner('BEGIN pantsd.log') for line in read_pantsd_log(workdir): print(line) banner('END pantsd.log') self.assert_runner( workdir, pantsd_config, ['kill-pantsd'], # TODO(#6574): this should be 1, see above. expected_runs=1, ) checker.assert_stopped()
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('\npantsd log is {}/pantsd/pantsd.log'.format(workdir)) 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': '/tmp/watchman.{}.sock'.format(os.getpid()), 'level': log_level, 'pants_subprocessdir': pid_dir, } } if extra_config: recursively_update(pantsd_config, extra_config) print('>>> config: \n{}\n'.format(pantsd_config)) 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 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-runner') 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('\npantsd log is {}/pantsd/pantsd.log'.format(workdir)) 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': '/tmp/watchman.{}.sock'.format(os.getpid()), 'level': log_level, 'pants_subprocessdir': pid_dir, } } if extra_config: recursively_update(pantsd_config, extra_config) print('>>> config: \n{}\n'.format(pantsd_config)) 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(workdir))