2013-09-03 37 views
11

Tôi đang thử nghiệm một gói cung cấp giao diện cho một vài dịch vụ web. Nó có một bộ thử nghiệm được cho là để kiểm tra hầu hết các chức năng mà không cần kết nối với internet. Tuy nhiên, có một số thử nghiệm kéo dài có thể cố kết nối với dữ liệu internet/tải xuống và tôi muốn ngăn chúng làm như vậy vì hai lý do: trước tiên, để đảm bảo rằng bộ thử nghiệm của tôi hoạt động nếu không có kết nối mạng; thứ hai, để tôi không gửi spam các dịch vụ web với các truy vấn dư thừa.Python: chặn kết nối mạng cho mục đích thử nghiệm?

Một giải pháp rõ ràng là rút phích cắm máy của tôi/tắt không dây, nhưng khi tôi chạy thử nghiệm trên máy từ xa rõ ràng không hoạt động.

Vì vậy, câu hỏi của tôi: Tôi có thể chặn truy cập mạng/cổng cho một quá trình python không? ("Sandbox" nó, nhưng chỉ chặn các kết nối mạng)

(afaict, pysandbox không làm điều này)

EDIT: Tôi đang sử dụng py.test vì vậy tôi cần một giải pháp mà sẽ làm việc với py.test, trong trường hợp ảnh hưởng đến bất kỳ câu trả lời được đề xuất nào.

Trả lời

10

khỉ vá socket phải làm điều đó:

import socket 
def guard(*args, **kwargs): 
    raise Exception("I told you not to use the Internet!") 
socket.socket = guard 

Hãy chắc chắn này chạy trước bất kỳ nhập khẩu khác.

+0

Điều này thật tuyệt! Bất kỳ suy nghĩ về làm thế nào để có được py.test để chạy này trước khi bất cứ điều gì khác? – keflavich

+0

Trả lời nhận xét cuối cùng của tôi: chạy câu lệnh này trong 'conftests.py'. – keflavich

+0

@keflavich Tốt để biết - cảm ơn! –

7

Cập nhật: Hiện tại, plugin hiện tại có cùng chức năng với câu trả lời này! Bạn có thể đọc câu trả lời chỉ để xem cách làm việc, nhưng tôi mạnh mẽkhuyên bạn sử dụng plugin thay vì sao chép-dán câu trả lời của tôi :-) Xem ở đây: https://github.com/miketheman/pytest-socket


Tôi tìm thấy câu trả lời Thomas Orozco của rất Hữu ích. Theo keflavich, đây là cách tôi tích hợp vào bộ thử nghiệm đơn vị của mình. Điều này làm việc cho tôi với hàng ngàn trường hợp thử nghiệm đơn vị rất khác nhau (< 100 cần ổ cắm mặc dù) ... và vào và ra khỏi tài liệu.

Tôi đã đăng here. Bao gồm dưới đây để thuận tiện. Thử nghiệm với Python 2.7.5, pytest == 2.7.0. (Để kiểm tra cho chính mình, chạy py.test --doctest-modules trong thư mục với tất cả 3 file nhân bản.)

_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's 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) 
+0

Tại sao không tăng ngoại lệ 'ConnectionError'? –

+0

@FemtoTrader Tôi cho rằng vì đó là _too_ đúng. Không muốn nhầm lẫn lỗi mà chúng tôi đang ném, với lỗi mà một built-in sẽ ném, cho một 'ConnectionError' hợp lệ. Trong thực tế, tôi thực sự sử dụng một phân lớp của Runtime Error nhưng tôi muốn giữ ví dụ này đơn giản hơn – hangtwenty

+2

Bất kỳ cơ hội cập nhật nào để làm việc cho Python3? Tôi cũng rất sẵn lòng giúp biến tính năng này thành plugin bổ sung. –

Các vấn đề liên quan