Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 41 additions & 12 deletions tests/test_vuln_staleness.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,35 @@ def fresh_client(tmp_workspace):
return OSVClient(workspace=tmp_workspace, ttl=DEFAULT_TTL, offline=True)


@pytest.fixture
def app_fixture_copy():
"""Copy a named app fixture to a temp dir; cleaned up after the test.

Returns a function ``copy(name) -> path`` that copies
``FIXTURES_DIR/<name>`` into a fresh temp dir and returns its path.
The temp dir is removed when the test finishes.

Using a temp copy (instead of running scans directly on the shared
fixture directory) prevents side-effects like ``.codelens/osv_cache.db``
from being written into the fixture and leaking into other tests.
"""
copies: list = []

def _copy(name: str) -> str:
src = os.path.join(FIXTURES_DIR, name)
if not os.path.isdir(src):
pytest.skip(f"fixture {name!r} not available")
dst = tempfile.mkdtemp(prefix=f"codelens_vuln_{name}_")
shutil.copytree(src, dst, dirs_exist_ok=True)
copies.append(dst)
return dst

yield _copy

for d in copies:
shutil.rmtree(d, ignore_errors=True)


def _make_pkg(name="lodash", version="4.17.15", ecosystem="npm"):
"""Build an OSVPackage with a supported ecosystem by default."""
return OSVPackage(name=name, version=version, ecosystem=ecosystem)
Expand Down Expand Up @@ -398,10 +427,10 @@ def test_max_age_zero_acts_like_refresh(self, tmp_workspace):
class TestScanVulnerabilitiesCacheInfo:
"""End-to-end: ``scan_vulnerabilities()`` output includes ``cache_info``."""

def test_clean_app_no_deps_has_cache_info(self):
def test_clean_app_no_deps_has_cache_info(self, app_fixture_copy):
"""``clean_app`` has no dependency files → empty ``cache_info``."""
fixture = os.path.join(FIXTURES_DIR, "clean_app")
result = scan_vulnerabilities(fixture, offline=True)
workspace = app_fixture_copy("clean_app")
result = scan_vulnerabilities(workspace, offline=True)
assert result["status"] == "ok"
assert "cache_info" in result
info = result["cache_info"]
Expand All @@ -410,10 +439,10 @@ def test_clean_app_no_deps_has_cache_info(self):
assert info["stale_packages"] == []
assert info["ttl_hours"] == 24.0

def test_vulnerable_app_has_stale_cache_info(self):
def test_vulnerable_app_has_stale_cache_info(self, app_fixture_copy):
"""``vulnerable_app`` has npm deps; offline mode → all stale."""
fixture = os.path.join(FIXTURES_DIR, "vulnerable_app")
result = scan_vulnerabilities(fixture, offline=True)
workspace = app_fixture_copy("vulnerable_app")
result = scan_vulnerabilities(workspace, offline=True)
assert result["status"] == "ok"
assert "cache_info" in result
info = result["cache_info"]
Expand All @@ -423,10 +452,10 @@ def test_vulnerable_app_has_stale_cache_info(self):
# npm packages from vulnerable_app's package.json
assert "lodash@4.17.15" in info["stale_packages"]

def test_cache_info_shape(self):
def test_cache_info_shape(self, app_fixture_copy):
"""``cache_info`` dict has exactly the keys specified in issue #30."""
fixture = os.path.join(FIXTURES_DIR, "clean_app")
result = scan_vulnerabilities(fixture, offline=True)
workspace = app_fixture_copy("clean_app")
result = scan_vulnerabilities(workspace, offline=True)
info = result["cache_info"]
expected_keys = {
"last_refresh",
Expand All @@ -437,10 +466,10 @@ def test_cache_info_shape(self):
}
assert set(info.keys()) == expected_keys

def test_cache_info_is_additive(self):
def test_cache_info_is_additive(self, app_fixture_copy):
"""Adding cache_info must not remove or rename existing output keys."""
fixture = os.path.join(FIXTURES_DIR, "clean_app")
result = scan_vulnerabilities(fixture, offline=True)
workspace = app_fixture_copy("clean_app")
result = scan_vulnerabilities(workspace, offline=True)
# Pre-issue-#30 output keys must still be present.
for key in (
"status",
Expand Down
Loading