test_unit_outdated.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import datetime
  2. import os
  3. import sys
  4. from contextlib import contextmanager
  5. import freezegun
  6. import pretend
  7. import pytest
  8. from pip._vendor import lockfile, pkg_resources
  9. from pip._internal.index import InstallationCandidate
  10. from pip._internal.utils import outdated
  11. class MockPackageFinder(object):
  12. BASE_URL = 'https://pypi.org/simple/pip-{0}.tar.gz'
  13. PIP_PROJECT_NAME = 'pip'
  14. INSTALLATION_CANDIDATES = [
  15. InstallationCandidate(PIP_PROJECT_NAME, '6.9.0',
  16. BASE_URL.format('6.9.0')),
  17. InstallationCandidate(PIP_PROJECT_NAME, '3.3.1',
  18. BASE_URL.format('3.3.1')),
  19. InstallationCandidate(PIP_PROJECT_NAME, '1.0',
  20. BASE_URL.format('1.0')),
  21. ]
  22. def __init__(self, *args, **kwargs):
  23. pass
  24. def find_all_candidates(self, project_name):
  25. return self.INSTALLATION_CANDIDATES
  26. class MockDistribution(object):
  27. def __init__(self, installer):
  28. self.installer = installer
  29. def has_metadata(self, name):
  30. return name == 'INSTALLER'
  31. def get_metadata_lines(self, name):
  32. if self.has_metadata(name):
  33. yield self.installer
  34. else:
  35. raise NotImplementedError('nope')
  36. def _options():
  37. ''' Some default options that we pass to outdated.pip_version_check '''
  38. return pretend.stub(
  39. find_links=False, extra_index_urls=[], index_url='default_url',
  40. pre=False, trusted_hosts=False, process_dependency_links=False,
  41. cache_dir='',
  42. )
  43. @pytest.mark.parametrize(
  44. [
  45. 'stored_time',
  46. 'installed_ver',
  47. 'new_ver',
  48. 'installer',
  49. 'check_if_upgrade_required',
  50. 'check_warn_logs',
  51. ],
  52. [
  53. # Test we return None when installed version is None
  54. ('1970-01-01T10:00:00Z', None, '1.0', 'pip', False, False),
  55. # Need an upgrade - upgrade warning should print
  56. ('1970-01-01T10:00:00Z', '1.0', '6.9.0', 'pip', True, True),
  57. # Upgrade available, pip installed via rpm - warning should not print
  58. ('1970-01-01T10:00:00Z', '1.0', '6.9.0', 'rpm', True, False),
  59. # No upgrade - upgrade warning should not print
  60. ('1970-01-9T10:00:00Z', '6.9.0', '6.9.0', 'pip', False, False),
  61. ]
  62. )
  63. def test_pip_version_check(monkeypatch, stored_time, installed_ver, new_ver,
  64. installer, check_if_upgrade_required,
  65. check_warn_logs):
  66. monkeypatch.setattr(outdated, 'get_installed_version',
  67. lambda name: installed_ver)
  68. monkeypatch.setattr(outdated, 'PackageFinder', MockPackageFinder)
  69. monkeypatch.setattr(outdated.logger, 'warning',
  70. pretend.call_recorder(lambda *a, **kw: None))
  71. monkeypatch.setattr(outdated.logger, 'debug',
  72. pretend.call_recorder(lambda s, exc_info=None: None))
  73. monkeypatch.setattr(pkg_resources, 'get_distribution',
  74. lambda name: MockDistribution(installer))
  75. fake_state = pretend.stub(
  76. state={"last_check": stored_time, 'pypi_version': installed_ver},
  77. save=pretend.call_recorder(lambda v, t: None),
  78. )
  79. monkeypatch.setattr(
  80. outdated, 'SelfCheckState', lambda **kw: fake_state
  81. )
  82. with freezegun.freeze_time(
  83. "1970-01-09 10:00:00",
  84. ignore=[
  85. "six.moves",
  86. "pip._vendor.six.moves",
  87. "pip._vendor.requests.packages.urllib3.packages.six.moves",
  88. ]
  89. ):
  90. latest_pypi_version = outdated.pip_version_check(None, _options())
  91. # See we return None if not installed_version
  92. if not installed_ver:
  93. assert not latest_pypi_version
  94. # See that we saved the correct version
  95. elif check_if_upgrade_required:
  96. assert fake_state.save.calls == [
  97. pretend.call(new_ver, datetime.datetime(1970, 1, 9, 10, 00, 00)),
  98. ]
  99. else:
  100. # Make sure no Exceptions
  101. assert not outdated.logger.debug.calls
  102. # See that save was not called
  103. assert fake_state.save.calls == []
  104. # Ensure we warn the user or not
  105. if check_warn_logs:
  106. assert len(outdated.logger.warning.calls) == 1
  107. else:
  108. assert len(outdated.logger.warning.calls) == 0
  109. def test_self_check_state(monkeypatch, tmpdir):
  110. CONTENT = '''{"pip_prefix": {"last_check": "1970-01-02T11:00:00Z",
  111. "pypi_version": "1.0"}}'''
  112. fake_file = pretend.stub(
  113. read=pretend.call_recorder(lambda: CONTENT),
  114. write=pretend.call_recorder(lambda s: None),
  115. )
  116. @pretend.call_recorder
  117. @contextmanager
  118. def fake_open(filename, mode='r'):
  119. yield fake_file
  120. monkeypatch.setattr(outdated, 'open', fake_open, raising=False)
  121. @pretend.call_recorder
  122. @contextmanager
  123. def fake_lock(filename):
  124. yield
  125. monkeypatch.setattr(outdated, "check_path_owner", lambda p: True)
  126. monkeypatch.setattr(lockfile, 'LockFile', fake_lock)
  127. monkeypatch.setattr(os.path, "exists", lambda p: True)
  128. cache_dir = tmpdir / 'cache_dir'
  129. monkeypatch.setattr(sys, 'prefix', tmpdir / 'pip_prefix')
  130. state = outdated.SelfCheckState(cache_dir=cache_dir)
  131. state.save('2.0', datetime.datetime.utcnow())
  132. expected_path = cache_dir / 'selfcheck.json'
  133. assert fake_lock.calls == [pretend.call(expected_path)]
  134. assert fake_open.calls == [
  135. pretend.call(expected_path),
  136. pretend.call(expected_path),
  137. pretend.call(expected_path, 'w'),
  138. ]
  139. # json.dumps will call this a number of times
  140. assert len(fake_file.write.calls)