|
9 | 9 | import unittest |
10 | 10 | from collections import defaultdict |
11 | 11 |
|
12 | | -from test.support import captured_stderr |
13 | | - |
14 | 12 | try: |
15 | 13 | import _remote_debugging |
16 | 14 | from _remote_debugging import ( |
@@ -1033,142 +1031,6 @@ def test_writer_total_samples_after_close_returns_zero(self): |
1033 | 1031 | w.close() |
1034 | 1032 | self.assertEqual(w.total_samples, 0) |
1035 | 1033 |
|
1036 | | - def test_binary_collector_stops_gracefully_on_overflow(self): |
1037 | | - """OverflowError from the writer stops collection via the running |
1038 | | - protocol instead of propagating and corrupting the file. |
1039 | | - See gh-151292.""" |
1040 | | - with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: |
1041 | | - filename = f.name |
1042 | | - self.temp_files.append(filename) |
1043 | | - |
1044 | | - collector = BinaryCollector(filename, 1000, compression="none") |
1045 | | - self.assertTrue(collector.running) |
1046 | | - |
1047 | | - sample = [ |
1048 | | - make_interpreter(0, [make_thread(1, [make_frame("a.py", 1, "f")])]) |
1049 | | - ] |
1050 | | - |
1051 | | - # Collect real samples first, then hit the limit. |
1052 | | - for i in range(3): |
1053 | | - collector.collect(sample, timestamp_us=(i + 1) * 1000) |
1054 | | - self.assertTrue(collector.running) |
1055 | | - |
1056 | | - bad = [make_interpreter(2**32, sample[0].threads)] |
1057 | | - with captured_stderr() as stderr: |
1058 | | - collector.collect(bad, timestamp_us=4000) |
1059 | | - collector.collect(sample, timestamp_us=5000) |
1060 | | - |
1061 | | - self.assertFalse(collector.running) |
1062 | | - self.assertTrue(collector._writer.limit_reached) |
1063 | | - self.assertEqual(stderr.getvalue().count("Warning:"), 1) |
1064 | | - self.assertIn("interpreter_id", stderr.getvalue()) |
1065 | | - |
1066 | | - collector.export(None) |
1067 | | - |
1068 | | - self.assertEqual(collector.total_samples, 3) |
1069 | | - |
1070 | | - reader_collector = RawCollector() |
1071 | | - with BinaryReader(filename) as reader: |
1072 | | - self.assertEqual(reader.replay_samples(reader_collector), 3) |
1073 | | - |
1074 | | - def test_interpreter_id_overflow_rejected(self): |
1075 | | - """An interpreter_id wider than u32 raises OverflowError before any |
1076 | | - writer state is mutated: subsequent valid samples are still accepted |
1077 | | - and finalize produces a readable file.""" |
1078 | | - with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: |
1079 | | - filename = f.name |
1080 | | - self.temp_files.append(filename) |
1081 | | - |
1082 | | - good = [ |
1083 | | - make_interpreter(0, [make_thread(1, [make_frame("a.py", 1, "f")])]) |
1084 | | - ] |
1085 | | - bad = [ |
1086 | | - make_interpreter(2**32, [make_thread(1, [make_frame("a.py", 1, "f")])]) |
1087 | | - ] |
1088 | | - |
1089 | | - writer = _remote_debugging.BinaryWriter(filename, 1000, 0, compression=0) |
1090 | | - writer.write_sample(good, 1000) |
1091 | | - with self.assertRaises(OverflowError): |
1092 | | - writer.write_sample(bad, 2000) |
1093 | | - writer.write_sample(good, 3000) |
1094 | | - writer.finalize() |
1095 | | - self.assertEqual(writer.total_samples, 2) |
1096 | | - |
1097 | | - reader_collector = RawCollector() |
1098 | | - with BinaryReader(filename) as reader: |
1099 | | - self.assertEqual(reader.replay_samples(reader_collector), 2) |
1100 | | - |
1101 | | - def test_writer_finalizes_after_format_limit(self): |
1102 | | - for compression in (0, 1) if ZSTD_AVAILABLE else (0,): |
1103 | | - with self.subTest(compression=compression): |
1104 | | - with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: |
1105 | | - filename = f.name |
1106 | | - self.temp_files.append(filename) |
1107 | | - good = [make_interpreter(0, [ |
1108 | | - make_thread(1, [make_frame("a.py", 1, "f")]) |
1109 | | - ])] |
1110 | | - bad = [make_interpreter(2**32, good[0].threads)] |
1111 | | - writer = _remote_debugging.BinaryWriter( |
1112 | | - filename, 1000, 0, compression=compression |
1113 | | - ) |
1114 | | - with self.assertRaises(OverflowError): |
1115 | | - with writer: |
1116 | | - writer.write_sample(good, 1000) |
1117 | | - writer.write_sample(good, 2000) |
1118 | | - # The first interpreter is committed before the limit. |
1119 | | - writer.write_sample(good + bad, 3000) |
1120 | | - self.assertEqual(writer.total_samples, 3) |
1121 | | - with BinaryReader(filename) as reader: |
1122 | | - self.assertEqual(reader.replay_samples(RawCollector()), 3) |
1123 | | - |
1124 | | - def test_collector_does_not_swallow_unrelated_overflow(self): |
1125 | | - class BadStatus: |
1126 | | - def __index__(self): |
1127 | | - raise OverflowError("status conversion failed") |
1128 | | - |
1129 | | - with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: |
1130 | | - filename = f.name |
1131 | | - self.temp_files.append(filename) |
1132 | | - collector = BinaryCollector(filename, 1000, compression="none") |
1133 | | - self.addCleanup(collector._writer.close) |
1134 | | - sample = [make_interpreter(0, [make_thread(1, [], BadStatus())])] |
1135 | | - with captured_stderr() as stderr: |
1136 | | - with self.assertRaisesRegex(OverflowError, "status conversion failed"): |
1137 | | - collector.collect(sample, timestamp_us=1000) |
1138 | | - self.assertEqual(stderr.getvalue(), "") |
1139 | | - self.assertFalse(collector._writer.limit_reached) |
1140 | | - with self.assertRaisesRegex(ValueError, "broken"): |
1141 | | - collector.export() |
1142 | | - with self.assertRaisesRegex(ValueError, "broken"): |
1143 | | - collector._writer.write_sample([], 2000) |
1144 | | - # Closing a broken writer must not attempt to finalize it. |
1145 | | - collector.__exit__(None, None, None) |
1146 | | - |
1147 | | - def test_collector_finalizes_after_external_exception(self): |
1148 | | - with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: |
1149 | | - filename = f.name |
1150 | | - self.temp_files.append(filename) |
1151 | | - with self.assertRaisesRegex(RuntimeError, "sampling failed"): |
1152 | | - with BinaryCollector(filename, 1000, compression="none") as collector: |
1153 | | - collector.collect([make_interpreter(0, [make_thread(1, [])])]) |
1154 | | - raise RuntimeError("sampling failed") |
1155 | | - self.assertEqual(collector.total_samples, 1) |
1156 | | - with BinaryReader(filename) as reader: |
1157 | | - self.assertEqual(reader.replay_samples(RawCollector()), 1) |
1158 | | - |
1159 | | - @unittest.skipUnless(os.path.exists("/dev/full"), "requires /dev/full") |
1160 | | - def test_finalize_failure_breaks_writer(self): |
1161 | | - writer = _remote_debugging.BinaryWriter("/dev/full", 1000, 0) |
1162 | | - self.addCleanup(writer.close) |
1163 | | - writer.write_sample([make_interpreter(0, [make_thread(1, [])])], 1000) |
1164 | | - with self.assertRaises(OSError): |
1165 | | - writer.finalize() |
1166 | | - self.assertFalse(writer.limit_reached) |
1167 | | - with self.assertRaisesRegex(ValueError, "broken"): |
1168 | | - writer.finalize() |
1169 | | - with self.assertRaisesRegex(ValueError, "broken"): |
1170 | | - writer.write_sample([], 2000) |
1171 | | - |
1172 | 1034 |
|
1173 | 1035 | class TestBinaryFormatValidation(BinaryFormatTestBase): |
1174 | 1036 | """Tests for malformed binary files.""" |
|
0 commit comments