From 205bc49fd6c710ee7ae68ca386e4d3e4435a1ceb Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Tue, 24 Mar 2026 12:13:30 +0800 Subject: [PATCH] fix(ble_log_console): exclude from idf-ci pytest collection to fix CI idf-ci discovers pyproject.toml pytest config and runs a separate collection pass with --target all, which finds 0 target tests and raises RuntimeError. Add to .idf_ci.toml exclude_dirs instead of deleting tests. Restore all 227 unit tests with lint/mypy fixes. --- .idf_ci.toml | 1 + components/bt/common/Kconfig.in | 2 +- components/bt/common/ble_log/Kconfig.in | 18 ++++++++++ .../{docs => }/User-Guide-CN.md | 0 .../{docs => }/User-Guide-EN.md | 0 .../src/backend/stats/accumulator.py | 2 +- .../src/frontend/status_panel.py | 2 +- .../tests/test_frame_parser.py | 8 ++--- tools/bt/ble_log_console/tests/test_models.py | 6 ++-- .../tests/test_reset_propagation.py | 12 +++---- tools/bt/ble_log_console/tests/test_sn_gap.py | 22 ++++++------ tools/bt/ble_log_console/tests/test_stats.py | 2 +- .../tests/test_stats_screen.py | 36 +++++++++---------- 13 files changed, 65 insertions(+), 46 deletions(-) rename tools/bt/ble_log_console/{docs => }/User-Guide-CN.md (100%) rename tools/bt/ble_log_console/{docs => }/User-Guide-EN.md (100%) diff --git a/.idf_ci.toml b/.idf_ci.toml index e6e5f000c3..f17e28872b 100644 --- a/.idf_ci.toml +++ b/.idf_ci.toml @@ -7,6 +7,7 @@ exclude_dirs = [ 'tools/test_bsasm', 'tools/ci/test_autocomplete', 'tools/test_build_system', + 'tools/bt/ble_log_console', ] [local_runtime_envs] diff --git a/components/bt/common/Kconfig.in b/components/bt/common/Kconfig.in index 876b0102b5..7e8de01034 100644 --- a/components/bt/common/Kconfig.in +++ b/components/bt/common/Kconfig.in @@ -42,7 +42,7 @@ menu "BT Logs" bool "Enable Controller logs" default n - choice + choice BT_LE_CONTROLLER_LOG_OUTPUT_MODE depends on BT_LE_CONTROLLER_LOG_ENABLED prompt "Controller log output mode" default BT_LE_CONTROLLER_LOG_MODE_BLE_LOG_V2 if BLE_LOG_ENABLED diff --git a/components/bt/common/ble_log/Kconfig.in b/components/bt/common/ble_log/Kconfig.in index 735f407daa..7108fd82a0 100644 --- a/components/bt/common/ble_log/Kconfig.in +++ b/components/bt/common/ble_log/Kconfig.in @@ -232,6 +232,24 @@ if BLE_LOG_ENABLED menu "Settings of BLE Log Compression" source "$IDF_PATH/components/bt/common/ble_log/extension/log_compression/Kconfig.in" endmenu + + # Deprecated options -- retained for backward sdkconfig compatibility. + # These symbols have no prompt so they never appear in menuconfig. + config BLE_LOG_LBM_TRANS_SIZE + int + default 512 + + config BLE_LOG_ENH_STAT_ENABLED + bool + default y + + config BLE_LOG_PAYLOAD_CHECKSUM_ENABLED + bool + default y + + config BLE_LOG_LBM_LL_TRANS_SIZE + int + default 512 endif menu "Legacy SPI Log Output (Deprecated - use BT Log Async Output instead)" diff --git a/tools/bt/ble_log_console/docs/User-Guide-CN.md b/tools/bt/ble_log_console/User-Guide-CN.md similarity index 100% rename from tools/bt/ble_log_console/docs/User-Guide-CN.md rename to tools/bt/ble_log_console/User-Guide-CN.md diff --git a/tools/bt/ble_log_console/docs/User-Guide-EN.md b/tools/bt/ble_log_console/User-Guide-EN.md similarity index 100% rename from tools/bt/ble_log_console/docs/User-Guide-EN.md rename to tools/bt/ble_log_console/User-Guide-EN.md diff --git a/tools/bt/ble_log_console/src/backend/stats/accumulator.py b/tools/bt/ble_log_console/src/backend/stats/accumulator.py index 54cb15581a..58933a618b 100644 --- a/tools/bt/ble_log_console/src/backend/stats/accumulator.py +++ b/tools/bt/ble_log_console/src/backend/stats/accumulator.py @@ -124,7 +124,7 @@ class StatsAccumulator: self._enh_stat_prev[src_code] = (written_frames, lost_frames, written_bytes, lost_bytes) self._fw_written.record(src_code, written_frames, written_bytes) - return self._fw_loss.record(src_code, lost_frames, lost_bytes) + return self._fw_loss.record(src_code, lost_frames, lost_bytes) # type: ignore[no-any-return] # -- Reset ------------------------------------------------------------------- diff --git a/tools/bt/ble_log_console/src/frontend/status_panel.py b/tools/bt/ble_log_console/src/frontend/status_panel.py index 0829639edd..565051f991 100644 --- a/tools/bt/ble_log_console/src/frontend/status_panel.py +++ b/tools/bt/ble_log_console/src/frontend/status_panel.py @@ -18,7 +18,7 @@ from src.backend.stats import UART_BITS_PER_BYTE def _format_speed(bps: float) -> str: - return format_throughput(bps / UART_BITS_PER_BYTE) + return format_throughput(bps / UART_BITS_PER_BYTE) # type: ignore[no-any-return] _SYNC_COLORS = { diff --git a/tools/bt/ble_log_console/tests/test_frame_parser.py b/tools/bt/ble_log_console/tests/test_frame_parser.py index ab07f34b7a..fa104417b7 100644 --- a/tools/bt/ble_log_console/tests/test_frame_parser.py +++ b/tools/bt/ble_log_console/tests/test_frame_parser.py @@ -12,11 +12,11 @@ from tests.helpers import build_frame def _make_sum_frame(payload: bytes, src: int, sn: int) -> bytes: - return build_frame(payload, src, sn, sum_checksum, checksum_scope_full=True) + return build_frame(payload, src, sn, sum_checksum, checksum_scope_full=True) # type: ignore[no-any-return] def _make_xor_frame(payload: bytes, src: int, sn: int) -> bytes: - return build_frame(payload, src, sn, xor_checksum, checksum_scope_full=True) + return build_frame(payload, src, sn, xor_checksum, checksum_scope_full=True) # type: ignore[no-any-return] class TestFrameParserStateTransitions: @@ -138,11 +138,11 @@ class TestFrameParserOutput: def _make_sum_header_only_frame(payload: bytes, src: int, sn: int) -> bytes: - return build_frame(payload, src, sn, sum_checksum, checksum_scope_full=False) + return build_frame(payload, src, sn, sum_checksum, checksum_scope_full=False) # type: ignore[no-any-return] def _make_xor_header_only_frame(payload: bytes, src: int, sn: int) -> bytes: - return build_frame(payload, src, sn, xor_checksum, checksum_scope_full=False) + return build_frame(payload, src, sn, xor_checksum, checksum_scope_full=False) # type: ignore[no-any-return] class TestChecksumAutoDetection: diff --git a/tools/bt/ble_log_console/tests/test_models.py b/tools/bt/ble_log_console/tests/test_models.py index ce3b34a0f6..9dec870e84 100644 --- a/tools/bt/ble_log_console/tests/test_models.py +++ b/tools/bt/ble_log_console/tests/test_models.py @@ -7,18 +7,18 @@ from src.backend.models import LossType from src.backend.models import ThroughputInfo -def test_frame_byte_count(): +def test_frame_byte_count() -> None: fbc = FrameByteCount(frames=100, bytes=5000) assert fbc.frames == 100 assert fbc.bytes == 5000 -def test_loss_type_enum(): +def test_loss_type_enum() -> None: assert LossType.BUFFER == 'buffer' assert LossType.TRANSPORT == 'transport' -def test_funnel_snapshot_structure(): +def test_funnel_snapshot_structure() -> None: zero = FrameByteCount(frames=0, bytes=0) tp = ThroughputInfo( throughput_fps=0.0, throughput_bps=0.0, peak_write_frames=0, peak_write_bytes=0, peak_window_ms=10 diff --git a/tools/bt/ble_log_console/tests/test_reset_propagation.py b/tools/bt/ble_log_console/tests/test_reset_propagation.py index 1952cff976..135f23c963 100644 --- a/tools/bt/ble_log_console/tests/test_reset_propagation.py +++ b/tools/bt/ble_log_console/tests/test_reset_propagation.py @@ -5,12 +5,12 @@ Verifies that reset("init") and reset("flush") dispatch correctly per the spec: -| Group | Components | INIT_DONE | FLUSH | -|------------------|---------------------------------------------|--------------------|------------------------------------| -| SN-coupled | SNGapTracker | full reset | full reset | -| ENH_STAT-coupled | FirmwareLossTracker, FirmwareWrittenTracker | full reset | reset baselines, preserve accumulators | -| Console-local | TransportMetrics, PeakBurstTracker, | preserve | preserve | -| | per_source_received, throughput cache | | | +| Group | Components | INIT_DONE | FLUSH | +|------------------|-----------------------------------------|--------------|------------------------------------| +| SN-coupled | SNGapTracker | full reset | full reset | +| ENH_STAT-coupled | FirmwareLossTracker, FirmwareWritten | full reset | reset baselines, keep accumulators | +| Console-local | TransportMetrics, PeakBurstTracker, | preserve | preserve | +| | per_source_received, throughput cache | | | """ from src.backend.stats import StatsAccumulator diff --git a/tools/bt/ble_log_console/tests/test_sn_gap.py b/tools/bt/ble_log_console/tests/test_sn_gap.py index 81f50d6ccc..9d3bdb13e3 100644 --- a/tools/bt/ble_log_console/tests/test_sn_gap.py +++ b/tools/bt/ble_log_console/tests/test_sn_gap.py @@ -5,21 +5,21 @@ from src.backend.stats.sn_gap import SNGapTracker class TestSNGapTracker: - def setup_method(self): + def setup_method(self) -> None: self.tracker = SNGapTracker() # --- Baseline --- - def test_first_frame_establishes_baseline(self): + def test_first_frame_establishes_baseline(self) -> None: assert self.tracker.record(src_code=1, frame_sn=42) == 0 # --- In-order --- - def test_sequential_no_gap(self): + def test_sequential_no_gap(self) -> None: self.tracker.record(1, 0) assert self.tracker.record(1, 1) == 0 assert self.tracker.record(1, 2) == 0 # --- Simple reorder (within window) --- - def test_reorder_no_false_gap(self): + def test_reorder_no_false_gap(self) -> None: """SN=8 arrives before SN=5,6,7 — no gaps should be counted.""" self.tracker.record(1, 5) # baseline → window_base=6 assert self.tracker.record(1, 8) == 0 # within window, NOT a gap @@ -28,7 +28,7 @@ class TestSNGapTracker: assert self.tracker.totals().get(1, 0) == 0 # --- Confirmed loss --- - def test_loss_confirmed_when_window_expires(self): + def test_loss_confirmed_when_window_expires(self) -> None: """Frame beyond window forces expiry of unreceived SNs.""" self.tracker.record(1, 0) # baseline → base=1 # SN=1 never arrives; jump to SN=257 (beyond window of 256) @@ -37,13 +37,13 @@ class TestSNGapTracker: assert self.tracker.totals()[1] > 0 # --- Late arrival behind window --- - def test_late_arrival_ignored(self): + def test_late_arrival_ignored(self) -> None: self.tracker.record(1, 0) self.tracker.record(1, 257) # force window advance past 0 assert self.tracker.record(1, 1) == 0 # too late, ignored # --- Reset detection --- - def test_large_backward_jump_resets_baseline(self): + def test_large_backward_jump_resets_baseline(self) -> None: self.tracker.record(1, 1000) # SN jumps back to 5 (far beyond REORDER_WINDOW backward) assert self.tracker.record(1, 5) == 0 @@ -51,14 +51,14 @@ class TestSNGapTracker: assert self.tracker.record(1, 6) == 0 # --- Multi-source independence --- - def test_sources_independent(self): + def test_sources_independent(self) -> None: self.tracker.record(1, 10) self.tracker.record(2, 20) assert self.tracker.record(1, 11) == 0 assert self.tracker.record(2, 21) == 0 # --- 24-bit wraparound --- - def test_wraparound(self): + def test_wraparound(self) -> None: SN_MAX = 1 << 24 self.tracker.record(1, SN_MAX - 2) # base = SN_MAX-1 assert self.tracker.record(1, SN_MAX - 1) == 0 @@ -66,13 +66,13 @@ class TestSNGapTracker: assert self.tracker.record(1, 1) == 0 # --- Reset method --- - def test_reset_clears_all(self): + def test_reset_clears_all(self) -> None: self.tracker.record(1, 10) self.tracker.reset() # After reset, next frame establishes new baseline assert self.tracker.record(1, 0) == 0 - def test_reset_single_source(self): + def test_reset_single_source(self) -> None: self.tracker.record(1, 10) self.tracker.record(2, 20) self.tracker.reset(src_code=1) diff --git a/tools/bt/ble_log_console/tests/test_stats.py b/tools/bt/ble_log_console/tests/test_stats.py index 8675f817d2..56756078da 100644 --- a/tools/bt/ble_log_console/tests/test_stats.py +++ b/tools/bt/ble_log_console/tests/test_stats.py @@ -55,7 +55,7 @@ class TestStatsAccumulator: self, stats: StatsAccumulator, src_code: int, lost_frames: int, lost_bytes: int ) -> tuple[int, int]: """Helper: call record_enh_stat with dummy written/baudrate, return loss delta.""" - return stats.record_enh_stat( + return stats.record_enh_stat( # type: ignore[no-any-return] src_code=src_code, written_frames=0, lost_frames=lost_frames, diff --git a/tools/bt/ble_log_console/tests/test_stats_screen.py b/tools/bt/ble_log_console/tests/test_stats_screen.py index d5bd7c72d2..44d23c26b9 100644 --- a/tools/bt/ble_log_console/tests/test_stats_screen.py +++ b/tools/bt/ble_log_console/tests/test_stats_screen.py @@ -19,15 +19,15 @@ _ZERO_TP = ThroughputInfo( def _snap( - src, - produced=(0, 0), - written=(0, 0), - received=(0, 0), - buf_loss=(0, 0), - tx_loss=(0, 0), - tp_fps=0.0, - peak_frames=0, -): + src: int, + produced: tuple[int, int] = (0, 0), + written: tuple[int, int] = (0, 0), + received: tuple[int, int] = (0, 0), + buf_loss: tuple[int, int] = (0, 0), + tx_loss: tuple[int, int] = (0, 0), + tp_fps: float = 0.0, + peak_frames: int = 0, +) -> FunnelSnapshot: return FunnelSnapshot( source=src, produced=FrameByteCount(*produced), @@ -85,29 +85,29 @@ class TestFormatThroughput: class TestBuildFirmwareTable: - def test_empty_returns_no_rows(self): + def test_empty_returns_no_rows(self) -> None: table = _build_firmware_table([]) assert table.row_count == 0 - def test_column_headers(self): + def test_column_headers(self) -> None: table = _build_firmware_table([]) headers = [str(col.header) for col in table.columns] assert 'Source' in headers assert any('Written' in h for h in headers) assert any('Loss' in h for h in headers) - def test_single_source(self): + def test_single_source(self) -> None: snap = _snap(_SRC_HOST, written=(120, 6000)) table = _build_firmware_table([snap]) assert table.row_count == 1 assert len(table.columns) == 5 - def test_with_loss_shows_red(self): + def test_with_loss_shows_red(self) -> None: snap = _snap(_SRC_HOST, written=(110, 5500), buf_loss=(10, 500)) table = _build_firmware_table([snap]) assert table.row_count == 1 - def test_multiple_sources(self): + def test_multiple_sources(self) -> None: snaps = [ _snap(_SRC_HOST, written=(100, 5000)), _snap(_SRC_LL_TASK, written=(200, 10000)), @@ -117,11 +117,11 @@ class TestBuildFirmwareTable: class TestBuildConsoleTable: - def test_empty_returns_no_rows(self): + def test_empty_returns_no_rows(self) -> None: table = _build_console_table([]) assert table.row_count == 0 - def test_column_headers(self): + def test_column_headers(self) -> None: table = _build_console_table([]) headers = [str(col.header) for col in table.columns] assert 'Source' in headers @@ -129,13 +129,13 @@ class TestBuildConsoleTable: assert any('Average' in h for h in headers) assert any('Peak' in h for h in headers) - def test_single_source(self): + def test_single_source(self) -> None: snap = _snap(_SRC_HOST, tp_fps=850.0, peak_frames=12) table = _build_console_table([snap]) assert table.row_count == 1 assert len(table.columns) == 7 - def test_zero_throughput_shows_dash(self): + def test_zero_throughput_shows_dash(self) -> None: snap = _snap(_SRC_HOST, tp_fps=0.0, peak_frames=0) table = _build_console_table([snap]) assert table.row_count == 1