--- name: pysa-integration-tests description: Use when running, debugging, updating, or creating Pysa end-to-end integration tests. Use when taint analysis tests fail, when expected output files need updating, or when working with .models, .cg, .hofcg, .overrides files under `source/interprocedural_analyses/taint/test/integration`. oncalls: [pysa] --- # Pysa Integration Tests ## Overview End-to-end integration tests for the Pysa taint analysis engine. Each test is a `.py` file under `source/interprocedural_analyses/taint/test/integration/`. Tests run the full taint analysis pipeline and compare output against expected files. ## Running Tests All commands must be run from the `source/` directory. ```bash cd source # Run ALL tests (parallelized with 16 shards) OUNIT_SHARDS=16 dune exec interprocedural_analyses/taint/test/integrationTest.exe # Run a SINGLE test (e.g., format.py) PYSA_INTEGRATION_TEST=format.py dune exec interprocedural_analyses/taint/test/integrationTest.exe ``` ### With Pyrefly Frontend (Meta Internal Only) See the "Pyrefly Integration" section in `AGENTS.md` for how to build the Pyrefly binary. To run integration tests with Pyrefly: ```bash PYREFLY_BINARY= PYSA_INTEGRATION_TEST=format.py dune exec interprocedural_analyses/taint/test/integrationTest.exe ``` ## Test File Structure Each test `.py` may have these companion files: | File | Required | Purpose | |------|----------|---------| | `.py` | Yes | Python source code to analyze | | `.py.pysa` | No | Pysa model file: declares sources, sinks, TITO | | `.py.config` | No | Taint configuration: rules, sources, sinks, options | | `.py.models` | Yes | Expected output: taint models and issues (JSON) | | `.py.cg` | Yes | Expected output: call graph | | `.py.hofcg` | Yes | Expected output: higher-order call graph | | `.py.overrides` | Yes | Expected output: override graph | | `.py.pyrefly.models` | No | Expected Pyrefly output: models | | `.py.pyrefly.cg` | No | Expected Pyrefly output: call graph | | `.py.pyrefly.hofcg` | No | Expected Pyrefly output: higher-order call graph | | `.py.pyrefly.overrides` | No | Expected Pyrefly output: overrides | **Default models:** When no `.pysa` and no `.config` file is present, the test runner automatically provides default test models (`_test_sink`, `_test_source`, etc.). When either file is present, the test must be self-contained. ## Debugging Test Failures When a test fails because expected output doesn't match: 1. The test runner prints a diff (may be truncated for large diffs) 2. It creates `.actual` files for each mismatched output (e.g., `format.py.models.actual`) 3. Use `diff` to compare expected vs actual: ```bash diff source/interprocedural_analyses/taint/test/integration/format.py.models \ source/interprocedural_analyses/taint/test/integration/format.py.models.actual ``` If the test fails with type errors or analysis errors (not output mismatches), the issue is in the Python source or model definitions. ## Updating Expected Files If the output changes are expected (e.g., you intentionally changed the analysis): ```bash # Automatically moves all .actual files to their expected counterparts facebook/scripts/in_path/pysa-update-expected ``` This replaces each `.py.` with the corresponding `.py..actual`. **Always review the diff before updating** — run `sl diff` after updating to verify changes are intentional. ## Creating a New Test 1. Create `.py` under `source/interprocedural_analyses/taint/test/integration/` 2. Optionally create `.py.pysa` (model file) and/or `.py.config` (taint config) 3. Run the test — the runner auto-creates missing expected output files on the first run: ```bash PYSA_INTEGRATION_TEST=.py dune exec interprocedural_analyses/taint/test/integrationTest.exe ``` 4. Review the generated `.models`, `.cg`, `.hofcg`, `.overrides` files 5. Commit all files together ## Common Mistakes - **Wrong env var name**: It's `PYSA_INTEGRATION_TEST`, not `PYSA_TEST` or similar - **Forgetting the `.py` extension**: Use `PYSA_INTEGRATION_TEST=format.py`, not `format` - **Running from wrong directory**: `dune exec` must be run from `source/` - **Guessing OUnit flags**: Don't use `-- format` to filter tests; use the `PYSA_INTEGRATION_TEST` env var - **Manually editing expected files**: Use `pysa-update-expected` instead; expected files are `@generated` - **Forgetting OUNIT_SHARDS**: Running all tests without `OUNIT_SHARDS=16` is much slower