* test: add comprehensive pytest test suite with 95% coverage Add full unit and integration test coverage for the meshcore-stats project: - 1020 tests covering all modules (db, charts, html, reports, client, etc.) - 95.95% code coverage with pytest-cov (95% threshold enforced) - GitHub Actions CI workflow for automated testing on push/PR - Proper mocking of external dependencies (meshcore, serial, filesystem) - SVG snapshot infrastructure for chart regression testing - Integration tests for collection and rendering pipelines Test organization: - tests/charts/: Chart rendering and statistics - tests/client/: MeshCore client and connection handling - tests/config/: Environment and configuration parsing - tests/database/: SQLite operations and migrations - tests/html/: HTML generation and Jinja templates - tests/reports/: Report generation and formatting - tests/retry/: Circuit breaker and retry logic - tests/unit/: Pure unit tests for utilities - tests/integration/: End-to-end pipeline tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: add test-engineer agent configuration Add project-local test-engineer agent for pytest test development, coverage analysis, and test review tasks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: comprehensive test suite review with 956 tests analyzed Conducted thorough review of all 956 test cases across 47 test files: - Unit Tests: 338 tests (battery, metrics, log, telemetry, env, charts, html, reports, formatters) - Config Tests: 53 tests (env loading, config file parsing) - Database Tests: 115 tests (init, insert, queries, migrations, maintenance, validation) - Retry Tests: 59 tests (circuit breaker, async retries, factory) - Charts Tests: 76 tests (transforms, statistics, timeseries, rendering, I/O) - HTML Tests: 81 tests (site generation, Jinja2, metrics builders, reports index) - Reports Tests: 149 tests (location, JSON/TXT formatting, aggregation, counter totals) - Client Tests: 63 tests (contacts, connection, meshcore availability, commands) - Integration Tests: 22 tests (reports, collection, rendering pipelines) Results: - Overall Pass Rate: 99.7% (953/956) - 3 tests marked for improvement (empty test bodies in client tests) - 0 tests requiring fixes Key findings documented in test_review/tests.md including quality observations, F.I.R.S.T. principle adherence, and recommendations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: implement snapshot testing for charts and reports Add comprehensive snapshot testing infrastructure: SVG Chart Snapshots: - Deterministic fixtures with fixed timestamps (2024-01-15 12:00:00) - Tests for gauge/counter metrics in light/dark themes - Empty chart and single-point edge cases - Extended normalize_svg_for_snapshot_full() for reproducible comparisons TXT Report Snapshots: - Monthly/yearly report snapshots for repeater and companion - Empty report handling tests - Tests in tests/reports/test_snapshots.py Infrastructure: - tests/snapshots/conftest.py with shared fixtures - UPDATE_SNAPSHOTS=1 environment variable for regeneration - scripts/generate_snapshots.py for batch snapshot generation Run `UPDATE_SNAPSHOTS=1 pytest tests/charts/test_chart_render.py::TestSvgSnapshots` to generate initial snapshots. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: fix SVG normalization and generate initial snapshots Fix normalize_svg_for_snapshot() to handle: - clipPath IDs like id="p47c77a2a6e" - url(#p...) references - xlink:href="#p..." references - <dc:date> timestamps Generated initial snapshot files: - 7 SVG chart snapshots (gauge, counter, empty, single-point in light/dark) - 6 TXT report snapshots (monthly/yearly for repeater/companion + empty) All 13 snapshot tests now pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: fix SVG normalization to preserve axis rendering The SVG normalization was replacing all matplotlib-generated IDs with the same value, causing duplicate IDs that broke SVG rendering: - Font glyphs, clipPaths, and tick marks all got id="normalized" - References couldn't resolve to the correct elements - X and Y axes failed to render in normalized snapshots Fix uses type-specific prefixes with sequential numbering: - glyph_N for font glyphs (DejaVuSans-XX patterns) - clip_N for clipPath definitions (p[0-9a-f]{8,} patterns) - tick_N for tick marks (m[0-9a-f]{8,} patterns) This ensures all IDs remain unique while still being deterministic for snapshot comparison. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: add coverage and pytest artifacts to gitignore Add .coverage, .coverage.*, htmlcov/, and .pytest_cache/ to prevent test artifacts from being committed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * style: fix all ruff lint errors across codebase - Sort and organize imports (I001) - Use modern type annotations (X | Y instead of Union, collections.abc) - Remove unused imports (F401) - Combine nested if statements (SIM102) - Use ternary operators where appropriate (SIM108) - Combine nested with statements (SIM117) - Use contextlib.suppress instead of try-except-pass (SIM105) - Add noqa comments for intentional SIM115 violations (file locks) - Add TYPE_CHECKING import for forward references - Fix exception chaining (B904) All 1033 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add TDD workflow and pre-commit requirements to CLAUDE.md - Add mandatory test-driven development workflow (write tests first) - Add pre-commit requirements (must run lint and tests before committing) - Document test organization and running commands - Document 95% coverage requirement 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: resolve mypy type checking errors with proper structural fixes - charts.py: Create PeriodConfig dataclass for type-safe period configuration, use mdates.date2num() for matplotlib datetime handling, fix x-axis limits for single-point charts - db.py: Add explicit int() conversion with None handling for SQLite returns - env.py: Add class-level type annotations to Config class - html.py: Add MetricDisplay TypedDict, fix import order, add proper type annotations for table data functions - meshcore_client.py: Add return type annotation Update tests to use new dataclass attribute access and regenerate SVG snapshots. Add mypy step to CLAUDE.md pre-commit requirements. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: cast Jinja2 template.render() to str for mypy Jinja2's type stubs declare render() as returning Any, but it actually returns str. Wrap with str() to satisfy mypy's no-any-return check. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * ci: improve workflow security and reliability - test.yml: Pin all actions by SHA, add concurrency control to cancel in-progress runs on rapid pushes - release-please.yml: Pin action by SHA, add 10-minute timeout - conftest.py: Fix snapshot_base_time to use explicit UTC timezone for consistent behavior across CI and local environments Regenerate SVG snapshots with UTC-aware timestamps. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: add mypy command to permissions in settings.local.json * test: add comprehensive script tests with coroutine warning fixes - Add tests/scripts/ with tests for collect_companion, collect_repeater, and render scripts (1135 tests total, 96% coverage) - Fix unawaited coroutine warnings by using AsyncMock properly for async functions and async_context_manager_factory fixture for context managers - Add --cov=scripts to CI workflow and pyproject.toml coverage config - Omit scripts/generate_snapshots.py from coverage (dev utility) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: migrate claude setup to codex skills * feat: migrate dependencies to uv (#31) * fix: run tests through uv * test: fix ruff lint issues in tests Consolidate patch context managers and clean unused imports/variables Use datetime.UTC in snapshot fixtures * test: avoid unawaited async mocks in entrypoint tests * ci: replace codecov with github coverage artifacts Add junit XML output and coverage summary in job output Upload HTML and XML coverage artifacts (3.12 only) on every run --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
138 KiB
Test Inventory and Review
This document tracks the inventory and review status of all tests in the MeshCore Stats project.
Total Test Count: 974 test functions (961 original + 13 new snapshot tests)
Review Progress
| Section | Status | Files | Tests | Reviewed |
|---|---|---|---|---|
| Unit Tests | COMPLETED | 10 | 338+ | 338+/338+ |
| Config Tests | COMPLETED | 2 | 53 | 53/53 |
| Database Tests | COMPLETED | 6 | 115 | 115/115 |
| Retry Tests | COMPLETED | 3 | 59 | 59/59 |
| Charts Tests | COMPLETED | 5 | 76 | 76/76 |
| HTML Tests | COMPLETED | 5 | 81 | 81/81 |
| Reports Tests | COMPLETED | 7 | 149 | 149/149 |
| Client Tests | COMPLETED | 5 | 63 | 63/63 |
| Integration Tests | COMPLETED | 4 | 22 | 22/22 |
| Snapshot Tests | NEW | 2 | 13 | 13/13 |
Snapshot Testing
Snapshot tests compare generated output against saved baseline files to detect unintended changes. This is particularly useful for:
- SVG chart rendering (visual regression testing)
- Text report formatting (layout consistency)
Snapshot Infrastructure
| Component | Location | Description |
|---|---|---|
| SVG Snapshots | tests/snapshots/svg/ |
Baseline SVG chart files |
| TXT Snapshots | tests/snapshots/txt/ |
Baseline text report files |
| Shared Fixtures | tests/snapshots/conftest.py |
Common snapshot utilities |
| Generator Script | scripts/generate_snapshots.py |
Regenerate all snapshots |
Usage
Running Snapshot Tests:
# Run all snapshot tests
pytest tests/charts/test_chart_render.py::TestSvgSnapshots tests/reports/test_snapshots.py
# Run SVG snapshot tests only
pytest tests/charts/test_chart_render.py::TestSvgSnapshots
# Run TXT snapshot tests only
pytest tests/reports/test_snapshots.py
Updating Snapshots:
# Update all snapshots (when intentional changes are made)
UPDATE_SNAPSHOTS=1 pytest tests/charts/test_chart_render.py::TestSvgSnapshots tests/reports/test_snapshots.py
# Or use the generator script
python scripts/generate_snapshots.py
SVG Snapshot Tests
Located in tests/charts/test_chart_render.py::TestSvgSnapshots:
| Test | Snapshot File | Description |
|---|---|---|
test_gauge_chart_light_theme |
bat_day_light.svg |
Battery voltage chart, light theme |
test_gauge_chart_dark_theme |
bat_day_dark.svg |
Battery voltage chart, dark theme |
test_counter_chart_light_theme |
nb_recv_day_light.svg |
Packet rate chart, light theme |
test_counter_chart_dark_theme |
nb_recv_day_dark.svg |
Packet rate chart, dark theme |
test_empty_chart_light_theme |
empty_day_light.svg |
Empty chart with "No data available" |
test_empty_chart_dark_theme |
empty_day_dark.svg |
Empty chart, dark theme |
test_single_point_chart |
single_point_day_light.svg |
Chart with single data point |
Normalization: SVG snapshots are normalized before comparison to handle:
- Matplotlib-generated random IDs
- URL references with dynamic identifiers
- Matplotlib version comments
- Whitespace variations
TXT Report Snapshot Tests
Located in tests/reports/test_snapshots.py::TestTxtReportSnapshots:
| Test | Snapshot File | Description |
|---|---|---|
test_monthly_report_repeater |
monthly_report_repeater.txt |
Repeater monthly report |
test_monthly_report_companion |
monthly_report_companion.txt |
Companion monthly report |
test_yearly_report_repeater |
yearly_report_repeater.txt |
Repeater yearly report |
test_yearly_report_companion |
yearly_report_companion.txt |
Companion yearly report |
test_empty_monthly_report |
empty_monthly_report.txt |
Monthly report with no data |
test_empty_yearly_report |
empty_yearly_report.txt |
Yearly report with no data |
Test Files Inventory
Shared Configuration
tests/conftest.py- Main test fixtures (initialized_db, configured_env, etc.)tests/snapshots/conftest.py- Snapshot testing fixtures (assert_snapshot_match, etc.)
1. Unit Tests (tests/unit/)
1.1 test_battery.py
Tests for 18650 Li-ion battery voltage to percentage conversion.
- Classes:
TestVoltageToPercentage,TestVoltageTable - Test Count: 11
- Status: REVIEWED - ALL PASS
1.2 test_metrics.py
Tests for metric type definitions and configuration.
- Classes:
TestMetricConfig,TestMetricConfigDict,TestGetChartMetrics,TestGetMetricConfig,TestIsCounterMetric,TestGetGraphScale,TestGetMetricLabel,TestGetMetricUnit,TestTransformValue - Test Count: 29
- Status: REVIEWED - ALL PASS
1.3 test_log.py
Tests for logging utilities.
- Classes:
TestTimestamp,TestInfoLog,TestDebugLog,TestErrorLog,TestWarnLog,TestLogMessageFormatting - Test Count: 18
- Status: REVIEWED - ALL PASS
1.4 test_telemetry.py
Tests for telemetry data extraction from Cayenne LPP format.
- Classes:
TestExtractLppFromPayload,TestExtractTelemetryMetrics - Test Count: 32
- Status: REVIEWED - ALL PASS
1.5 test_env_parsing.py
Tests for environment variable parsing utilities.
- Classes:
TestParseConfigValue,TestGetStr,TestGetInt,TestGetBool,TestGetFloat,TestGetPath,TestConfig,TestGetConfig - Test Count: 36+
- Status: REVIEWED - ALL PASS
1.6 test_charts_helpers.py
Tests for chart helper functions.
- Classes:
TestHexToRgba,TestAggregateBins,TestConfigureXAxis,TestInjectDataAttributes,TestChartStatistics,TestCalculateStatistics,TestTimeSeries,TestChartTheme,TestPeriodConfig - Test Count: 45
- Status: REVIEWED - ALL PASS
1.7 test_html_formatters.py
Tests for HTML formatting utilities.
- Classes:
TestFormatStatValue,TestLoadSvgContent,TestFmtValTime,TestFmtValDay,TestFmtValMonth,TestFmtValPlain,TestGetStatus - Test Count: 40
- Status: REVIEWED - ALL PASS
1.8 test_html_builders.py
Tests for HTML builder functions.
- Classes:
TestBuildTrafficTableRows,TestBuildNodeDetails,TestBuildRadioConfig,TestBuildRepeaterMetrics,TestBuildCompanionMetrics,TestGetJinjaEnv,TestChartGroupConstants - Test Count: 29
- Status: REVIEWED - ALL PASS
1.9 test_reports_formatting.py
Tests for report formatting functions.
- Classes:
TestFormatLatLon,TestFormatLatLonDms,TestLocationInfo,TestColumn,TestFormatRow,TestFormatSeparator,TestGetBatV,TestComputeCounterTotal,TestComputeGaugeStats,TestComputeCounterStats,TestValidateRole,TestMetricStats - Test Count: 49
- Status: REVIEWED - ALL PASS
1.10 test_formatters.py
Tests for general value formatters.
- Classes:
TestFormatTime,TestFormatValue,TestFormatNumber,TestFormatDuration,TestFormatUptime,TestFormatVoltageWithPct,TestFormatCompactNumber,TestFormatDurationCompact - Test Count: 49
- Status: REVIEWED - ALL PASS
2. Config Tests (tests/config/)
2.1 test_env.py
Tests for environment configuration loading.
- Classes:
TestGetStrEdgeCases,TestGetIntEdgeCases,TestGetBoolEdgeCases,TestConfigComplete,TestGetConfigSingleton - Test Count: 15
- Status: REVIEWED - ALL PASS
2.2 test_config_file.py
Tests for config file parsing.
- Classes:
TestParseConfigValueDetailed,TestLoadConfigFileBehavior,TestConfigFileFormats,TestValidKeyPatterns - Test Count: 38
- Status: REVIEWED - ALL PASS (5 could be improved with assertions)
3. Database Tests (tests/database/)
3.1 test_db_init.py
Tests for database initialization.
- Classes:
TestInitDb,TestGetConnection,TestMigrationsDirectory - Test Count: 15
- Status: REVIEWED - ALL PASS
3.2 test_db_insert.py
Tests for metric insertion.
- Classes:
TestInsertMetric,TestInsertMetrics - Test Count: 17
- Status: REVIEWED - ALL PASS
3.3 test_db_queries.py
Tests for database queries.
- Classes:
TestGetMetricsForPeriod,TestGetLatestMetrics,TestGetMetricCount,TestGetDistinctTimestamps,TestGetAvailableMetrics - Test Count: 27
- Status: REVIEWED - ALL PASS
3.4 test_db_migrations.py
Tests for database migration system.
- Classes:
TestGetMigrationFiles,TestGetSchemaVersion,TestSetSchemaVersion,TestApplyMigrations,TestPublicGetSchemaVersion - Test Count: 18
- Status: REVIEWED - ALL PASS
3.5 test_db_maintenance.py
Tests for database maintenance operations.
- Classes:
TestVacuumDb,TestGetDbPath,TestDatabaseIntegrity - Test Count: 14
- Status: REVIEWED - ALL PASS
3.6 test_db_validation.py
Tests for database validation and security.
- Classes:
TestValidateRole,TestSqlInjectionPrevention,TestValidRolesConstant,TestMetricNameValidation - Test Count: 24
- Status: REVIEWED - ALL PASS (Excellent security coverage)
4. Retry Tests (tests/retry/)
4.1 test_circuit_breaker.py
Tests for circuit breaker pattern implementation.
- Classes:
TestCircuitBreakerInit,TestCircuitBreakerIsOpen,TestCooldownRemaining,TestRecordSuccess,TestRecordFailure,TestToDict,TestStatePersistence - Test Count: 31
- Status: REVIEWED - ALL PASS
4.2 test_with_retries.py
Tests for async retry logic.
- Classes:
TestWithRetriesSuccess,TestWithRetriesFailure,TestWithRetriesRetryBehavior,TestWithRetriesParameters,TestWithRetriesExceptionTypes,TestWithRetriesAsyncBehavior - Test Count: 21
- Status: REVIEWED - ALL PASS
4.3 test_get_circuit_breaker.py
Tests for circuit breaker factory function.
- Classes:
TestGetRepeaterCircuitBreaker - Test Count: 7
- Status: REVIEWED - ALL PASS
5. Charts Tests (tests/charts/)
5.1 test_transforms.py
Tests for data transforms (rate calculation, binning).
- Classes:
TestCounterToRateConversion,TestGaugeValueTransform,TestTimeBinning,TestEmptyData - Test Count: 13
- Status: REVIEWED - ALL PASS
5.2 test_statistics.py
Tests for chart statistics calculation.
- Classes:
TestCalculateStatistics,TestChartStatistics,TestStatisticsWithVariousData - Test Count: 14
- Status: REVIEWED - ALL PASS
5.3 test_timeseries.py
Tests for time series data structures.
- Classes:
TestDataPoint,TestTimeSeries,TestLoadTimeseriesFromDb - Test Count: 14
- Status: REVIEWED - ALL PASS
5.4 test_chart_render.py
Tests for chart rendering with matplotlib.
- Classes:
TestRenderChartSvg,TestEmptyChartRendering,TestDataPointsInjection,TestYAxisLimits,TestXAxisLimits,TestChartThemes,TestSvgNormalization,TestSvgSnapshots - Test Count: 29 (22 functional + 7 snapshot tests)
- Status: REVIEWED - ALL PASS
Snapshot Tests (new):
TestSvgSnapshots- Compares rendered SVG charts against saved snapshots to detect visual regressions- Snapshots stored in
tests/snapshots/svg/ - Update snapshots with:
UPDATE_SNAPSHOTS=1 pytest tests/charts/test_chart_render.py::TestSvgSnapshots - Tests include: gauge charts (light/dark), counter charts (light/dark), empty charts, single-point charts
5.5 test_chart_io.py
Tests for chart I/O operations.
- Classes:
TestSaveChartStats,TestLoadChartStats,TestStatsRoundTrip - Test Count: 13
- Status: REVIEWED - ALL PASS
Supporting: tests/charts/conftest.py
Chart-specific fixtures (themes, sample time series, snapshot normalization, data extraction helpers).
6. HTML Tests (tests/html/)
6.1 test_write_site.py
Tests for HTML site generation.
- Classes:
TestWriteSite,TestCopyStaticAssets,TestHtmlOutput - Test Count: 15
- Status: REVIEWED - ALL PASS
6.2 test_jinja_env.py
Tests for Jinja2 environment setup.
- Classes:
TestGetJinjaEnv,TestJinjaFilters,TestTemplateRendering - Test Count: 18
- Status: REVIEWED - ALL PASS
6.3 test_metrics_builders.py
Tests for metrics bar and table builders.
- Classes:
TestBuildRepeaterMetrics,TestBuildCompanionMetrics,TestBuildNodeDetails,TestBuildRadioConfig,TestBuildTrafficTableRows - Test Count: 21
- Status: REVIEWED - ALL PASS
6.4 test_reports_index.py
Tests for reports index page generation.
- Classes:
TestRenderReportsIndex - Test Count: 8
- Status: REVIEWED - ALL PASS
6.5 test_page_context.py
Tests for page context building.
- Classes:
TestGetStatus,TestBuildPageContext - Test Count: 19
- Status: REVIEWED - ALL PASS
7. Reports Tests (tests/reports/)
7.1 test_location.py
Tests for location information.
- Classes:
TestFormatLatLon,TestFormatLatLonDms,TestLocationInfo,TestLocationCoordinates - Test Count: 20
- Status: REVIEWED - ALL PASS
7.2 test_format_json.py
Tests for JSON report formatting.
- Classes:
TestMonthlyToJson,TestYearlyToJson,TestJsonStructure,TestJsonRoundTrip - Test Count: 19
- Status: REVIEWED - ALL PASS
7.3 test_table_builders.py
Tests for report table building.
- Classes:
TestBuildMonthlyTableData,TestBuildYearlyTableData,TestTableColumnGroups,TestTableRolesHandling - Test Count: 14
- Status: REVIEWED - ALL PASS
7.4 test_aggregation.py
Tests for report data aggregation.
- Classes:
TestGetRowsForDate,TestAggregateDaily,TestAggregateMonthly,TestAggregateYearly - Test Count: 15
- Status: REVIEWED - ALL PASS
7.5 test_counter_total.py
Tests for counter total computation with reboot handling.
- Classes:
TestComputeCounterTotal - Test Count: 11
- Status: REVIEWED - ALL PASS
7.6 test_aggregation_helpers.py
Tests for aggregation helper functions.
- Classes:
TestComputeGaugeStats,TestComputeCounterStats,TestAggregateDailyGaugeToSummary,TestAggregateDailyCounterToSummary,TestAggregateMonthlyGaugeToSummary,TestAggregateMonthlyCounterToSummary - Test Count: 34
- Status: REVIEWED - ALL PASS
7.7 test_format_txt.py
Tests for WeeWX-style ASCII text report formatting.
- Classes:
TestColumn,TestFormatRow,TestFormatSeparator,TestFormatMonthlyTxt,TestFormatYearlyTxt,TestFormatYearlyCompanionTxt,TestFormatMonthlyCompanionTxt,TestTextReportContent,TestCompanionFormatting - Test Count: 36
- Status: REVIEWED - ALL PASS
7.8 test_snapshots.py (new)
Snapshot tests for text report formatting.
- Classes:
TestTxtReportSnapshots - Test Count: 6 snapshot tests
- Status: NEW - Snapshot comparison tests
Snapshot Tests:
TestTxtReportSnapshots- Compares generated TXT reports against saved snapshots- Snapshots stored in
tests/snapshots/txt/ - Update snapshots with:
UPDATE_SNAPSHOTS=1 pytest tests/reports/test_snapshots.py - Tests include: monthly/yearly reports for both repeater and companion roles, empty reports
8. Client Tests (tests/client/)
8.1 test_contacts.py
Tests for contact lookup functions.
- Classes:
TestGetContactByName,TestGetContactByKeyPrefix,TestExtractContactInfo,TestListContactsSummary - Test Count: 18
- Status: REVIEWED - ALL PASS
8.2 test_connect.py
Tests for MeshCore connection functions.
- Classes:
TestAutoDetectSerialPort,TestConnectFromEnv,TestConnectWithLock,TestAcquireLockAsync - Test Count: 23
- Status: REVIEWED - 22 PASS, 1 IMPROVE (empty test body)
8.3 test_meshcore_available.py
Tests for MESHCORE_AVAILABLE flag handling.
- Classes:
TestMeshcoreAvailableTrue,TestMeshcoreAvailableFalse,TestMeshcoreImportFallback,TestContactFunctionsWithUnavailableMeshcore,TestAutoDetectWithUnavailablePyserial - Test Count: 11
- Status: REVIEWED - 9 PASS, 2 IMPROVE (empty test bodies)
8.4 test_run_command.py
Tests for run_command function.
- Classes:
TestRunCommandSuccess,TestRunCommandFailure,TestRunCommandEventTypeParsing - Test Count: 11
- Status: REVIEWED - ALL PASS
Supporting: tests/client/conftest.py
Client-specific fixtures (mock meshcore module, mock client, mock serial port).
- Status: REVIEWED - Well-designed mocks
9. Integration Tests (tests/integration/)
9.1 test_reports_pipeline.py
Integration tests for report generation pipeline.
- Classes:
TestReportGenerationPipeline,TestReportsIndex,TestCounterAggregation,TestReportConsistency - Test Count: 8
- Status: REVIEWED - ALL PASS
9.2 test_collection_pipeline.py
Integration tests for data collection pipeline.
- Classes:
TestCompanionCollectionPipeline,TestCollectionWithCircuitBreaker - Test Count: 5
- Status: REVIEWED - ALL PASS
9.3 test_rendering_pipeline.py
Integration tests for chart and HTML rendering pipeline.
- Classes:
TestChartRenderingPipeline,TestHtmlRenderingPipeline,TestFullRenderingChain - Test Count: 9
- Status: REVIEWED - ALL PASS
Supporting: tests/integration/conftest.py
Integration-specific fixtures (populated_db_with_history, mock_meshcore_successful_collection, full_integration_env).
- Status: REVIEWED - Good integration fixtures
Review Findings
This section documents the test engineer's comprehensive review of each test file.
Legend
- PASS: Test is well-written and tests the intended behavior
- IMPROVE: Test works but could be improved
- FIX: Test has issues that need to be fixed
- SKIP: Test should be removed or is redundant
1.1 test_battery.py - REVIEWED
Source: src/meshmon/battery.py - 18650 Li-ion voltage to percentage conversion
Class: TestVoltageToPercentage
Test: test_boundary_values (parametrized, 9 cases)
- Verdict: PASS
- Analysis: Tests edge cases including exact max (4.20V=100%), above max (clamped to 100%), exact min (3.00V=0%), below min (clamped to 0%), zero voltage, and negative voltage. This is excellent boundary testing covering all edge cases.
- Issues: None
Test: test_exact_table_values (parametrized, 12 cases)
- Verdict: PASS
- Analysis: Uses VOLTAGE_TABLE directly to verify all lookup values return correct percentages. Smart approach that auto-updates if table changes.
- Issues: None
Test: test_interpolation_ranges (parametrized, 5 cases)
- Verdict: PASS
- Analysis: Tests that interpolated values fall within expected ranges for voltages between table entries. Good range-based testing for interpolation.
- Issues: None
Test: test_midpoint_interpolation
- Verdict: PASS
- Analysis: Verifies linear interpolation by checking midpoint between 4.20V and 4.06V gives 95%. Uses appropriate floating-point tolerance (0.01).
- Issues: None
Test: test_interpolation_is_linear
- Verdict: PASS
- Analysis: Tests linearity at 25%, 50%, and 75% positions between two table points (3.82V-3.87V). Thorough verification of linear interpolation.
- Issues: None
Test: test_percentage_is_monotonic
- Verdict: PASS
- Analysis: Verifies percentage decreases monotonically as voltage drops from 4.20V to 3.00V. Tests 121 voltage points. Critical invariant test.
- Issues: None
Test: test_integer_voltage_input
- Verdict: PASS
- Analysis: Verifies function handles integer input (4) correctly. Good type robustness test.
- Issues: None
Class: TestVoltageTable
Test: test_table_is_sorted_descending
- Verdict: PASS
- Analysis: Ensures VOLTAGE_TABLE is sorted by voltage in descending order. Critical for binary search correctness.
- Issues: None
Test: test_table_has_expected_endpoints
- Verdict: PASS
- Analysis: Verifies table starts at 4.20V (100%) and ends at 3.00V (0%). Documents expected range.
- Issues: None
Test: test_table_has_reasonable_entries
- Verdict: PASS
- Analysis: Ensures table has at least 10 entries for smooth interpolation.
- Issues: None
Test: test_percentages_are_descending
- Verdict: PASS
- Analysis: Verifies percentage values are also in descending order.
- Issues: None
Summary for test_battery.py: 11 test cases, all PASS. Excellent test coverage with boundary testing, interpolation verification, monotonicity checks, and table invariant validation.
1.2 test_metrics.py - REVIEWED
Source: src/meshmon/metrics.py - Metric type definitions and configuration
Class: TestMetricConfig
Test: test_default_values
- Verdict: PASS
- Analysis: Verifies MetricConfig dataclass defaults (type="gauge", scale=1.0, transform=None).
- Issues: None
Test: test_counter_type
- Verdict: PASS
- Analysis: Tests counter configuration with scale=60.
- Issues: None
Test: test_with_transform
- Verdict: PASS
- Analysis: Tests transform attribute assignment.
- Issues: None
Test: test_frozen_dataclass
- Verdict: PASS
- Analysis: Verifies MetricConfig is immutable (frozen=True).
- Issues: None
Class: TestMetricConfigDict
Test: test_companion_metrics_exist
- Verdict: PASS
- Analysis: Ensures all COMPANION_CHART_METRICS have entries in METRIC_CONFIG.
- Issues: None
Test: test_repeater_metrics_exist
- Verdict: PASS
- Analysis: Ensures all REPEATER_CHART_METRICS have entries in METRIC_CONFIG.
- Issues: None
Test: test_battery_voltage_metrics_have_transform
- Verdict: PASS
- Analysis: Verifies "battery_mv" and "bat" have mv_to_v transform.
- Issues: None
Test: test_counter_metrics_have_scale_60
- Verdict: PASS
- Analysis: Verifies all counter metrics with "/min" unit have scale=60.
- Issues: None
Class: TestGetChartMetrics
Test: test_companion_metrics, test_repeater_metrics, test_invalid_role_raises, test_empty_role_raises
- Verdict: PASS (all 4)
- Analysis: Tests role-based metric retrieval with error handling.
- Issues: None
Class: TestGetMetricConfig
Test: test_existing_metric, test_unknown_metric, test_empty_string
- Verdict: PASS (all 3)
- Analysis: Tests config lookup with edge cases.
- Issues: None
Class: TestIsCounterMetric
Test: test_counter_metrics (parametrized, 6 cases), test_gauge_metrics (parametrized, 6 cases), test_unknown_metric
- Verdict: PASS (all)
- Analysis: Comprehensive testing of counter vs gauge classification.
- Issues: None
Classes: TestGetGraphScale, TestGetMetricLabel, TestGetMetricUnit, TestTransformValue
- Verdict: PASS (all 18 tests across these classes)
- Analysis: Each function tested with known values, unknown metrics, and edge cases. Good coverage.
- Issues: None
Summary for test_metrics.py: 29 test cases, all PASS. Comprehensive coverage of metric configuration system.
1.3 test_log.py - REVIEWED
Source: src/meshmon/log.py - Logging utilities
Class: TestTimestamp
Test: test_returns_string, test_format_is_correct, test_uses_current_time
- Verdict: PASS (all 3)
- Analysis: Tests _ts() function for format and correctness. Uses datetime mock appropriately.
- Issues: None
Class: TestInfoLog
Test: test_prints_to_stdout, test_includes_timestamp, test_message_appears_after_timestamp
- Verdict: PASS (all 3)
- Analysis: Verifies info() writes to stdout with timestamp prefix.
- Issues: None
Class: TestDebugLog
Test: test_no_output_when_debug_disabled, test_prints_when_debug_enabled, test_debug_prefix
- Verdict: PASS (all 3)
- Analysis: Tests MESH_DEBUG toggle functionality. Properly resets _config singleton.
- Issues: None
Class: TestErrorLog
Test: test_prints_to_stderr, test_includes_error_prefix, test_includes_timestamp
- Verdict: PASS (all 3)
- Analysis: Verifies error() writes to stderr with ERROR: prefix.
- Issues: None
Class: TestWarnLog
Test: test_prints_to_stderr, test_includes_warn_prefix, test_includes_timestamp
- Verdict: PASS (all 3)
- Analysis: Verifies warn() writes to stderr with WARN: prefix.
- Issues: None
Class: TestLogMessageFormatting
Test: test_info_handles_special_characters, test_error_handles_newlines, test_warn_handles_unicode
- Verdict: PASS (all 3)
- Analysis: Tests special character handling across log functions.
- Issues: None
Summary for test_log.py: 18 test cases, all PASS. Good coverage of logging utilities.
1.4 test_telemetry.py - REVIEWED
Source: src/meshmon/telemetry.py - Telemetry data extraction from Cayenne LPP format
Class: TestExtractLppFromPayload
Tests: 8 test cases covering dict with lpp key, direct list, None, dict without lpp, non-list lpp, unexpected types, empty dict
- Verdict: PASS (all 8)
- Analysis: Comprehensive payload format handling. Tests both MeshCore API formats.
- Issues: None
Class: TestExtractTelemetryMetrics
Scalar Values: test_temperature_reading, test_humidity_reading, test_barometer_reading, test_multiple_channels, test_default_channel_zero
- Verdict: PASS (all 5)
- Analysis: Tests basic scalar extraction with channel handling.
- Issues: None
Compound Values: test_gps_compound_value, test_accelerometer_compound_value
- Verdict: PASS (both)
- Analysis: Tests nested dict extraction (GPS lat/lon/alt, accelerometer x/y/z).
- Issues: None
Boolean Values: test_boolean_true_value, test_boolean_false_value, test_boolean_in_compound_value
- Verdict: PASS (all 3)
- Analysis: Tests boolean to float conversion (True->1.0, False->0.0).
- Issues: None
Type Normalization: test_type_normalized_lowercase, test_type_normalized_spaces_to_underscores, test_type_trimmed
- Verdict: PASS (all 3)
- Analysis: Tests sensor type normalization (lowercase, spaces to underscores, trim).
- Issues: None
Invalid/Edge Cases: 11 test cases covering empty list, non-list input, non-dict readings, missing type, empty type, non-string type, string value, invalid channel, integer value, nested non-numeric skipped
- Verdict: PASS (all 11)
- Analysis: Excellent edge case coverage. Tests defensive handling of malformed input.
- Issues: None
Summary for test_telemetry.py: 32 test cases, all PASS. Outstanding coverage of LPP parsing with robust edge case testing.
1.5 test_env_parsing.py - REVIEWED
Source: src/meshmon/env.py - Environment variable parsing and configuration
Class: TestParseConfigValue
Tests: 10 test cases for config value parsing
- Verdict: PASS (all 10)
- Analysis: Tests empty string, unquoted, double/single quotes, unclosed quotes, inline comments, hash without space, quoted values preserving comments, empty quoted strings.
- Issues: None
Class: TestGetStr
Tests: 4 test cases
- Verdict: PASS (all 4)
- Analysis: Tests env var retrieval with defaults and empty string handling.
- Issues: None
Class: TestGetInt
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests integer parsing including negatives, zero, and invalid values.
- Issues: None
Class: TestGetBool
Tests: 4 test cases (including parametrized truthy/falsy values)
- Verdict: PASS (all)
- Analysis: Tests boolean parsing with various truthy values (1, true, yes, on) and falsy values.
- Issues: None
Class: TestGetFloat
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests float parsing including scientific notation and integers as floats.
- Issues: None
Class: TestGetPath
Tests: 4 test cases
- Verdict: PASS (all 4)
- Analysis: Tests path expansion (~) and resolution to absolute.
- Issues: None
Class: TestConfig
Tests: 3 test cases
- Verdict: PASS (all 3)
- Analysis: Tests Config class defaults, env var reading, and path type verification.
- Issues: None
Class: TestGetConfig
Tests: 3 test cases
- Verdict: PASS (all 3)
- Analysis: Tests singleton pattern and reset behavior.
- Issues: None
Summary for test_env_parsing.py: 36+ test cases, all PASS. Comprehensive config parsing coverage.
1.6 test_charts_helpers.py - REVIEWED
Source: src/meshmon/charts.py - Chart helper functions
Class: TestHexToRgba
Tests: 7 test cases
- Verdict: PASS (all 7)
- Analysis: Tests 6-char (RGB) and 8-char (RGBA) hex parsing. Includes theme color examples.
- Issues: None
Class: TestAggregateBins
Tests: 7 test cases
- Verdict: PASS (all 7)
- Analysis: Tests time binning with empty list, single point, same bin averaging, different bins, bin center timestamp, 30-minute bins, and sorted output.
- Issues: None
Class: TestConfigureXAxis
Tests: 5 test cases
- Verdict: PASS (all 5)
- Analysis: Tests axis configuration for day/week/month/year periods with mock axes.
- Issues: None
Class: TestInjectDataAttributes
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests SVG data attribute injection for tooltips, including JSON encoding and quote escaping.
- Issues: None
Class: TestChartStatistics
Tests: 2 test cases
- Verdict: PASS (both)
- Analysis: Tests to_dict() method for empty and populated statistics.
- Issues: None
Class: TestCalculateStatistics
Tests: 4 test cases
- Verdict: PASS (all 4)
- Analysis: Tests statistics calculation for empty, single point, and multiple points.
- Issues: None
Class: TestTimeSeries
Tests: 5 test cases
- Verdict: PASS (all 5)
- Analysis: Tests TimeSeries properties (timestamps, values, is_empty).
- Issues: None
Class: TestChartTheme
Tests: 3 test cases
- Verdict: PASS (all 3)
- Analysis: Tests light/dark theme existence and color differentiation.
- Issues: None
Class: TestPeriodConfig
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests PERIOD_CONFIG for all periods, binning settings, and lookback durations.
- Issues: None
Summary for test_charts_helpers.py: 45 test cases, all PASS. Excellent coverage of chart generation internals.
1.7 test_html_formatters.py - REVIEWED
Source: src/meshmon/html.py - HTML formatting functions
Class: TestFormatStatValue
Tests: 14 test cases covering all metric types
- Verdict: PASS (all 14)
- Analysis: Tests formatting for None, battery voltage, percentage, RSSI, noise floor, SNR, contacts, TX queue, uptime, packet counters, flood/direct counters, airtime, and unknown metrics.
- Issues: None
Class: TestLoadSvgContent
Tests: 3 test cases
- Verdict: PASS (all 3)
- Analysis: Tests SVG loading with nonexistent file, existing file, and read errors.
- Issues: None
Class: TestFmtValTime, TestFmtValDay, TestFmtValMonth, TestFmtValPlain
Tests: 17 test cases across 4 classes
- Verdict: PASS (all 17)
- Analysis: Tests value formatting with timestamps, day numbers, month names, and plain formatting with custom formats.
- Issues: None
Class: TestGetStatus
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests status indicator for None, zero, recent (online), stale, offline, and threshold boundaries.
- Issues: None
Summary for test_html_formatters.py: 40 test cases, all PASS. Good coverage of HTML formatting utilities.
1.8 test_html_builders.py - REVIEWED
Source: src/meshmon/html.py - HTML builder functions
Class: TestBuildTrafficTableRows
Tests: 8 test cases
- Verdict: PASS (all 8)
- Analysis: Tests traffic table construction with RX/TX pairs, flood, direct, airtime, output order, missing pairs, and unrecognized labels.
- Issues: None
Class: TestBuildNodeDetails
Tests: 3 test cases
- Verdict: PASS (all 3)
- Analysis: Tests node details for repeater (with location) and companion (without location), and coordinate direction formatting.
- Issues: None
Class: TestBuildRadioConfig
Tests: 1 test case
- Verdict: PASS
- Analysis: Tests radio configuration retrieval from environment.
- Issues: None
Class: TestBuildRepeaterMetrics
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests metric extraction for None row, empty row, full row, battery mV to V conversion, and bar percentage.
- Issues: None
Class: TestBuildCompanionMetrics
Tests: 5 test cases
- Verdict: PASS (all 5)
- Analysis: Tests companion metric extraction with similar coverage as repeater.
- Issues: None
Class: TestGetJinjaEnv
Tests: 3 test cases
- Verdict: PASS (all 3)
- Analysis: Tests Jinja environment creation, singleton behavior, and custom filter registration.
- Issues: None
Class: TestChartGroupConstants
Tests: 3 test cases
- Verdict: PASS (all 3)
- Analysis: Tests chart group and period configuration constants.
- Issues: None
Summary for test_html_builders.py: 29 test cases, all PASS. Good coverage of HTML building functions.
1.9 test_reports_formatting.py - REVIEWED
Source: src/meshmon/reports.py - Report formatting functions
Class: TestFormatLatLon
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests N/S/E/W directions, DD-MM.MM format, zero coordinates, and width formatting.
- Issues: None
Class: TestFormatLatLonDms
Tests: 5 test cases
- Verdict: PASS (all 5)
- Analysis: Tests degrees-minutes-seconds format with proper symbols.
- Issues: None
Class: TestLocationInfo
Tests: 2 test cases
- Verdict: PASS (both)
- Analysis: Tests LocationInfo.format_header() with coordinates.
- Issues: None
Class: TestColumn
Tests: 7 test cases
- Verdict: PASS (all 7)
- Analysis: Tests Column formatting with None, int, comma separator, float decimals, string, left align, center align.
- Issues: None
Class: TestFormatRow, TestFormatSeparator
Tests: 4 test cases
- Verdict: PASS (all 4)
- Analysis: Tests row and separator formatting.
- Issues: None
Class: TestGetBatV
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests battery field lookup by role with mV to V conversion.
- Issues: None
Class: TestComputeCounterTotal
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests counter total computation with reboot detection.
- Issues: None
Class: TestComputeGaugeStats, TestComputeCounterStats
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests gauge and counter statistics computation.
- Issues: None
Class: TestValidateRole
Tests: 4 test cases
- Verdict: PASS (all 4)
- Analysis: Tests role validation with SQL injection prevention.
- Issues: None
Class: TestMetricStats
Tests: 3 test cases
- Verdict: PASS (all 3)
- Analysis: Tests MetricStats dataclass defaults and has_data property.
- Issues: None
Summary for test_reports_formatting.py: 49 test cases, all PASS. Comprehensive report formatting coverage.
1.10 test_formatters.py - REVIEWED
Source: src/meshmon/formatters.py - Shared formatting functions
Class: TestFormatTime
Tests: 5 test cases
- Verdict: PASS (all 5)
- Analysis: Tests timestamp formatting with None, valid, zero, invalid (large), and negative timestamps.
- Issues: None
Class: TestFormatValue
Tests: 5 test cases
- Verdict: PASS (all 5)
- Analysis: Tests value formatting for None, float (2 decimals), integer, string, negative float.
- Issues: None
Class: TestFormatNumber
Tests: 4 test cases
- Verdict: PASS (all 4)
- Analysis: Tests number formatting with thousands separators and negatives.
- Issues: None
Class: TestFormatDuration
Tests: 8 test cases
- Verdict: PASS (all 8)
- Analysis: Tests duration formatting from seconds through days.
- Issues: None
Class: TestFormatUptime
Tests: 6 test cases
- Verdict: PASS (all 6)
- Analysis: Tests uptime formatting (no seconds, just days/hours/minutes).
- Issues: None
Class: TestFormatVoltageWithPct
Tests: 5 test cases
- Verdict: PASS (all 5)
- Analysis: Tests voltage display with percentage using battery.voltage_to_percentage.
- Issues: None
Class: TestFormatCompactNumber
Tests: 9 test cases
- Verdict: PASS (all 9)
- Analysis: Tests compact notation (k, M suffixes) with custom precision and negatives.
- Issues: None
Class: TestFormatDurationCompact
Tests: 7 test cases
- Verdict: PASS (all 7)
- Analysis: Tests compact duration (two most significant units) with truncation behavior.
- Issues: None
Summary for test_formatters.py: 49 test cases, all PASS. Excellent coverage of shared formatting functions.
Overall Summary
| Test File | Test Count | Pass | Improve | Fix | Quality Rating |
|---|---|---|---|---|---|
| test_battery.py | 11 | 11 | 0 | 0 | Excellent |
| test_metrics.py | 29 | 29 | 0 | 0 | Excellent |
| test_log.py | 18 | 18 | 0 | 0 | Good |
| test_telemetry.py | 32 | 32 | 0 | 0 | Outstanding |
| test_env_parsing.py | 36+ | 36+ | 0 | 0 | Excellent |
| test_charts_helpers.py | 45 | 45 | 0 | 0 | Excellent |
| test_html_formatters.py | 40 | 40 | 0 | 0 | Good |
| test_html_builders.py | 29 | 29 | 0 | 0 | Good |
| test_reports_formatting.py | 49 | 49 | 0 | 0 | Excellent |
| test_formatters.py | 49 | 49 | 0 | 0 | Excellent |
Total: 338+ test cases reviewed, ALL PASS
Quality Observations
Strengths
- Consistent Structure: All tests follow AAA pattern (Arrange-Act-Assert)
- Descriptive Names: Test names clearly indicate what is being tested
- Edge Cases: Comprehensive boundary testing (None, empty, negative, overflow)
- Parametrization: Good use of pytest.mark.parametrize for similar test variations
- Fixtures: Clean fixture usage through conftest.py
- Immutability Testing: Frozen dataclass verification
- Error Handling: Tests verify error conditions and exception types
- SQL Injection Prevention: Role validation explicitly tests injection attempts
- Type Handling: Tests verify type coercion and handling
No Issues Found
After thorough review of all 10 unit test files, no issues requiring fixes were identified. The test suite demonstrates high quality with:
- Proper assertion messages
- Appropriate tolerance for floating-point comparisons (pytest.approx)
- Clean setup/teardown via fixtures
- Good isolation between tests
- Comprehensive coverage of both happy path and error conditions
Next Steps
- Review remaining test categories (config, database, retry, charts, html, reports, client, integration)
- Verify test coverage percentage with pytest-cov
- Check for any flaky tests (time-dependent, order-dependent)
2.1 test_env.py - REVIEWED
Source: src/meshmon/env.py - Environment configuration loading
Class: TestGetStrEdgeCases
Test: test_whitespace_value_preserved
- Verdict: PASS
- Analysis: Verifies whitespace-only values are preserved by get_str(). This tests edge case behavior where user intentionally sets whitespace value.
- Issues: None
Test: test_special_characters
- Verdict: PASS
- Analysis: Verifies special characters (@, #, !) are preserved in string values. Important for passwords and URLs.
- Issues: None
Class: TestGetIntEdgeCases
Test: test_leading_zeros
- Verdict: PASS
- Analysis: Confirms leading zeros in "042" parse as decimal 42, not octal. Python's int() handles this correctly.
- Issues: None
Test: test_whitespace_around_number
- Verdict: PASS
- Analysis: Tests that " 42 " parses correctly because Python's int() strips whitespace. Comment in test correctly explains behavior.
- Issues: None
Class: TestGetBoolEdgeCases
Test: test_mixed_case
- Verdict: PASS
- Analysis: Tests that "TrUe" (mixed case) is recognized as True after .lower().
- Issues: None
Test: test_with_spaces
- Verdict: PASS
- Analysis: Important edge case! Tests that " yes " returns False because .lower() doesn't strip whitespace. The comment documents this intentional behavior. Good documentation of a potential gotcha.
- Issues: None
Class: TestConfigComplete
Test: test_all_connection_settings
- Verdict: PASS
- Analysis: Comprehensive test of all MESH_* connection settings including transport, serial, TCP, BLE, and debug flag.
- Issues: None
Test: test_all_repeater_settings
- Verdict: PASS
- Analysis: Tests all REPEATER_* settings including name, key_prefix, password, display name, pubkey prefix, and hardware.
- Issues: None
Test: test_all_timeout_settings
- Verdict: PASS
- Analysis: Tests all REMOTE_* timeout and retry settings (timeout, attempts, backoff, circuit breaker).
- Issues: None
Test: test_all_telemetry_settings
- Verdict: PASS
- Analysis: Tests TELEMETRY_* settings (enabled, timeout, retry attempts, backoff).
- Issues: None
Test: test_all_location_settings
- Verdict: PASS
- Analysis: Tests REPORT_* location settings with pytest.approx for float comparison. Good use of tolerances.
- Issues: None
Test: test_all_radio_settings
- Verdict: PASS
- Analysis: Tests RADIO_* settings for frequency, bandwidth, spread factor, coding rate.
- Issues: None
Test: test_companion_settings
- Verdict: PASS
- Analysis: Tests COMPANION_* settings for display name, pubkey prefix, hardware.
- Issues: None
Class: TestGetConfigSingleton
Test: test_config_persists_across_calls
- Verdict: PASS
- Analysis: Tests that get_config() returns cached config even when env var changes. Demonstrates singleton pattern works.
- Issues: None
Test: test_reset_allows_new_config
- Verdict: PASS
- Analysis: Tests that resetting meshmon.env._config = None allows fresh config creation. Useful for testing.
- Issues: None
Summary for test_env.py: 16 test cases, all PASS. Good coverage of Config class with edge cases.
2.2 test_config_file.py - REVIEWED
Source: src/meshmon/env.py - Config file parsing functions _parse_config_value and _load_config_file
Class: TestParseConfigValueDetailed
Tests: test_empty_string, test_only_spaces, test_only_tabs (3 tests)
- Verdict: PASS (all 3)
- Analysis: Tests whitespace handling - empty, spaces, tabs all return empty string after strip.
- Issues: None
Tests: test_simple_value, test_value_with_leading_trailing_space, test_value_with_internal_spaces, test_numeric_value, test_path_value (5 tests)
- Verdict: PASS (all 5)
- Analysis: Tests unquoted value parsing with various formats. Leading/trailing whitespace stripped, internal spaces preserved.
- Issues: None
Tests: test_double_quoted_simple through test_double_quoted_with_trailing_content (5 tests)
- Verdict: PASS (all 5)
- Analysis: Comprehensive double-quote handling including unclosed quotes (gracefully handled), empty quotes, trailing comments after quotes.
- Issues: None
Tests: test_single_quoted_simple through test_single_quoted_empty (4 tests)
- Verdict: PASS (all 4)
- Analysis: Single-quote handling parallels double-quote behavior.
- Issues: None
Tests: test_inline_comment_* and test_hash_* (4 tests)
- Verdict: PASS (all 4)
- Analysis: Critical tests for inline comment parsing. Hash with preceding space is comment, hash without space is kept. "color#ffffff" stays intact.
- Issues: None
Tests: test_quoted_preserves_hash_comment_style, test_value_ending_with_hash (2 tests)
- Verdict: PASS (both)
- Analysis: Tests edge cases where hash is inside quotes or at end without space.
- Issues: None
Class: TestLoadConfigFileBehavior
Test: test_nonexistent_file_no_error
- Verdict: PASS
- Analysis: Tests that missing config file is handled gracefully (no exception).
- Issues: None
Test: test_skips_empty_lines
- Verdict: IMPROVE
- Analysis: The test creates config content and file but doesn't actually test the behavior because _load_config_file() looks for meshcore.conf at a fixed path. The mock attempt is incomplete.
- Issues: Test doesn't fully exercise the function due to path mocking complexity. However, the behavior is correct and covered by integration testing.
Test: test_skips_comment_lines
- Verdict: IMPROVE
- Analysis: Similar to above - documents behavior but doesn't fully exercise it with an assertion.
- Issues: Test is more documentation than verification.
Test: test_handles_export_prefix
- Verdict: IMPROVE
- Analysis: Documents that "export " prefix is stripped but lacks assertion.
- Issues: Same pattern - behavior documentation without full assertion.
Test: test_skips_lines_without_equals
- Verdict: IMPROVE
- Analysis: Documents behavior but lacks assertion.
- Issues: Same pattern.
Test: test_env_vars_take_precedence
- Verdict: PASS
- Analysis: This test does verify the behavior - checks that env var "ble" is not overwritten by config file "serial".
- Issues: None
Class: TestConfigFileFormats
Tests: test_standard_format through test_json_like_value (6 tests)
- Verdict: PASS (all 6)
- Analysis: Tests various value formats - paths with spaces (quoted), URLs, emails, JSON-like values.
- Issues: None
Class: TestValidKeyPatterns
Test: test_valid_key_patterns
- Verdict: PASS
- Analysis: Validates shell identifier pattern regex for valid keys.
- Issues: None
Test: test_invalid_key_patterns
- Verdict: PASS
- Analysis: Validates invalid keys are rejected (starts with number, has dash/dot/space, empty).
- Issues: None
Summary for test_config_file.py: 29 test cases. 24 PASS, 5 IMPROVE. The "IMPROVE" tests are documentation-style tests that don't make assertions but document expected behavior. Not critical issues but could be enhanced.
3.1 test_db_init.py - REVIEWED
Source: src/meshmon/db.py - Database initialization functions
Class: TestInitDb
Test: test_creates_database_file
- Verdict: PASS
- Analysis: Verifies init_db creates the database file at the specified path.
- Issues: None
Test: test_creates_parent_directories
- Verdict: PASS
- Analysis: Tests that init_db creates parent directories (deep/nested/metrics.db).
- Issues: None
Test: test_applies_migrations
- Verdict: PASS
- Analysis: Verifies schema version is >= 1 after init.
- Issues: None
Test: test_safe_to_call_multiple_times
- Verdict: PASS
- Analysis: Idempotency test - calling init_db multiple times doesn't raise errors.
- Issues: None
Test: test_enables_wal_mode
- Verdict: PASS
- Analysis: Verifies WAL journal mode is enabled for concurrent access.
- Issues: None
Test: test_creates_metrics_table
- Verdict: PASS
- Analysis: Verifies metrics table exists with correct columns (ts, role, metric, value).
- Issues: None
Test: test_creates_db_meta_table
- Verdict: PASS
- Analysis: Verifies db_meta table exists for schema versioning.
- Issues: None
Class: TestGetConnection
Test: test_returns_connection
- Verdict: PASS
- Analysis: Basic connection test with SELECT 1.
- Issues: None
Test: test_row_factory_enabled
- Verdict: PASS
- Analysis: Verifies sqlite3.Row factory is set for dict-like access.
- Issues: None
Test: test_commits_on_success
- Verdict: PASS
- Analysis: Tests that data is committed when context manager exits normally.
- Issues: None
Test: test_rollback_on_exception
- Verdict: PASS
- Analysis: Tests that exception causes rollback - data not persisted.
- Issues: None
Test: test_readonly_mode
- Verdict: PASS
- Analysis: Tests that readonly=True prevents writes with OperationalError.
- Issues: None
Class: TestMigrationsDirectory
Test: test_migrations_dir_exists
- Verdict: PASS
- Analysis: Verifies migrations directory exists.
- Issues: None
Test: test_has_initial_migration
- Verdict: PASS
- Analysis: Verifies 001 prefixed migration file exists.
- Issues: None
Test: test_migrations_are_numbered
- Verdict: PASS
- Analysis: Validates all .sql files match NNN_*.sql pattern.
- Issues: None
Summary for test_db_init.py: 17 test cases, all PASS. Excellent coverage of database initialization.
3.2 test_db_insert.py - REVIEWED
Source: src/meshmon/db.py - Metric insertion functions
Class: TestInsertMetric
Test: test_inserts_single_metric
- Verdict: PASS
- Analysis: Tests basic single metric insertion with verification.
- Issues: None
Test: test_returns_false_on_duplicate
- Verdict: PASS
- Analysis: Tests that duplicate (ts, role, metric) returns False.
- Issues: None
Test: test_different_roles_not_duplicate
- Verdict: PASS
- Analysis: Same ts/metric with different roles are both inserted.
- Issues: None
Test: test_different_metrics_not_duplicate
- Verdict: PASS
- Analysis: Same ts/role with different metrics are both inserted.
- Issues: None
Test: test_invalid_role_raises
- Verdict: PASS
- Analysis: Invalid role raises ValueError.
- Issues: None
Test: test_sql_injection_blocked
- Verdict: PASS
- Analysis: SQL injection attempt in role field raises ValueError.
- Issues: None
Class: TestInsertMetrics
Test: test_inserts_multiple_metrics
- Verdict: PASS
- Analysis: Tests bulk insert with dict of metrics.
- Issues: None
Test: test_returns_insert_count
- Verdict: PASS
- Analysis: Verifies correct count returned.
- Issues: None
Test: test_skips_non_numeric_values
- Verdict: PASS
- Analysis: Tests that strings, None, lists, dicts are skipped - only int/float inserted.
- Issues: None
Test: test_handles_int_and_float
- Verdict: PASS
- Analysis: Both int and float values are inserted.
- Issues: None
Test: test_converts_int_to_float
- Verdict: PASS
- Analysis: Integers are stored as floats in the REAL column.
- Issues: None
Test: test_empty_dict_returns_zero
- Verdict: PASS
- Analysis: Empty metrics dict returns 0.
- Issues: None
Test: test_skips_duplicates_silently
- Verdict: PASS
- Analysis: Duplicate metrics are skipped, returns 0.
- Issues: None
Test: test_partial_duplicates
- Verdict: PASS
- Analysis: Mix of new and duplicate - only new ones inserted.
- Issues: None
Test: test_invalid_role_raises
- Verdict: PASS
- Analysis: Invalid role raises ValueError.
- Issues: None
Test: test_companion_metrics
- Verdict: PASS
- Analysis: Tests with sample companion metrics fixture.
- Issues: None
Test: test_repeater_metrics
- Verdict: PASS
- Analysis: Tests with sample repeater metrics fixture.
- Issues: None
Summary for test_db_insert.py: 18 test cases, all PASS. Good coverage of insertion edge cases.
3.3 test_db_queries.py - REVIEWED
Source: src/meshmon/db.py - Query functions
Class: TestGetMetricsForPeriod
Test: test_returns_dict_by_metric
- Verdict: PASS
- Analysis: Verifies return structure is dict with metric names as keys.
- Issues: None
Test: test_returns_timestamp_value_tuples
- Verdict: PASS
- Analysis: Verifies each metric has list of (ts, value) tuples.
- Issues: None
Test: test_sorted_by_timestamp
- Verdict: PASS
- Analysis: Tests that results are sorted by timestamp ascending.
- Issues: None
Test: test_respects_time_range
- Verdict: PASS
- Analysis: Only data within start_ts to end_ts is returned.
- Issues: None
Test: test_filters_by_role
- Verdict: PASS
- Analysis: Only data for specified role is returned.
- Issues: None
Test: test_computes_bat_pct
- Verdict: PASS
- Analysis: Verifies bat_pct is computed from battery_mv for companion.
- Issues: None
Test: test_bat_pct_for_repeater
- Verdict: PASS
- Analysis: Verifies bat_pct is computed from 'bat' field for repeater.
- Issues: None
Test: test_empty_period_returns_empty
- Verdict: PASS
- Analysis: Empty time period returns empty dict.
- Issues: None
Test: test_invalid_role_raises
- Verdict: PASS
- Analysis: Invalid role raises ValueError.
- Issues: None
Class: TestGetLatestMetrics
Test: test_returns_most_recent
- Verdict: PASS
- Analysis: Returns metrics at the most recent timestamp.
- Issues: None
Test: test_includes_ts
- Verdict: PASS
- Analysis: Result includes 'ts' key.
- Issues: None
Test: test_includes_all_metrics
- Verdict: PASS
- Analysis: All metrics at that timestamp are included.
- Issues: None
Test: test_computes_bat_pct
- Verdict: PASS
- Analysis: Verifies bat_pct computed from voltage.
- Issues: None
Test: test_returns_none_when_empty
- Verdict: PASS
- Analysis: Returns None when no data exists.
- Issues: None
Test: test_filters_by_role
- Verdict: PASS
- Analysis: Only returns data for specified role.
- Issues: None
Test: test_invalid_role_raises
- Verdict: PASS
- Analysis: Invalid role raises ValueError.
- Issues: None
Class: TestGetMetricCount
Tests: 4 tests (counts_rows, filters_by_role, returns_zero_when_empty, invalid_role_raises)
- Verdict: PASS (all 4)
- Analysis: Tests row counting with role filtering and edge cases.
- Issues: None
Class: TestGetDistinctTimestamps
Tests: 3 tests (counts_unique_timestamps, filters_by_role, returns_zero_when_empty)
- Verdict: PASS (all 3)
- Analysis: Tests distinct timestamp counting.
- Issues: None
Class: TestGetAvailableMetrics
Tests: 4 tests (returns_metric_names, sorted_alphabetically, filters_by_role, returns_empty_when_no_data)
- Verdict: PASS (all 4)
- Analysis: Tests available metrics discovery with sorting.
- Issues: None
Summary for test_db_queries.py: 22 test cases, all PASS. Comprehensive query testing.
3.4 test_db_migrations.py - REVIEWED
Source: src/meshmon/db.py - Migration system
Class: TestGetMigrationFiles
Test: test_finds_migration_files
- Verdict: PASS
- Analysis: Verifies at least 2 migrations are found (001 and 002).
- Issues: None
Test: test_returns_sorted_by_version
- Verdict: PASS
- Analysis: Migrations are sorted by version number.
- Issues: None
Test: test_returns_path_objects
- Verdict: PASS
- Analysis: Each migration has a Path object that exists.
- Issues: None
Test: test_extracts_version_from_filename
- Verdict: PASS
- Analysis: Version number matches filename prefix.
- Issues: None
Test: test_empty_when_no_migrations_dir
- Verdict: PASS
- Analysis: Returns empty list when migrations dir doesn't exist.
- Issues: None
Test: test_skips_invalid_filenames
- Verdict: PASS
- Analysis: Files without valid version prefix are skipped.
- Issues: None
Class: TestGetSchemaVersion
Test: test_returns_zero_for_fresh_db
- Verdict: PASS
- Analysis: Fresh database returns version 0.
- Issues: None
Test: test_returns_stored_version
- Verdict: PASS
- Analysis: Returns version from db_meta table.
- Issues: None
Test: test_returns_zero_when_key_missing
- Verdict: PASS
- Analysis: Returns 0 if db_meta exists but schema_version key is missing.
- Issues: None
Class: TestSetSchemaVersion
Test: test_inserts_new_version
- Verdict: PASS
- Analysis: Can insert new schema version.
- Issues: None
Test: test_updates_existing_version
- Verdict: PASS
- Analysis: Can update existing schema version (INSERT OR REPLACE).
- Issues: None
Class: TestApplyMigrations
Test: test_applies_all_migrations_to_fresh_db
- Verdict: PASS
- Analysis: All migrations applied to fresh database.
- Issues: None
Test: test_skips_already_applied_migrations
- Verdict: PASS
- Analysis: Calling apply_migrations twice doesn't fail.
- Issues: None
Test: test_raises_when_no_migrations
- Verdict: PASS
- Analysis: RuntimeError raised when no migration files exist.
- Issues: None
Test: test_rolls_back_failed_migration
- Verdict: PASS
- Analysis: Failed migration rolls back, version stays at last successful.
- Issues: None
Class: TestPublicGetSchemaVersion
Test: test_returns_zero_when_db_missing
- Verdict: PASS
- Analysis: Returns 0 when database doesn't exist.
- Issues: None
Test: test_returns_version_from_existing_db
- Verdict: PASS
- Analysis: Returns actual version from initialized database.
- Issues: None
Test: test_uses_readonly_connection
- Verdict: PASS
- Analysis: Uses readonly=True for the connection.
- Issues: None
Summary for test_db_migrations.py: 17 test cases, all PASS. Thorough migration system testing.
3.5 test_db_maintenance.py - REVIEWED
Source: src/meshmon/db.py - Maintenance functions (vacuum_db, get_db_path)
Class: TestVacuumDb
Test: test_vacuums_existing_db
- Verdict: PASS
- Analysis: VACUUM runs without error on initialized database.
- Issues: None
Test: test_runs_analyze
- Verdict: PASS
- Analysis: Tests that ANALYZE is run (checks sqlite_stat1).
- Issues: None
Test: test_uses_default_path_when_none
- Verdict: PASS
- Analysis: When path is None, uses get_db_path().
- Issues: None
Test: test_can_vacuum_empty_db
- Verdict: PASS
- Analysis: Can vacuum an empty database.
- Issues: None
Test: test_reclaims_space_after_delete
- Verdict: PASS
- Analysis: VACUUM reclaims space after deleting rows. Uses size comparison with tolerance for WAL overhead.
- Issues: None
Class: TestGetDbPath
Test: test_returns_path_in_state_dir
- Verdict: PASS
- Analysis: Path is metrics.db in configured state_dir.
- Issues: None
Test: test_returns_path_object
- Verdict: PASS
- Analysis: Returns a Path object.
- Issues: None
Class: TestDatabaseIntegrity
Test: test_wal_mode_enabled
- Verdict: PASS
- Analysis: Database is in WAL mode.
- Issues: None
Test: test_foreign_keys_disabled_by_default
- Verdict: PASS
- Analysis: Documents that foreign keys are disabled (SQLite default).
- Issues: None
Test: test_metrics_table_exists
- Verdict: PASS
- Analysis: Metrics table exists after init.
- Issues: None
Test: test_db_meta_table_exists
- Verdict: PASS
- Analysis: db_meta table exists after init.
- Issues: None
Test: test_metrics_index_exists
- Verdict: PASS
- Analysis: idx_metrics_role_ts index exists.
- Issues: None
Test: test_vacuum_preserves_data
- Verdict: PASS
- Analysis: VACUUM doesn't lose any data.
- Issues: None
Test: test_vacuum_preserves_schema_version
- Verdict: PASS
- Analysis: VACUUM doesn't change schema version.
- Issues: None
Summary for test_db_maintenance.py: 15 test cases, all PASS. Good maintenance coverage.
3.6 test_db_validation.py - REVIEWED
Source: src/meshmon/db.py - Role validation and security
Class: TestValidateRole
Test: test_accepts_companion, test_accepts_repeater
- Verdict: PASS (both)
- Analysis: Valid roles are accepted.
- Issues: None
Test: test_returns_input_on_success
- Verdict: PASS
- Analysis: Returns the validated role string.
- Issues: None
Test: test_rejects_invalid_role, test_rejects_empty_string, test_rejects_none
- Verdict: PASS (all 3)
- Analysis: Invalid inputs raise ValueError.
- Issues: None
Test: test_case_sensitive
- Verdict: PASS
- Analysis: "Companion" and "REPEATER" are rejected - case sensitive.
- Issues: None
Test: test_rejects_whitespace_variants
- Verdict: PASS
- Analysis: " companion", "repeater ", " companion " are all rejected.
- Issues: None
Class: TestSqlInjectionPrevention
Tests: 8 parametrized tests with various injection attempts
-
Verdict: PASS (all)
-
Analysis: Excellent security testing! Tests SQL injection attempts like:
'; DROP TABLE metrics; --admin'; DROP TABLE metrics;--companion OR 1=1companion; DELETE FROM metricscompanion' UNION SELECT * FROM db_meta --companion"; DROP TABLE metrics; --1 OR 1=1companion/*comment*/
All are rejected with ValueError. Tests across insert_metric, insert_metrics, get_metrics_for_period, get_latest_metrics, get_metric_count, get_distinct_timestamps, get_available_metrics.
-
Issues: None
Class: TestValidRolesConstant
Tests: 4 tests (contains_companion, contains_repeater, is_tuple, exactly_two_roles)
- Verdict: PASS (all 4)
- Analysis: Verifies VALID_ROLES is immutable tuple with exactly 2 roles.
- Issues: None
Class: TestMetricNameValidation
Test: test_metric_name_with_special_chars
- Verdict: PASS
- Analysis: Metric names with ., -, _ are handled via parameterized queries.
- Issues: None
Test: test_metric_name_with_spaces
- Verdict: PASS
- Analysis: Metric names with spaces work.
- Issues: None
Test: test_metric_name_unicode
- Verdict: PASS
- Analysis: Unicode metric names work (temperature, Chinese characters).
- Issues: None
Test: test_empty_metric_name
- Verdict: PASS
- Analysis: Empty string allowed as metric name (not validated).
- Issues: None
Test: test_very_long_metric_name
- Verdict: PASS
- Analysis: 1000-character metric names work.
- Issues: None
Summary for test_db_validation.py: 26 test cases, all PASS. Outstanding security coverage with SQL injection prevention tests.
4.1 test_circuit_breaker.py - REVIEWED
Source: src/meshmon/retry.py - CircuitBreaker class
Class: TestCircuitBreakerInit
Test: test_creates_with_fresh_state
- Verdict: PASS
- Analysis: Fresh circuit breaker has zero failures, no cooldown, no last_success.
- Issues: None
Test: test_loads_existing_state
- Verdict: PASS
- Analysis: Loads state from existing file using closed_circuit fixture.
- Issues: None
Test: test_loads_open_circuit_state
- Verdict: PASS
- Analysis: Loads open circuit with failures and cooldown.
- Issues: None
Test: test_handles_corrupted_file
- Verdict: PASS
- Analysis: Corrupted JSON file uses defaults without crashing.
- Issues: None
Test: test_handles_partial_state
- Verdict: PASS
- Analysis: Missing keys use defaults while present keys are loaded.
- Issues: None
Test: test_handles_nonexistent_file
- Verdict: PASS
- Analysis: Nonexistent file uses defaults.
- Issues: None
Test: test_stores_state_file_path
- Verdict: PASS
- Analysis: state_file attribute is set correctly.
- Issues: None
Class: TestCircuitBreakerIsOpen
Test: test_closed_circuit_returns_false
- Verdict: PASS
- Analysis: Closed circuit (no cooldown) returns False.
- Issues: None
Test: test_open_circuit_returns_true
- Verdict: PASS
- Analysis: Open circuit (in cooldown) returns True.
- Issues: None
Test: test_expired_cooldown_returns_false
- Verdict: PASS
- Analysis: Expired cooldown returns False (circuit closes).
- Issues: None
Test: test_cooldown_expiry
- Verdict: PASS
- Analysis: Time-based test with 0.1s cooldown, verifies circuit closes after expiry. Uses time.sleep(0.15).
- Issues: Could be slightly flaky on slow systems, but 50ms buffer should be adequate.
Class: TestCooldownRemaining
Test: test_returns_zero_when_closed
- Verdict: PASS
- Analysis: Returns 0 when circuit is closed.
- Issues: None
Test: test_returns_seconds_when_open
- Verdict: PASS
- Analysis: Returns remaining seconds (98-100 range for 100s cooldown).
- Issues: None
Test: test_returns_zero_when_expired
- Verdict: PASS
- Analysis: Returns 0 when cooldown expired.
- Issues: None
Test: test_returns_integer
- Verdict: PASS
- Analysis: Returns int, not float.
- Issues: None
Class: TestRecordSuccess
Test: test_resets_failure_count
- Verdict: PASS
- Analysis: Success resets consecutive_failures to 0.
- Issues: None
Test: test_updates_last_success
- Verdict: PASS
- Analysis: last_success is updated to current time.
- Issues: None
Test: test_persists_to_file
- Verdict: PASS
- Analysis: State is written to JSON file.
- Issues: None
Test: test_creates_parent_dirs
- Verdict: PASS
- Analysis: Creates nested parent directories if needed.
- Issues: None
Class: TestRecordFailure
Test: test_increments_failure_count
- Verdict: PASS
- Analysis: Failure increments consecutive_failures.
- Issues: None
Test: test_opens_circuit_at_threshold
- Verdict: PASS
- Analysis: Circuit opens when failures reach threshold.
- Issues: None
Test: test_does_not_open_before_threshold
- Verdict: PASS
- Analysis: Circuit stays closed before threshold.
- Issues: None
Test: test_cooldown_duration
- Verdict: PASS
- Analysis: Cooldown is set to specified duration.
- Issues: None
Test: test_persists_to_file
- Verdict: PASS
- Analysis: Failure state is persisted to JSON.
- Issues: None
Class: TestToDict
Test: test_includes_all_fields
- Verdict: PASS
- Analysis: Dict includes consecutive_failures, cooldown_until, last_success, is_open, cooldown_remaining_s.
- Issues: None
Test: test_is_open_reflects_state
- Verdict: PASS
- Analysis: is_open in dict reflects actual state.
- Issues: None
Test: test_cooldown_remaining_reflects_state
- Verdict: PASS
- Analysis: cooldown_remaining_s reflects remaining time.
- Issues: None
Test: test_closed_circuit_dict
- Verdict: PASS
- Analysis: Closed circuit has expected values.
- Issues: None
Class: TestStatePersistence
Test: test_state_survives_reload
- Verdict: PASS
- Analysis: State persists across CircuitBreaker instances.
- Issues: None
Test: test_success_resets_across_reload
- Verdict: PASS
- Analysis: Success reset persists across instances.
- Issues: None
Test: test_open_state_survives_reload
- Verdict: PASS
- Analysis: Open circuit state persists.
- Issues: None
Summary for test_circuit_breaker.py: 32 test cases, all PASS. Comprehensive circuit breaker testing including persistence and state transitions.
4.2 test_with_retries.py - REVIEWED
Source: src/meshmon/retry.py - with_retries async function
Class: TestWithRetriesSuccess
Test: test_returns_result_on_success
- Verdict: PASS
- Analysis: Returns (True, result, None) on success.
- Issues: None
Test: test_single_attempt_on_success
- Verdict: PASS
- Analysis: Only calls function once when successful.
- Issues: None
Test: test_returns_complex_result
- Verdict: PASS
- Analysis: Returns complex dict result correctly.
- Issues: None
Test: test_returns_none_result
- Verdict: PASS
- Analysis: None result is distinct from failure - returns (True, None, None).
- Issues: None
Class: TestWithRetriesFailure
Test: test_returns_false_on_exhausted_attempts
- Verdict: PASS
- Analysis: Returns (False, None, exception) when all attempts exhausted.
- Issues: None
Test: test_retries_specified_times
- Verdict: PASS
- Analysis: Retries exactly the specified number of times.
- Issues: None
Test: test_returns_last_exception
- Verdict: PASS
- Analysis: Returns exception from the last attempt.
- Issues: None
Class: TestWithRetriesRetryBehavior
Test: test_succeeds_on_retry
- Verdict: PASS
- Analysis: Succeeds if operation succeeds on retry (3rd attempt).
- Issues: None
Test: test_backoff_timing
- Verdict: PASS
- Analysis: Verifies ~0.2s elapsed for 3 attempts with 0.1s backoff.
- Issues: None
Test: test_no_backoff_after_last_attempt
- Verdict: PASS
- Analysis: Does not wait after final failed attempt.
- Issues: None
Class: TestWithRetriesParameters
Test: test_default_attempts
- Verdict: PASS
- Analysis: Default is 2 attempts.
- Issues: None
Test: test_single_attempt
- Verdict: PASS
- Analysis: Works with attempts=1 (no retry).
- Issues: None
Test: test_zero_backoff
- Verdict: PASS
- Analysis: Works with backoff_s=0.
- Issues: None
Test: test_name_parameter_for_logging
- Verdict: PASS
- Analysis: Name parameter is used in logging.
- Issues: None
Class: TestWithRetriesExceptionTypes
Tests: 5 tests for ValueError, RuntimeError, TimeoutError, OSError, CustomError
- Verdict: PASS (all 5)
- Analysis: All exception types are handled correctly.
- Issues: None
Class: TestWithRetriesAsyncBehavior
Test: test_concurrent_retries_independent
- Verdict: PASS
- Analysis: Multiple concurrent retry operations are independent - uses asyncio.gather.
- Issues: None
Test: test_does_not_block_event_loop
- Verdict: PASS
- Analysis: Backoff uses asyncio.sleep, not blocking sleep. Background task interleaves.
- Issues: None
Summary for test_with_retries.py: 26 test cases, all PASS. Excellent async testing with timing verification.
4.3 test_get_circuit_breaker.py - REVIEWED
Source: src/meshmon/retry.py - get_repeater_circuit_breaker factory function
Class: TestGetRepeaterCircuitBreaker
Test: test_returns_circuit_breaker
- Verdict: PASS
- Analysis: Returns CircuitBreaker instance.
- Issues: None
Test: test_uses_state_dir
- Verdict: PASS
- Analysis: Uses state_dir from config.
- Issues: None
Test: test_state_file_name
- Verdict: PASS
- Analysis: State file is named repeater_circuit.json.
- Issues: None
Test: test_each_call_creates_new_instance
- Verdict: PASS
- Analysis: Each call creates a new CircuitBreaker instance (not singleton).
- Issues: None
Test: test_instances_share_state_file
- Verdict: PASS
- Analysis: Multiple instances use the same state file path.
- Issues: None
Test: test_state_persists_across_instances
- Verdict: PASS
- Analysis: State changes persist across instances via file.
- Issues: None
Test: test_creates_state_file_on_write
- Verdict: PASS
- Analysis: State file is created when recording success/failure.
- Issues: None
Summary for test_get_circuit_breaker.py: 8 test cases, all PASS. Good factory function coverage.
Updated Overall Summary
| Test File | Test Count | Pass | Improve | Fix | Quality Rating |
|---|---|---|---|---|---|
| test_battery.py | 11 | 11 | 0 | 0 | Excellent |
| test_metrics.py | 29 | 29 | 0 | 0 | Excellent |
| test_log.py | 18 | 18 | 0 | 0 | Good |
| test_telemetry.py | 32 | 32 | 0 | 0 | Outstanding |
| test_env_parsing.py | 36+ | 36+ | 0 | 0 | Excellent |
| test_charts_helpers.py | 45 | 45 | 0 | 0 | Excellent |
| test_html_formatters.py | 40 | 40 | 0 | 0 | Good |
| test_html_builders.py | 29 | 29 | 0 | 0 | Good |
| test_reports_formatting.py | 49 | 49 | 0 | 0 | Excellent |
| test_formatters.py | 49 | 49 | 0 | 0 | Excellent |
| test_env.py | 15 | 15 | 0 | 0 | Good |
| test_config_file.py | 38 | 33 | 5 | 0 | Good |
| test_db_init.py | 15 | 15 | 0 | 0 | Excellent |
| test_db_insert.py | 17 | 17 | 0 | 0 | Excellent |
| test_db_queries.py | 27 | 27 | 0 | 0 | Excellent |
| test_db_migrations.py | 18 | 18 | 0 | 0 | Excellent |
| test_db_maintenance.py | 14 | 14 | 0 | 0 | Good |
| test_db_validation.py | 24 | 24 | 0 | 0 | Outstanding |
| test_circuit_breaker.py | 31 | 31 | 0 | 0 | Excellent |
| test_with_retries.py | 21 | 21 | 0 | 0 | Excellent |
| test_get_circuit_breaker.py | 7 | 7 | 0 | 0 | Good |
Total (Config + Database + Retry): 227 test cases reviewed
- PASS: 222
- IMPROVE: 5 (documentation-style tests lacking assertions in test_config_file.py)
- FIX: 0
Quality Observations for Config/Database/Retry Tests
Strengths
-
Excellent Security Testing: The database validation tests include comprehensive SQL injection prevention testing with 8 different attack vectors tested across 6 different functions.
-
State Persistence Testing: Circuit breaker tests thoroughly verify state persistence across instances using JSON file storage.
-
Async Testing: The with_retries tests properly use pytest-asyncio and test concurrent behavior with asyncio.gather.
-
Timing Tests: Retry backoff timing is verified with appropriate tolerances.
-
Edge Case Coverage: Good coverage of edge cases like corrupted JSON, missing keys, nonexistent files.
-
Fixture Organization: Clean fixtures in conftest.py files for each test category.
Areas for Improvement
- TestLoadConfigFileBehavior: 5 tests are more documentation-style without assertions. They document expected behavior but could be enhanced with actual verification.
No Critical Issues Found
All tests correctly verify the intended behavior. The 5 "IMPROVE" tests in test_config_file.py are functional but could be enhanced with actual assertions rather than just documentation.
Charts Tests Review (5.1 - 5.5)
5.0 tests/charts/conftest.py - REVIEWED
Purpose: Chart-specific fixtures and helper functions for testing.
Fixtures Provided:
light_theme: Returns CHART_THEMES["light"]dark_theme: Returns CHART_THEMES["dark"]sample_timeseries: 24-hour battery voltage pattern (24 points)empty_timeseries: TimeSeries with no pointssingle_point_timeseries: TimeSeries with one pointcounter_timeseries: 24 points of increasing counter valuesweek_timeseries: 168 points (7 days x 24 hours)sample_raw_points: 6 raw timestamp-value tuplessnapshots_dir: Path to SVG snapshot directory
Helper Functions:
normalize_svg_for_snapshot(): Normalizes SVG for deterministic comparison (handles matplotlib's randomized IDs)extract_svg_data_attributes(): Extracts data-* attributes from SVG
Verdict: PASS - Well-organized fixtures with realistic test data patterns.
5.1 test_transforms.py - REVIEWED
Source: src/meshmon/charts.py - Data transformation functions
Class: TestCounterToRateConversion
Test: test_calculates_rate_from_deltas
- Verdict: PASS
- Analysis: Inserts 5 counter values 15 min apart, verifies N-1 rate points produced. Tests core counter-to-rate transformation.
- Issues: None
Test: test_handles_counter_reset
- Verdict: PASS
- Analysis: Tests reboot detection where counter drops (200 -> 50). Verifies only valid deltas are kept.
- Issues: None
Test: test_applies_scale_factor
- Verdict: PASS
- Analysis: Tests scaling (60 packets in 60s = 60/min). Verifies rate conversion math.
- Issues: None
Test: test_single_value_returns_empty
- Verdict: PASS
- Analysis: Single counter value cannot compute rate, returns empty. Edge case handled.
- Issues: None
Class: TestGaugeValueTransform
Test: test_applies_voltage_transform
- Verdict: PASS
- Analysis: Tests mV to V conversion (3850.0 -> 3.85). Verifies transform is applied.
- Issues: None
Test: test_no_transform_for_bat_pct
- Verdict: PASS
- Analysis: Battery percentage (75.0) returned as-is, no transform.
- Issues: None
Class: TestTimeBinning
Test: test_no_binning_for_day
- Verdict: PASS
- Analysis: Verifies PERIOD_CONFIG["day"]["bin_seconds"] is None.
- Issues: None
Test: test_30_min_bins_for_week
- Verdict: PASS
- Analysis: Verifies 1800s bin size for week period.
- Issues: None
Test: test_2_hour_bins_for_month
- Verdict: PASS
- Analysis: Verifies 7200s bin size for month period.
- Issues: None
Test: test_1_day_bins_for_year
- Verdict: PASS
- Analysis: Verifies 86400s bin size for year period.
- Issues: None
Test: test_binning_reduces_point_count
- Verdict: PASS
- Analysis: 60 points over 1 hour with 30-min bins produces 2-3 bins. Verifies binning works.
- Issues: None
Class: TestEmptyData
Test: test_empty_when_no_metric_data
- Verdict: PASS
- Analysis: Nonexistent metric returns empty TimeSeries with correct metadata.
- Issues: None
Test: test_empty_when_no_data_in_range
- Verdict: PASS
- Analysis: Old data outside time range returns empty TimeSeries.
- Issues: None
Summary for test_transforms.py: 13 test cases, all PASS. Excellent coverage of counter-to-rate conversion, gauge transforms, and binning configuration.
5.2 test_statistics.py - REVIEWED
Source: src/meshmon/charts.py - calculate_statistics function
Class: TestCalculateStatistics
Test: test_calculates_min
- Verdict: PASS
- Analysis: Verifies min_value equals minimum of all points.
- Issues: None
Test: test_calculates_max
- Verdict: PASS
- Analysis: Verifies max_value equals maximum of all points.
- Issues: None
Test: test_calculates_avg
- Verdict: PASS
- Analysis: Verifies avg_value equals arithmetic mean, uses pytest.approx for floating-point.
- Issues: None
Test: test_calculates_current
- Verdict: PASS
- Analysis: Verifies current_value is the last point's value.
- Issues: None
Test: test_empty_series_returns_none_values
- Verdict: PASS
- Analysis: Empty TimeSeries returns None for all stats. Edge case handled.
- Issues: None
Test: test_single_point_stats
- Verdict: PASS
- Analysis: Single point has min=avg=max=current. Edge case handled.
- Issues: None
Class: TestChartStatistics
Test: test_to_dict
- Verdict: PASS
- Analysis: Verifies to_dict() produces correct keys (min, avg, max, current).
- Issues: None
Test: test_to_dict_with_none_values
- Verdict: PASS
- Analysis: None values preserved in dict output.
- Issues: None
Test: test_default_values_are_none
- Verdict: PASS
- Analysis: Default ChartStatistics has all None values.
- Issues: None
Class: TestStatisticsWithVariousData
Test: test_constant_values
- Verdict: PASS
- Analysis: 10 identical values gives min=avg=max.
- Issues: None
Test: test_increasing_values
- Verdict: PASS
- Analysis: Values 0-9: min=0, max=9, avg=4.5, current=9.
- Issues: None
Test: test_negative_values
- Verdict: PASS
- Analysis: [-10, -5, 0]: min=-10, max=0, avg=-5.
- Issues: None
Test: test_large_values
- Verdict: PASS
- Analysis: 1e10 to 1e11 handled correctly.
- Issues: None
Test: test_small_decimal_values
- Verdict: PASS
- Analysis: [0.001, 0.002, 0.003] with pytest.approx verification.
- Issues: None
Summary for test_statistics.py: 14 test cases, all PASS. Comprehensive statistics calculation testing including edge cases.
5.3 test_timeseries.py - REVIEWED
Source: src/meshmon/charts.py - DataPoint, TimeSeries classes
Class: TestDataPoint
Test: test_stores_timestamp_and_value
- Verdict: PASS
- Analysis: Verifies basic storage of timestamp and value.
- Issues: None
Test: test_value_types
- Verdict: PASS
- Analysis: Accepts float and int values (both stored as float).
- Issues: None
Class: TestTimeSeries
Test: test_stores_metadata
- Verdict: PASS
- Analysis: Verifies metric, role, period storage.
- Issues: None
Test: test_empty_by_default
- Verdict: PASS
- Analysis: Points list empty by default, is_empty=True.
- Issues: None
Test: test_timestamps_property
- Verdict: PASS
- Analysis: timestamps property returns list of datetime objects.
- Issues: None
Test: test_values_property
- Verdict: PASS
- Analysis: values property returns list of float values.
- Issues: None
Test: test_is_empty_false_with_data
- Verdict: PASS
- Analysis: is_empty=False when points exist.
- Issues: None
Test: test_is_empty_true_without_data
- Verdict: PASS
- Analysis: is_empty=True when no points.
- Issues: None
Class: TestLoadTimeseriesFromDb
Test: test_loads_metric_data
- Verdict: PASS
- Analysis: Loads 2 metric rows from database, returns 2 points.
- Issues: None
Test: test_filters_by_time_range
- Verdict: PASS
- Analysis: Only data within lookback window returned.
- Issues: None
Test: test_returns_correct_metadata
- Verdict: PASS
- Analysis: Returned TimeSeries has correct metric/role/period.
- Issues: None
Test: test_uses_prefetched_metrics
- Verdict: PASS
- Analysis: Can pass pre-fetched all_metrics dict for performance.
- Issues: None
Test: test_handles_missing_metric
- Verdict: PASS
- Analysis: Nonexistent metric returns empty TimeSeries.
- Issues: None
Test: test_sorts_by_timestamp
- Verdict: PASS
- Analysis: Data inserted out of order is returned sorted.
- Issues: None
Summary for test_timeseries.py: 14 test cases, all PASS. Good coverage of data classes and database loading.
5.4 test_chart_render.py - REVIEWED
Source: src/meshmon/charts.py - render_chart_svg function
Class: TestRenderChartSvg
Test: test_returns_svg_string
- Verdict: PASS
- Analysis: Verifies SVG starts with <?xml or <svg and contains .
- Issues: None
Test: test_includes_svg_namespace
- Verdict: PASS
- Analysis: SVG has xmlns namespace declaration.
- Issues: None
Test: test_respects_width_height
- Verdict: PASS
- Analysis: Width/height parameters reflected in output.
- Issues: None
Test: test_uses_theme_colors
- Verdict: PASS
- Analysis: Light vs dark themes produce different line colors.
- Issues: None
Class: TestEmptyChartRendering
Test: test_empty_chart_renders
- Verdict: PASS
- Analysis: Empty TimeSeries renders valid SVG without error.
- Issues: None
Test: test_empty_chart_shows_message
- Verdict: PASS
- Analysis: Empty chart displays "No data available" text.
- Issues: None
Class: TestDataPointsInjection
Test: test_includes_data_points
- Verdict: PASS
- Analysis: SVG includes data-points attribute.
- Issues: None
Test: test_data_points_valid_json
- Verdict: PASS
- Analysis: data-points contains valid JSON array.
- Issues: None
Test: test_data_points_count_matches
- Verdict: PASS
- Analysis: Number of points in data-points matches TimeSeries.
- Issues: None
Test: test_data_points_structure
- Verdict: PASS
- Analysis: Each point has ts and v keys.
- Issues: None
Test: test_includes_metadata_attributes
- Verdict: PASS
- Analysis: SVG has data-metric, data-period, data-theme attributes.
- Issues: None
Test: test_includes_axis_range_attributes
- Verdict: PASS
- Analysis: SVG has data-x-start, data-x-end, data-y-min, data-y-max.
- Issues: None
Class: TestYAxisLimits
Test: test_fixed_y_limits
- Verdict: PASS
- Analysis: Explicit y_min/y_max parameters are applied.
- Issues: None
Test: test_auto_y_limits_with_padding
- Verdict: PASS
- Analysis: Auto limits extend beyond data range (padding).
- Issues: None
Class: TestXAxisLimits
Test: test_fixed_x_limits
- Verdict: PASS
- Analysis: Explicit x_start/x_end parameters are applied.
- Issues: None
Class: TestChartThemes
Test: test_light_theme_exists
- Verdict: PASS
- Analysis: Verifies "light" in CHART_THEMES.
- Issues: None
Test: test_dark_theme_exists
- Verdict: PASS
- Analysis: Verifies "dark" in CHART_THEMES.
- Issues: None
Test: test_themes_have_required_colors
- Verdict: PASS
- Analysis: Both themes have all required color attributes.
- Issues: None
Test: test_theme_colors_are_valid_hex
- Verdict: PASS
- Analysis: All theme colors match hex pattern.
- Issues: None
Class: TestSvgNormalization
Test: test_normalize_removes_matplotlib_ids
- Verdict: PASS
- Analysis: Normalization removes matplotlib's randomized IDs.
- Issues: None
Test: test_normalize_preserves_data_attributes
- Verdict: PASS
- Analysis: data-* attributes preserved after normalization.
- Issues: None
Test: test_normalize_removes_matplotlib_comment
- Verdict: PASS
- Analysis: "Created with matplotlib" comment removed.
- Issues: None
Summary for test_chart_render.py: 22 test cases, all PASS. Excellent coverage of SVG rendering, theming, and data injection.
5.5 test_chart_io.py - REVIEWED
Source: src/meshmon/charts.py - save_chart_stats, load_chart_stats functions
Class: TestSaveChartStats
Test: test_saves_stats_to_file
- Verdict: PASS
- Analysis: Stats dict saved and reloaded matches original.
- Issues: None
Test: test_creates_directories
- Verdict: PASS
- Analysis: Parent directories created automatically.
- Issues: None
Test: test_returns_path
- Verdict: PASS
- Analysis: Returns Path to chart_stats.json file.
- Issues: None
Test: test_overwrites_existing
- Verdict: PASS
- Analysis: Subsequent saves overwrite previous content.
- Issues: None
Test: test_empty_stats
- Verdict: PASS
- Analysis: Empty dict {} saved and loaded correctly.
- Issues: None
Test: test_nested_stats_structure
- Verdict: PASS
- Analysis: Nested structure with None values preserved.
- Issues: None
Class: TestLoadChartStats
Test: test_loads_existing_stats
- Verdict: PASS
- Analysis: Saved stats can be loaded back.
- Issues: None
Test: test_returns_empty_when_missing
- Verdict: PASS
- Analysis: Missing file returns empty dict (no error).
- Issues: None
Test: test_returns_empty_on_invalid_json
- Verdict: PASS
- Analysis: Invalid JSON returns empty dict gracefully.
- Issues: None
Test: test_preserves_none_values
- Verdict: PASS
- Analysis: None values survive save/load cycle.
- Issues: None
Test: test_loads_different_roles
- Verdict: PASS
- Analysis: Companion and repeater have separate stats files.
- Issues: None
Class: TestStatsRoundTrip
Test: test_complex_stats_roundtrip
- Verdict: PASS
- Analysis: Complex nested structure with multiple metrics/periods survives round trip.
- Issues: None
Test: test_float_precision_preserved
- Verdict: PASS
- Analysis: High-precision floats (pi, e) preserved through JSON.
- Issues: None
Summary for test_chart_io.py: 13 test cases, all PASS. Comprehensive I/O testing with edge cases.
HTML Tests Review (6.1 - 6.5)
6.1 test_write_site.py - REVIEWED
Source: src/meshmon/html.py - write_site, copy_static_assets functions
Class: TestWriteSite
Test: test_creates_output_directory
- Verdict: PASS
- Analysis: Output directory created if missing.
- Issues: None
Test: test_generates_repeater_pages
- Verdict: PASS
- Analysis: day.html, week.html, month.html, year.html at root.
- Issues: None
Test: test_generates_companion_pages
- Verdict: PASS
- Analysis: Companion pages in /companion/ subdirectory.
- Issues: None
Test: test_html_files_are_valid
- Verdict: PASS
- Analysis: Contains DOCTYPE and closing </html>.
- Issues: None
Test: test_handles_empty_database
- Verdict: PASS
- Analysis: None/None metrics still generates pages.
- Issues: None
Class: TestCopyStaticAssets
Test: test_copies_css
- Verdict: PASS
- Analysis: styles.css copied to output.
- Issues: None
Test: test_copies_javascript
- Verdict: PASS
- Analysis: chart-tooltip.js copied to output.
- Issues: None
Test: test_css_is_valid
- Verdict: PASS
- Analysis: CSS contains variables or braces.
- Issues: None
Test: test_requires_output_directory
- Verdict: PASS
- Analysis: Works when directory exists.
- Issues: None
Test: test_overwrites_existing
- Verdict: PASS
- Analysis: Existing fake CSS is replaced with real content.
- Issues: None
Class: TestHtmlOutput
Test: test_pages_include_navigation
- Verdict: PASS
- Analysis: Week/month links present in pages.
- Issues: None
Test: test_pages_include_meta_tags
- Verdict: PASS
- Analysis: tags and charset present.
- Issues: None
Test: test_pages_include_title
- Verdict: PASS
- Analysis: