Skip to content

Commit 033d32b

Browse files
authored
chore: add targeted utils mutation tests (#576)
* chore: add targeted utils mutation tests * test: cover flag cache miss paths * address pr review feedback * pin mutation test cache action
1 parent b172ff2 commit 033d32b

6 files changed

Lines changed: 600 additions & 16 deletions

File tree

.github/workflows/ci.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,82 @@ jobs:
7777
run: |
7878
pytest --verbose --timeout=30
7979
80+
mutation-tests:
81+
name: Targeted mutation tests
82+
runs-on: ubuntu-latest
83+
84+
steps:
85+
- uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
86+
with:
87+
fetch-depth: 0
88+
89+
- name: Check targeted mutation inputs changed
90+
id: changes
91+
shell: bash
92+
run: |
93+
set -euo pipefail
94+
95+
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
96+
base="${{ github.event.pull_request.base.sha }}"
97+
head="${{ github.event.pull_request.head.sha }}"
98+
else
99+
base="${{ github.event.before }}"
100+
head="${{ github.sha }}"
101+
fi
102+
103+
changed_files="$(git diff --name-only "$base" "$head" -- \
104+
posthog/utils.py \
105+
posthog/test/test_utils.py \
106+
posthog/test/test_size_limited_dict.py)"
107+
108+
if [[ -n "$changed_files" ]]; then
109+
echo "changed=true" >> "$GITHUB_OUTPUT"
110+
echo "Targeted mutation inputs changed:"
111+
echo "$changed_files"
112+
else
113+
echo "changed=false" >> "$GITHUB_OUTPUT"
114+
echo "Skipping targeted mutation tests: inputs unchanged."
115+
fi
116+
117+
- name: Set up Python 3.11
118+
if: steps.changes.outputs.changed == 'true'
119+
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55
120+
with:
121+
python-version: 3.11.11
122+
123+
- name: Install uv
124+
if: steps.changes.outputs.changed == 'true'
125+
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
126+
with:
127+
enable-cache: true
128+
129+
- name: Restore mutmut cache
130+
id: mutmut-cache
131+
if: steps.changes.outputs.changed == 'true'
132+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
133+
with:
134+
path: mutants
135+
key: mutmut-${{ runner.os }}-py311-${{ hashFiles('posthog/utils.py', 'posthog/test/test_utils.py', 'posthog/test/test_size_limited_dict.py') }}
136+
restore-keys: |
137+
mutmut-${{ runner.os }}-py311-
138+
139+
- name: Skip mutation tests on exact cache hit
140+
if: steps.changes.outputs.changed == 'true' && steps.mutmut-cache.outputs.cache-hit == 'true'
141+
run: |
142+
echo "Skipping targeted mutation tests: exact mutmut cache hit."
143+
144+
- name: Run targeted mutation tests
145+
if: steps.changes.outputs.changed == 'true' && steps.mutmut-cache.outputs.cache-hit != 'true'
146+
shell: bash
147+
run: |
148+
set -euo pipefail
149+
UV_PROJECT_ENVIRONMENT=$pythonLocation uv run --extra test --with mutmut mutmut run --max-children 1
150+
results="$(UV_PROJECT_ENVIRONMENT=$pythonLocation uv run --extra test --with mutmut mutmut results)"
151+
if [[ -n "$results" ]]; then
152+
echo "$results"
153+
exit 1
154+
fi
155+
80156
import-check:
81157
name: Python ${{ matrix.python-version }} import check
82158
runs-on: ubuntu-latest

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ pyrightconfig.json
2121
.DS_Store
2222
posthog-python-references.json
2323
.claude/settings.local.json
24+
mutants/

posthog/test/test_size_limited_dict.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,13 @@ def test_size_limited_dict(self, size: int, iterations: int) -> None:
2222
self.assertIsNone(values.get(i - 3))
2323
self.assertIsNone(values.get(i - 5))
2424
self.assertIsNone(values.get(i - 9))
25+
26+
def test_size_limited_dict_forwards_defaultdict_args_and_kwargs(self) -> None:
27+
values = utils.SizeLimitedDict(
28+
3, lambda: "missing", {"existing": "value"}, other="item"
29+
)
30+
31+
assert values["missing"] == "missing"
32+
assert values["existing"] == "value"
33+
assert values["other"] == "item"
34+
assert values.max_size == 3

0 commit comments

Comments
 (0)