Implement testing suite: pytest scaffolding, unit tests for existing pure logic, CI workflow#116
Implement testing suite: pytest scaffolding, unit tests for existing pure logic, CI workflow#116zachtheyek wants to merge 5 commits into
Conversation
…ctories - tests/conftest.py: autouse isolation fixture (tmp-path AETHERSCAN_* env, singleton _reset() teardown for Config/ResourceManager/Database/Logger/ ResourceMonitor, signal-handler + atexit hygiene), plus synthetic data factories (tiny .npy background plates, .h5 observations, inference CSVs) - pyproject.toml: [tool.pytest.ini_options] with pythonpath=src, testpaths, and the slow/gpu/cluster/integration markers - tests/unit/: unit tests for existing pure logic across config, cli validation, data generation, preprocessing, train utilities, models, db, and resource manager - tests/integration/: gpu+cluster-marked end-to-end train and CSV-inference smoke tests (blpc3-sized known-good configs) - remove tests/placeholder Suite: 185 passed, 3 skipped (Linux-only), 2 deselected (gpu/cluster) on macOS CPU TF 2.17. Part of #113. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…CPU) Runs the default marker selection (-m 'not gpu and not cluster') on ubuntu-latest with tensorflow-cpu==2.17.* plus the pinned deps from requirements-container.txt (h5py/pandas/psutil/pytest added explicitly since the NGC base ships them). Pip cache keyed on the pin file. Also gives claude-flaky-test-tracker real CI runs to read. Part of #113. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…xt skill Replaces the 'tests/ is a placeholder — no test suite yet' notes with how to run the suite (default selection, cluster integration smokes, single tests), the marker table, the conftest isolation/fixture contract, and test-writing expectations for future PRs. Closes #113. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n, determinism - tests/integration/conftest.py: shared cluster_paths + run_pipeline fixtures (repo root, AETHERSCAN_* defaults, PYTHONPATH-injected subprocess launcher) replacing the copy-pasted env assembly in both smoke tests - CI: install hdf5plugin explicitly (preprocessing.py imports it at module scope; environment.yml pins it too — don't rely on setigen's transitive pull), single pip install layer, cache key includes the workflow file - pytest: --strict-markers so a typo'd marker can't silently dodge the CI selection - test_db: make the flush-during-shutdown test deterministic (stub writer thread instead of racing the real one); NOTE that the empty-list-filter test documents current (surprising) behavior, not desired behavior - test_preprocessing/conftest: derive grouping columns + h5-path column from InferenceConfig instead of duplicating the literals - test_models: merge the two slow Beta-VAE tests so the graph builds once - CLAUDE.md: integration tests are gpu+cluster-marked; keep the honesty guardrail for TF-less environments (run what you can, say what you ran) - conftest: carry over the clean-shutdown / release-deploy test TODOs from the deleted tests/placeholder Suite after fixes: 184 passed, 3 skipped (Linux-only), 2 deselected (gpu/cluster) on macOS CPU TF 2.17 / Keras 3.15. Part of #113. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @zachtheyek's task in 1m 21s —— View job PR Review: Testing Suite Implementation
Overall AssessmentThis is a very well-structured, thorough first test suite. The scaffolding design (autouse isolation fixture, singleton reset ordering, signal handler restoration) is production-quality and will make future test writing low-friction. 187 unit tests covering the pure-logic surface area of 8 modules, plus properly gated cluster integration smokes — strong foundation. A few observations below, roughly ordered by importance. Findings1.
|
…scan - test_data_generation: NOTE on _seed_rngs explaining np.random.seed() intentionally targets the legacy global RandomState (the code under test uses the legacy API) so future contributors don't break determinism by switching to np.random.default_rng - test_train_smoke: NOTE on _next_test_tag that the scan-then-pick is not atomic and assumes manual, sequential smoke runs Review findings 1 and 6 on PR #116; finding 9 deliberately left as-is per the reviewer's own note. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Addressed the two informational review notes in commit aaab689:
Finding 9 (sharing the smoke-flag constants between the unit and integration files) is deliberately left as-is per the reviewer's own note — the two copies are cross-referenced in comments instead, since sharing them would require restructuring tests/ into a package for one constant. |
|
@claude please perform a second-pass code review of this PR. Re-review the current diff for any remaining correctness bugs, security issues, or significant quality problems, and post your findings. If the diff is clean, please say so explicitly. (Final verification round before merge.) |
Second-pass code review — PR #116I've re-reviewed the full diff (~1800 lines across 14 files). The diff is clean. No correctness bugs, security issues, or significant quality problems found. What I checked
Minor observations (non-blocking, no action needed for this PR)
LGTM — ready to merge. |
Closes #113
Summary
Adds the pytest test suite that every later PR builds on: scaffolding, unit tests for the existing pure logic, cluster-marked end-to-end smokes, and a CI workflow.
Scaffolding
tests/conftest.py— autouse isolation fixture for every non-integration test: pointsAETHERSCAN_{DATA,MODEL,OUTPUT}_PATHattmp_path, resets all five singletons (Config,ResourceManager,Database,Logger,ResourceMonitor) via their_reset()hooks, re-runsinit_config(), and on teardown stops leaked pools/SHM/threads (mirroringcleanup_all()ordering), unregisters the per-testatexithook, and restores signal handlers. Also provides synthetic data factories: tiny.npybackground plates ((n, 6, 16, width)float32), tiny filterbank-style.h5files (datadset(16, 1, n_chans)+fch1/foff/nchansattrs), and tiny cadence-grouping CSVs (column names read fromInferenceConfig).pyproject.toml—[tool.pytest.ini_options]:pythonpath = ["src"],testpaths,--strict-markers, and theslow/gpu/cluster/integrationmarkers.tests/integration/conftest.py— sharedcluster_paths+run_pipelinefixtures so the two smokes can't drift apart.Unit tests (
tests/unit/, 187 tests)test_config.py_reset(), env-var paths,to_dict()drift guard (section keys vs dataclass fields), JSON serializabilitytest_cli_validation.py_TAG_PATTERNaccept/reject matrix, cross-replica divisibility matrix (defaults valid for 4/6 replicas but not 5; blpc3 smoke config the inverse), semantic checks (SNR ordering, step-schedule sum, enums, file-exists),_check_cross_constraints/_solve_cross_param_constraints(incl. L1-minimality on a patched grid + candidate budget),apply_saved_configprecedence (defaults < saved < CLI), mode-scoped flag routing,infer_start_roundtest_data_generation.pylog_normbounds/ordering/idempotence,check_valid_intersection(ON-region boundaries inclusive),new_cadencesignal_info keys + forced slope-clamp path,create_false/create_true_single/create_true_doubleshapes, prefixes, OFF-observation purity, stage A/B/C stats,_compute_intensity_statsNaN handlingtest_preprocessing.py_deduplicate_hits(greedy merge, strict boundary),group_observations_from_csv(valid/flagged/missing-col),_cadence_npy_filenamesanitization,_to_json_safe,_remove_dc_spike(exact asymmetric interpolation),_fit_channel_bandpasson a synthetic bandpass,_read_coarse_channel_workertest_train_utils.pyget_latest_tagpriority ladder (final > round > timestamp > test, numeric ties),_calculate_curriculum_snrall 3 schedules incl. endpoints + error cases,archive_directorymove/copy/delete-≥round semantics,compute_expected_std/check_encoder_trained,_select_positive_class_shapshape matrixtest_models.pyprepare_latent_featuresrow-major layout,RandomForestModeltrain/predict/proba/verbose/threshold/save-load on toy data,Samplinglayer, encoder/decoder symmetry + forward pass (markedslow)test_db.pyis_finitesanitization +slope_clampedround-trip + stability aggregation, query filters (scalar/list/range) and column whitelists (SQL-injection rejection)test_manager.pycleanup_allidempotence (Linux-only: PSS accounting)Integration smokes (
tests/integration/, markedintegration+gpu+cluster)test_train_smoke.py— the known-good blpc3 5-GPU smoke config (batch geometry divisible for exactly 5 replicas) via apython -m aetherscan.main trainsubprocess with a fresh auto-incrementedtest_vNNtag; asserts clean exit + final encoder/decoder/RF artifacts + per-round checkpoints + config snapshot.test_inference_smoke.py— subset CSV inference against the persistedtest_v17dummy model; asserts clean exit + config snapshot.CI (
.github/workflows/tests.yml)PR + push-to-master, ubuntu-latest, Python 3.10 and 3.12 matrix,
tensorflow-cpu==2.17.*+ the pins fromrequirements-container.txt+h5py hdf5plugin pandas psutil pytest, pip cache. Runspytest -m "not gpu and not cluster" -q. This also givesclaude-flaky-test-trackerreal runs to read.Docs
CLAUDE.md, CONTRIBUTING.md (new Testing section: commands, marker table, fixture contract, test-writing expectations), and the repo-context skill now describe the suite instead of "tests/ is a placeholder";
tests/placeholderremoved (its two TODO obligations are carried intotests/conftest.py).No
src/changes — the_reset()hooks the suite depends on already existed on all five singletons.Verification
Local (macOS arm64, CPU-only venv: Python 3.12.13, tensorflow 2.17.1 / Keras 3.15, pins from
requirements-container.txt):(3 skipped = Linux-only
cleanup_allPSS tests, which run in CI; 2 deselected = the gpu/cluster smokes.)Cluster (blpc3, NGC 25.02 container, 5x RTX PRO 6000, branch @ 9b379eb):
Integration smokes (GPUs confirmed idle via
nvidia-smibefore launch):test_inference_smoke: subset CSV inference against thetest_v17dummy model (resumed from the existing preprocessed subset stamps), clean exit + config snapshot.test_train_smoke: full end-to-end train under the fresh auto-incrementedtest_v18tag — finalvae_encoder/vae_decoder/random_forest_test_v18artifacts,round_01/round_02checkpoints, andconfig_test_v18.jsonall verified on disk. Thetest_v18artifacts were left in place as reusable dummies (liketest_v17).Full default (CPU) selection also run inside the NGC container, exercising the tf-keras shim + pytest 9.1.1 path and the 3 Linux-only tests that self-skip on macOS:
Cluster hygiene:
/dev/shmdiffed against a pre-run snapshot — no leaked segments; temp logs removed; cluster repo restored tomaster.pre-commit run --all-filespasses (ruff lint+format, yaml/toml checks, gitleaks).Deferred validation
collect_validation_errors, but not exercised end-to-end on hardware in this PR (bla0 not accessible this session). The default-config train path on 6 GPUs is the existing, previously-validated configuration.tests/conftest.py) belong to the retry-overhaul and release-engineering work respectively.AI assistance disclosure
Implemented with Claude Code (Anthropic). Extent: test-suite implementation (conftest, unit + integration tests), CI workflow, documentation updates, multi-angle code review, and local + cluster verification runs. All work reviewed against the existing source before submission; no
src/behavior was modified.🤖 Generated with Claude Code