Generate a core file for a process with a single thread and check that we can inspect and obtain all the information we need from the frame stack, including the native frames.
(
python: PythonVersion, method: StackMethod, blocking: bool, tmpdir: Path
)
| 48 | |
| 49 | @all_pystack_combinations(corefile=True) |
| 50 | def test_single_thread_stack( |
| 51 | python: PythonVersion, method: StackMethod, blocking: bool, tmpdir: Path |
| 52 | ) -> None: |
| 53 | """Generate a core file for a process with a single thread and check |
| 54 | that we can inspect and obtain all the information we need from the |
| 55 | frame stack, including the native frames. |
| 56 | """ |
| 57 | # GIVEN |
| 58 | |
| 59 | (major_version, minor_version), python_executable = python |
| 60 | |
| 61 | # WHEN |
| 62 | |
| 63 | with generate_core_file( |
| 64 | python_executable, TEST_SINGLE_THREAD_FILE, tmpdir |
| 65 | ) as core_file: |
| 66 | with xfail_on_expected_exceptions(method): |
| 67 | threads = list( |
| 68 | get_process_threads_for_core( |
| 69 | core_file, python_executable, method=method |
| 70 | ) |
| 71 | ) |
| 72 | |
| 73 | # THEN |
| 74 | |
| 75 | assert len(threads) == 1 |
| 76 | (thread,) = threads |
| 77 | |
| 78 | frames = list(thread.frames) |
| 79 | assert (len(frames)) == 4 |
| 80 | |
| 81 | filenames = {frame.code.filename for frame in frames} |
| 82 | assert filenames == {str(TEST_SINGLE_THREAD_FILE)} |
| 83 | |
| 84 | functions = [frame.code.scope for frame in frames] |
| 85 | assert functions == ["<module>", "first_func", "second_func", "third_func"] |
| 86 | |
| 87 | *line_numbers, last_line = [frame.code.location.lineno for frame in frames] |
| 88 | assert line_numbers == [20, 6, 10] |
| 89 | assert last_line in {16, 17} |
| 90 | |
| 91 | assert thread.native_frames |
| 92 | eval_frames = [ |
| 93 | frame |
| 94 | for frame in thread.native_frames |
| 95 | if frame_type(frame, thread.python_version) == NativeFrame.FrameType.EVAL |
| 96 | ] |
| 97 | if python_has_inlined_eval_frames(major_version, minor_version): # pragma: no cover |
| 98 | assert len(eval_frames) == 1 |
| 99 | else: # pragma: no cover |
| 100 | assert len(eval_frames) >= 4 |
| 101 | assert all("?" not in frame.symbol for frame in eval_frames) |
| 102 | assert all(frame.linenumber != 0 for frame in eval_frames if "?" not in frame.path) |
| 103 | |
| 104 | |
| 105 | @ALL_PYTHONS_THAT_SUPPORT_ELF_DATA |
nothing calls this directly
no test coverage detected