Created
February 13, 2019 21:49
-
-
Save digitalresistor/0be94ced48383a42e70c3d9fff1f4ad0 to your computer and use it in GitHub Desktop.
Pytest fixture to find a free port to pass to a function that is about to bind but can't be given port 0 (because it's got a stupid API that checks for port != 0) and you run a lot of concurrent tests that can't all bind to the same port!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@pytest.fixture(scope="session") | |
def find_free_port(): | |
""" | |
Returns a factory that finds the next free port that is available on the OS | |
This is a bit of a hack, it does this by creating a new socket, and calling | |
bind with the 0 port. The operating system will assign a brand new port, | |
which we can find out using getsockname(). Once we have the new port | |
information we close the socket thereby returning it to the free pool. | |
This means it is technically possible for this function to return the same | |
port twice (for example if run in very quick succession), however operating | |
systems return a random port number in the default range (1024 - 65535), | |
and it is highly unlikely for two processes to get the same port number. | |
In other words, it is possible to flake, but incredibly unlikely. | |
""" | |
def _find_free_port(): | |
import socket | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
s.bind(("0.0.0.0", 0)) | |
portnum = s.getsockname()[1] | |
s.close() | |
return portnum | |
return _find_free_port |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment