Skip to content

Commit 1daa8b2

Browse files
committed
Add mock server wrapper and replace network calls in a test
1 parent bf7ad4a commit 1daa8b2

File tree

2 files changed

+100
-23
lines changed

2 files changed

+100
-23
lines changed

tests/conftest.py

+66
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,27 @@
66
import shutil
77
import subprocess
88
import sys
9+
from contextlib import contextmanager
910

1011
import pytest
1112
import six
13+
from pip._vendor.contextlib2 import ExitStack
1214
from setuptools.wheel import Wheel
1315

1416
from pip._internal.main import main as pip_entry_point
17+
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
1518
from tests.lib import DATA_DIR, SRC_DIR, TestData
1619
from tests.lib.certs import make_tls_cert, serialize_cert, serialize_key
1720
from tests.lib.path import Path
1821
from tests.lib.scripttest import PipTestEnvironment
22+
from tests.lib.server import make_mock_server, server_running
1923
from tests.lib.venv import VirtualEnvironment
2024

25+
if MYPY_CHECK_RUNNING:
26+
from typing import Dict, Iterable
27+
28+
from tests.lib.server import MockServer as _MockServer, Responder
29+
2130

2231
def pytest_addoption(parser):
2332
parser.addoption(
@@ -404,3 +413,60 @@ def factory():
404413
return str(output_path)
405414

406415
return factory
416+
417+
418+
class MockServer(object):
419+
def __init__(self, server):
420+
# type: (_MockServer) -> None
421+
self._server = server
422+
self._running = False
423+
self.context = ExitStack()
424+
425+
@property
426+
def port(self):
427+
return self._server.port
428+
429+
@property
430+
def host(self):
431+
return self._server.host
432+
433+
def set_responses(self, responses):
434+
# type: (Iterable[Responder]) -> None
435+
assert not self._running, "responses cannot be set on running server"
436+
self._server.mock.side_effect = responses
437+
438+
def start(self):
439+
# type: () -> None
440+
assert not self._running, "running server cannot be started"
441+
self.context.enter_context(server_running(self._server))
442+
self.context.enter_context(self._set_running())
443+
444+
@contextmanager
445+
def _set_running(self):
446+
self._running = True
447+
try:
448+
yield
449+
finally:
450+
self._running = False
451+
452+
def stop(self):
453+
# type: () -> None
454+
assert self._running, "idle server cannot be stopped"
455+
self.context.close()
456+
457+
def get_requests(self):
458+
# type: () -> Dict[str, str]
459+
"""Get environ for each received request.
460+
"""
461+
assert not self._running, "cannot get mock from running server"
462+
return [
463+
call.args[0] for call in self._server.mock.call_args_list
464+
]
465+
466+
467+
@pytest.fixture
468+
def mock_server():
469+
server = make_mock_server()
470+
test_server = MockServer(server)
471+
with test_server.context:
472+
yield test_server

tests/functional/test_install_config.py

+34-23
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import pytest
66

7+
from tests.lib.server import file_response, package_page
8+
79

810
def test_options_from_env_vars(script):
911
"""
@@ -122,46 +124,55 @@ def test_command_line_appends_correctly(script, data):
122124
), 'stdout: {}'.format(result.stdout)
123125

124126

125-
@pytest.mark.network
126-
def test_config_file_override_stack(script, virtualenv):
127+
def test_config_file_override_stack(
128+
script, virtualenv, mock_server, shared_data
129+
):
127130
"""
128131
Test config files (global, overriding a global config with a
129132
local, overriding all with a command line flag).
130133
"""
134+
mock_server.set_responses([
135+
package_page({}),
136+
package_page({}),
137+
package_page({"INITools-0.2.tar.gz": "/files/INITools-0.2.tar.gz"}),
138+
file_response(shared_data.packages.joinpath("INITools-0.2.tar.gz")),
139+
])
140+
mock_server.start()
141+
base_address = "http://{}:{}".format(mock_server.host, mock_server.port)
142+
131143
config_file = script.scratch_path / "test-pip.cfg"
132144

133145
# set this to make pip load it
134146
script.environ['PIP_CONFIG_FILE'] = str(config_file)
147+
135148
config_file.write_text(textwrap.dedent("""\
136149
[global]
137-
index-url = https://download.zope.org/ppix
138-
"""))
139-
result = script.pip('install', '-vvv', 'INITools', expect_error=True)
140-
assert (
141-
"Getting page https://download.zope.org/ppix/initools" in result.stdout
142-
)
150+
index-url = {}/simple1
151+
""".format(base_address)))
152+
script.pip('install', '-vvv', 'INITools', expect_error=True)
143153
virtualenv.clear()
154+
144155
config_file.write_text(textwrap.dedent("""\
145156
[global]
146-
index-url = https://download.zope.org/ppix
157+
index-url = {address}/simple1
147158
[install]
148-
index-url = https://pypi.gocept.com/
149-
"""))
150-
result = script.pip('install', '-vvv', 'INITools', expect_error=True)
151-
assert "Getting page https://pypi.gocept.com/initools" in result.stdout
152-
result = script.pip(
153-
'install', '-vvv', '--index-url', 'https://pypi.org/simple/',
154-
'INITools',
159+
index-url = {address}/simple2
160+
""".format(address=base_address))
155161
)
156-
assert (
157-
"Getting page http://download.zope.org/ppix/INITools"
158-
not in result.stdout
159-
)
160-
assert "Getting page https://pypi.gocept.com/INITools" not in result.stdout
161-
assert (
162-
"Getting page https://pypi.org/simple/initools" in result.stdout
162+
script.pip('install', '-vvv', 'INITools', expect_error=True)
163+
script.pip(
164+
'install', '-vvv', '--index-url', "{}/simple3".format(base_address),
165+
'INITools',
163166
)
164167

168+
mock_server.stop()
169+
requests = mock_server.get_requests()
170+
assert len(requests) == 4
171+
assert requests[0]["PATH_INFO"] == "/simple1/initools/"
172+
assert requests[1]["PATH_INFO"] == "/simple2/initools/"
173+
assert requests[2]["PATH_INFO"] == "/simple3/initools/"
174+
assert requests[3]["PATH_INFO"] == "/files/INITools-0.2.tar.gz"
175+
165176

166177
def test_options_from_venv_config(script, virtualenv):
167178
"""

0 commit comments

Comments
 (0)