Ответ 1
Патч обезьяны socket
должен это сделать:
import socket
def guard(*args, **kwargs):
raise Exception("I told you not to use the Internet!")
socket.socket = guard
Убедитесь, что это выполняется перед любым другим импортом.
Я пытаюсь протестировать пакет, который предоставляет интерфейсы для нескольких веб-сервисов. У этого есть набор тестов, который должен проверить большинство функций без подключения к Интернету. Тем не менее, есть некоторые затяжные тесты, которые могут попытаться подключиться к данным в Интернете/загрузке, и я бы хотел, чтобы они не делали этого по двум причинам: во-первых, чтобы убедиться, что мой тестовый набор работает, если нет сетевого подключения; во-вторых, чтобы я не рассылал веб-сервисы с избыточными запросами.
Очевидным решением является отключить мой компьютер/отключить беспроводную связь, но когда я запускаю тесты на удаленной машине, которая, очевидно, не работает.
Итак, мой вопрос: могу ли я заблокировать доступ к сети/порту для одного процесса python? ( "песочница", но просто блокировка сетевых подключений)
(afaict, pysandbox этого не делает)
EDIT: я использую py.test
, поэтому мне нужно решение, которое будет работать с py.test
, в случае, если оно затрагивает любые предлагаемые ответы.
Патч обезьяны socket
должен это сделать:
import socket
def guard(*args, **kwargs):
raise Exception("I told you not to use the Internet!")
socket.socket = guard
Убедитесь, что это выполняется перед любым другим импортом.
Обновление: теперь есть плагин pytest, который делает то же самое, что и этот ответ! Вы можете прочитать ответ, чтобы посмотреть, как все работает, но я сильно рекомендую использовать плагин вместо копирования - вставить мой ответ:-) Смотрите здесь: https://github.com/miketheman/pytest-socket
Я нашел, что Томас Орозко ответил очень полезно. Следуя за кефлавичем, я объединил свой набор unit test. Это работает для меня с тысячами очень разных unit test -cases (< 100, которые нуждаются в сокете, хотя)... и в и из доктрин.
Я разместил здесь. Включая ниже для удобства. Протестировано с помощью Python 2.7.5, pytest == 2.7.0. (Чтобы проверить себя, запустите py.test --doctest-modules
в каталоге со всеми 3 клонированными файлами.)
_socket_toggle.py
from __future__ import print_function
import socket
import sys
_module = sys.modules[__name__]
def disable_socket():
""" disable socket.socket to disable the Internet. useful in testing.
.. doctest::
>>> enable_socket()
[!] socket.socket is enabled.
>>> disable_socket()
[!] socket.socket is disabled. Welcome to the desert of the real.
>>> socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Traceback (most recent call last):
...
RuntimeError: I told you not to use the Internet!
>>> enable_socket()
[!] socket.socket is enabled.
>>> enable_socket()
[!] socket.socket is enabled.
>>> disable_socket()
[!] socket.socket is disabled. Welcome to the desert of the real.
>>> socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Traceback (most recent call last):
...
RuntimeError: I told you not to use the Internet!
>>> enable_socket()
[!] socket.socket is enabled.
"""
setattr(_module, '_socket_disabled', True)
def guarded(*args, **kwargs):
if getattr(_module, '_socket_disabled', False):
raise RuntimeError("I told you not to use the Internet!")
else:
# SocketType is a valid public alias of socket.socket,
# we use it here to avoid namespace collisions
return socket.SocketType(*args, **kwargs)
socket.socket = guarded
print(u'[!] socket.socket is disabled. Welcome to the desert of the real.')
def enable_socket():
""" re-enable socket.socket to enable the Internet. useful in testing.
"""
setattr(_module, '_socket_disabled', False)
print(u'[!] socket.socket is enabled.')
conftest.py
# Put this in the conftest.py at the top of your unit tests folder,
# so it available to all unit tests
import pytest
import _socket_toggle
def pytest_runtest_setup():
""" disable the interet. test-cases can explicitly re-enable """
_socket_toggle.disable_socket()
@pytest.fixture(scope='function')
def enable_socket(request):
""" re-enable socket.socket for duration of this test function """
_socket_toggle.enable_socket()
request.addfinalizer(_socket_toggle.disable_socket)
test_example.py
# Example usage of the py.test fixture in tests
import socket
import pytest
try:
from urllib2 import urlopen
except ImportError:
import urllib3
urlopen = urllib.request.urlopen
def test_socket_disabled_by_default():
# default behavior: socket.socket is unusable
with pytest.raises(RuntimeError):
urlopen(u'https://www.python.org/')
def test_explicitly_enable_socket(enable_socket):
# socket is enabled by pytest fixture from conftest. disabled in finalizer
assert socket.socket(socket.AF_INET, socket.SOCK_STREAM)