test: add _check_memory_health missing and incomplete data tests#1212
Conversation
Greptile SummaryThis PR adds three unit tests for Confidence Score: 4/5Safe to merge after fixing the ruff formatting violations that will break CI. All three new tests are logically correct and cover the intended branches. Only P2 style issues are present (formatting violations that will fail tests/app/remote/test_server.py — ruff formatting fixes needed before CI will pass. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["_check_memory_health()"] --> B{"Path('/proc/meminfo').exists()"}
B -- "False\n(test 1 covers)" --> C["return DeepHealthCheck\nstatus='missing'\ndetail='/proc/meminfo unavailable...'"]
B -- "True" --> D["read_text(encoding='utf-8')"]
D -- "OSError\n(test 3 covers)" --> E["return DeepHealthCheck\nstatus='missing'\ndetail='Unable to read meminfo: ...'"]
D -- "success" --> F{"MemTotal and MemAvailable\npresent in values?"}
F -- "No\n(test 2 covers)" --> G["return DeepHealthCheck\nstatus='missing'\ndetail='Incomplete /proc/meminfo data.'"]
F -- "Yes" --> H["Compute used_pct"]
H --> I{"used_pct < 90?"}
I -- "Yes" --> J["return DeepHealthCheck\nstatus='passed'"]
I -- "No" --> K["return DeepHealthCheck\nstatus='warn'"]
Reviews (1): Last reviewed commit: "test: add _check_memory_health missing a..." | Re-trigger Greptile |
| assert isinstance(result, DeepHealthCheck) | ||
| assert result.name == "Memory" | ||
| assert result.status == "missing" | ||
| assert "Unable to read meminfo:" in result.detail No newline at end of file |
There was a problem hiding this comment.
Missing newline at end of file
The file has no trailing newline. This will cause ruff format --check (and thus make format-check) to fail in CI.
Context Used: Code style and conventions (source)
| def fake_read_text(self, **kwargs): | ||
| raise OSError("permission denied") | ||
|
|
||
| monkeypatch.setattr(Path, "read_text",fake_read_text) |
There was a problem hiding this comment.
Formatting issues — ruff will reject
Two ruff-enforced style violations in this function: a missing space after the comma in the monkeypatch.setattr call and a trailing-whitespace-only blank line inside fake_read_text. Running make format-check will fail on both.
| def fake_read_text(self, **kwargs): | |
| raise OSError("permission denied") | |
| monkeypatch.setattr(Path, "read_text",fake_read_text) | |
| def fake_read_text(self, **kwargs): | |
| raise OSError("permission denied") | |
| monkeypatch.setattr(Path, "read_text", fake_read_text) |
Context Used: Code style and conventions (source)
| monkeypatch.setattr(Path, "exists", lambda self: False) | ||
| result = _check_memory_health() | ||
|
|
There was a problem hiding this comment.
Broad
Path class patch may bleed into unrelated code
monkeypatch.setattr(Path, "exists", lambda self: False) replaces the method on the class itself, so every Path instance created anywhere during the test call-graph (e.g. inside imports, pytest internals, or future changes to _check_memory_health) will be affected. A narrower patch targeting only the specific path object — or patching at the module level with monkeypatch.setattr("app.remote.server.Path", ...) — limits the blast radius and makes intent clearer. The same applies to the read_text patches in the other two tests.
|
@RajGajjar-01 CI is still failing. |
yashksaini-coder
left a comment
There was a problem hiding this comment.
Thanks for picking this up, the test scope maps cleanly to issue #1125 and the three branches you covered are exactly the ones that needed coverage. Two things to sort before this can land, plus one design note.
Blocking — CI will fail: I ran make lint and make format-check locally and got 7 lint errors (I001 import ordering, 5x ARG005 unused lambda args, W293 trailing whitespace) plus 3 format-check failures. The fastest path is make format && ruff check tests/ --fix from the repo root in your venv, that should auto-fix the trailing comma, blank-line whitespace, import sort, and long-line split. The ARG005 errors are trickier because the lambda signatures are correct (they replace a method, so self is required); see the inline comment below for two clean ways to address them.
One design note: greptile's broad-Path-patch comment is worth taking seriously. I left a concrete suggestion inline.
Heads up — greptile's "missing newline at end of file" comment looks stale; your follow-up commit 66f45d83 did add the trailing newline, and I confirmed locally with od -c. So you can mark that one resolved.
| _lifespan, | ||
| investigate, | ||
| investigate_stream, | ||
| _check_memory_health |
There was a problem hiding this comment.
Quick formatting one. Two ruff issues here:
- I001 — the import block is sorted alphabetically by name;
_check_memory_healthshould be next to_check_disk_health,_imds_get,_imds_token,_lifespan(the underscore-prefixed group), not afterinvestigate_stream. - Trailing comma needed (
_check_memory_health,) per ruff's format rules.
Both are auto-fixable with make format && ruff check tests/ --fix. Worth running both before pushing, there are 7 ruff errors in this file as-is and CI will reject them.
| def test_check_memory_health_returns_missing_when_proc_file_absent( | ||
| monkeypatch: pytest.MonkeyPatch, | ||
| ) -> None: | ||
| monkeypatch.setattr(remote_server.Path, "exists", lambda self: False) |
There was a problem hiding this comment.
Reinforcing greptile's "broad Path class patch" concern with a concrete fix. The issue is that remote_server.Path is the same object as pathlib.Path, Python imports are references, not copies, so monkeypatch.setattr(remote_server.Path, "exists", ...) mutates the global Path class for the test's duration. Anything that creates a Path during your test (pytest internals, plugins, transitive imports inside _check_memory_health's call graph) sees the fake.
A cleaner pattern that scopes to just the module under test:
class _FakeMeminfoPath:
def __init__(self, *_args, **_kwargs): ...
def exists(self) -> bool: return False
monkeypatch.setattr("app.remote.server.Path", _FakeMeminfoPath)This replaces the Path name in the app.remote.server namespace only. Anywhere else still gets the real Path. Bonus: the named class lets you name the fake methods clearly per-test (_FakeMissingPath, _FakeIncompletePath, _FakeOsErrorPath) and you don't need lambdas, which sidesteps the ARG005 lint issue entirely.
| monkeypatch: pytest.MonkeyPatch, | ||
| ) -> None: | ||
| monkeypatch.setattr(remote_server.Path, "exists", lambda self: True) | ||
| monkeypatch.setattr(remote_server.Path, "read_text", lambda self, **kwargs: "MemTotal: 16384 kB\n") |
There was a problem hiding this comment.
The lambda self: ... and lambda self, **kwargs: ... patterns are technically correct (you need a self slot when the lambda is bound as a method), but ruff's ARG005 flags 5 unused-argument errors across these tests. Two clean ways to silence them without disabling the rule:
- Switch to the named-class approach from the comment above, replaces
Pathwholesale, no lambdas needed. - If you'd rather keep the patch shape, prefix unused params with underscore:
lambda _self: ...andlambda _self, **_kwargs: .... ruff treats_-prefixed names as intentionally unused.
Also on this line specifically: it's 107 chars, longer than the project's 100-char limit, so ruff format will want to split it across multiple lines anyway. make format will do that automatically.
|
@RajGajjar-01 CI is failing, and resolve git merge conflicts as well. Fail to respond back will result in issue handover and PR close |
6e82131 to
7299a90
Compare
|
Hey @yashksaini-coder I have made changes and pushed those changes as per you said. Thank you for guiding. |
| ) -> None: | ||
|
|
||
| class _FakeMeminfoPath: | ||
| def __init__(self, *_args, **_kwargs) -> None: ... |
| ) -> None: | ||
|
|
||
| class _FakeIncompletePath: | ||
| def __init__(self, *_args: object, **_kwargs: object) -> None: ... |
| monkeypatch: pytest.MonkeyPatch, | ||
| ) -> None: | ||
| class _FakeOsErrorPath: | ||
| def __init__(self, *_args: object, **_kwargs: object) -> None: ... |
|
@yashksaini-coder CI is now passing and conflicts are resolved. Could you please take another look? |
|
Hey @yashksaini-coder should I resolve the issue raised by codeql ? |
|
@RajGajjar-01 yes needs to be fixed |
|
anyhow merging this for velocity @RajGajjar-01 take care of the greptile and codeql reviews next time. :) |
|
⚡ LGTM → Merged. @RajGajjar-01, your work is in. Every commit counts — thank you for this one. 👋 Join us on Discord - OpenSRE : hang out, contribute, or hunt for features and issues. Everyone's welcome. |
Yes from further I will definitely take care thank you. |


Fixes #1125
Added 3 tests for
_check_memory_health()covering the missing file, incomplete data, andOSErrorbranches. Usedmonkeypatchto avoid touching the real/proc/meminfofilesystem.Demo/Screenshot for feature changes and bug fixes -
Code Understanding and AI Usage
Did you use AI assistance (ChatGPT, Claude, Copilot, etc.) to write any part of this code?
If you used AI assistance:
Explain your implementation approach:
_check_memory_health()has 3 early-return branches that needed test coverage.For each test I used
monkeypatchto replacePath.exists()andPath.read_text()with fakes so the tests never touch the real/proc/meminfofilesystem.Test 1 fakes
exists()returningFalseto hit the missing file branch.Test 2 fakes
exists()returningTrueandread_text()returning content withoutMemAvailableto hit the incomplete data branch.Test 3 fakes
read_text()raisingOSErrorto hit the read error branch.All 3 assert
status == "missing"with a useful detail message.Checklist before requesting a review