1
1
Fork 0
mirror of https://github.com/pypa/pip synced 2023-12-13 21:30:23 +01:00
pip/tests/unit/test_self_check_outdated.py

257 lines
7.4 KiB
Python

import datetime
import functools
import json
import os
import sys
from typing import Any, Optional, cast
from unittest import mock
import freezegun # type: ignore
import pytest
from pip._vendor.packaging.version import parse as parse_version
from pip._internal import self_outdated_check
from pip._internal.models.candidate import InstallationCandidate
from pip._internal.models.link import Link
from pip._internal.network.session import PipSession
from pip._internal.self_outdated_check import (
SelfCheckState,
logger,
pip_self_version_check,
)
from tests.lib.path import Path
class MockBestCandidateResult:
def __init__(self, best: InstallationCandidate) -> None:
self.best_candidate = best
class MockPackageFinder:
BASE_URL = "https://pypi.org/simple/pip-{0}.tar.gz"
PIP_PROJECT_NAME = "pip"
INSTALLATION_CANDIDATES = [
InstallationCandidate(
PIP_PROJECT_NAME,
"6.9.0",
Link(BASE_URL.format("6.9.0")),
),
InstallationCandidate(
PIP_PROJECT_NAME,
"3.3.1",
Link(BASE_URL.format("3.3.1")),
),
InstallationCandidate(
PIP_PROJECT_NAME,
"1.0",
Link(BASE_URL.format("1.0")),
),
]
@classmethod
def create(cls, *args: Any, **kwargs: Any) -> "MockPackageFinder":
return cls()
def find_best_candidate(self, project_name: str) -> MockBestCandidateResult:
return MockBestCandidateResult(self.INSTALLATION_CANDIDATES[0])
class MockDistribution:
def __init__(self, installer: str, version: str) -> None:
self.installer = installer
self.version = parse_version(version)
class MockEnvironment:
def __init__(self, installer: str, installed_version: Optional[str]) -> None:
self.installer = installer
self.installed_version = installed_version
def get_distribution(self, name: str) -> Optional[MockDistribution]:
if self.installed_version is None:
return None
return MockDistribution(self.installer, self.installed_version)
def _options() -> mock.Mock:
"""Some default options that we pass to
self_outdated_check.pip_self_version_check"""
return mock.Mock(
find_links=[],
index_url="default_url",
extra_index_urls=[],
no_index=False,
pre=False,
cache_dir="",
)
@pytest.mark.parametrize(
[
"stored_time",
"installed_ver",
"new_ver",
"installer",
"check_if_upgrade_required",
"check_warn_logs",
],
[
# Test we return None when installed version is None
("1970-01-01T10:00:00Z", None, "1.0", "pip", False, False),
# Need an upgrade - upgrade warning should print
("1970-01-01T10:00:00Z", "1.0", "6.9.0", "pip", True, True),
# Upgrade available, pip installed via rpm - warning should not print
("1970-01-01T10:00:00Z", "1.0", "6.9.0", "rpm", True, False),
# No upgrade - upgrade warning should not print
("1970-01-9T10:00:00Z", "6.9.0", "6.9.0", "pip", False, False),
],
)
def test_pip_self_version_check(
monkeypatch: pytest.MonkeyPatch,
stored_time: str,
installed_ver: Optional[str],
new_ver: str,
installer: str,
check_if_upgrade_required: bool,
check_warn_logs: bool,
) -> None:
monkeypatch.setattr(
self_outdated_check,
"get_default_environment",
functools.partial(MockEnvironment, installer, installed_ver),
)
monkeypatch.setattr(
self_outdated_check,
"PackageFinder",
MockPackageFinder,
)
monkeypatch.setattr(logger, "warning", mock.Mock())
monkeypatch.setattr(logger, "debug", mock.Mock())
fake_state = mock.Mock(
state={"last_check": stored_time, "pypi_version": installed_ver},
save=mock.Mock(),
)
monkeypatch.setattr(self_outdated_check, "SelfCheckState", lambda **kw: fake_state)
with freezegun.freeze_time(
"1970-01-09 10:00:00",
ignore=[
"six.moves",
"pip._vendor.six.moves",
"pip._vendor.requests.packages.urllib3.packages.six.moves",
],
):
pip_self_version_check(PipSession(), _options())
# See that we saved the correct version
if check_if_upgrade_required:
assert fake_state.save.call_args_list == [
mock.call(new_ver, datetime.datetime(1970, 1, 9, 10, 00, 00)),
]
elif installed_ver:
# Make sure no Exceptions
assert not cast(mock.Mock, logger.debug).call_args_list
# See that save was not called
assert fake_state.save.call_args_list == []
# Ensure we warn the user or not
if check_warn_logs:
assert cast(mock.Mock, logger.warning).call_count == 1
else:
assert cast(mock.Mock, logger.warning).call_count == 0
statefile_name_case_1 = "fcd2d5175dd33d5df759ee7b045264230205ef837bf9f582f7c3ada7"
statefile_name_case_2 = "902cecc0745b8ecf2509ba473f3556f0ba222fedc6df433acda24aa5"
@pytest.mark.parametrize(
"key,expected",
[
("/hello/world/venv", statefile_name_case_1),
("C:\\Users\\User\\Desktop\\venv", statefile_name_case_2),
],
)
def test_get_statefile_name_known_values(key: str, expected: str) -> None:
assert expected == self_outdated_check._get_statefile_name(key)
def _get_statefile_path(cache_dir: str, key: str) -> str:
return os.path.join(
cache_dir, "selfcheck", self_outdated_check._get_statefile_name(key)
)
def test_self_check_state_no_cache_dir() -> None:
state = SelfCheckState(cache_dir="")
assert state.state == {}
assert state.statefile_path is None
def test_self_check_state_key_uses_sys_prefix(monkeypatch: pytest.MonkeyPatch) -> None:
key = "helloworld"
monkeypatch.setattr(sys, "prefix", key)
state = self_outdated_check.SelfCheckState("")
assert state.key == key
def test_self_check_state_reads_expected_statefile(
monkeypatch: pytest.MonkeyPatch, tmpdir: Path
) -> None:
cache_dir = tmpdir / "cache_dir"
cache_dir.mkdir()
key = "helloworld"
statefile_path = _get_statefile_path(str(cache_dir), key)
last_check = "1970-01-02T11:00:00Z"
pypi_version = "1.0"
content = {
"key": key,
"last_check": last_check,
"pypi_version": pypi_version,
}
Path(statefile_path).parent.mkdir()
with open(statefile_path, "w") as f:
json.dump(content, f)
monkeypatch.setattr(sys, "prefix", key)
state = self_outdated_check.SelfCheckState(str(cache_dir))
assert state.state["last_check"] == last_check
assert state.state["pypi_version"] == pypi_version
def test_self_check_state_writes_expected_statefile(
monkeypatch: pytest.MonkeyPatch, tmpdir: Path
) -> None:
cache_dir = tmpdir / "cache_dir"
cache_dir.mkdir()
key = "helloworld"
statefile_path = _get_statefile_path(str(cache_dir), key)
last_check = datetime.datetime.strptime(
"1970-01-02T11:00:00Z", self_outdated_check.SELFCHECK_DATE_FMT
)
pypi_version = "1.0"
monkeypatch.setattr(sys, "prefix", key)
state = self_outdated_check.SelfCheckState(str(cache_dir))
state.save(pypi_version, last_check)
with open(statefile_path) as f:
saved = json.load(f)
expected = {
"key": key,
"last_check": last_check.strftime(self_outdated_check.SELFCHECK_DATE_FMT),
"pypi_version": pypi_version,
}
assert expected == saved