diff --git a/pactman/mock/mock_server.py b/pactman/mock/mock_server.py index 186b8c4..0870539 100644 --- a/pactman/mock/mock_server.py +++ b/pactman/mock/mock_server.py @@ -2,7 +2,7 @@ import queue import traceback from http.server import BaseHTTPRequestHandler, HTTPServer -from multiprocessing import Process, Queue +from multiprocessing import Process, Queue, SimpleQueue from .pact_request_handler import PactRequestHandler @@ -23,8 +23,10 @@ def __init__(self, pact): self.pact = pact self.interactions = Queue() self.results = Queue() - self.process = Process(target=run_server, args=(pact, self.interactions, self.results)) + notify_start = SimpleQueue() + self.process = Process(target=run_server, args=(pact, self.interactions, self.results, notify_start)) self.process.start() + notify_start.get() def setup(self, interactions): for interaction in interactions: @@ -42,16 +44,17 @@ def terminate(self): self.process.terminate() -def run_server(pact, interactions, results): - httpd = MockServer(pact, interactions, results) +def run_server(pact, interactions, results, notify_start): + httpd = MockServer(pact, interactions, results, notify_start) httpd.serve_forever() class MockServer(HTTPServer): - def __init__(self, pact, interactions, results): + def __init__(self, pact, interactions, results, notify_start): self.pact = pact self.incoming_interactions = interactions self.outgoing_results = results + self.notify_start = notify_start server_address = ("", pact.port) super().__init__(server_address, MockHTTPRequestHandler) self.interactions = [] @@ -60,6 +63,11 @@ def __init__(self, pact, interactions, results): self.log.setLevel(logging.DEBUG) self.log.propagate = False + def server_activate(self): + super().server_activate() + self.notify_start.put(True) + del self.notify_start + class Error(Exception): pass diff --git a/pactman/test/test_mock_server.py b/pactman/test/test_mock_server.py index 821dc85..37f6aed 100644 --- a/pactman/test/test_mock_server.py +++ b/pactman/test/test_mock_server.py @@ -1,3 +1,4 @@ +import socket from queue import Queue from unittest.mock import Mock @@ -21,8 +22,43 @@ def queue(*a): ) def test_correct_result_assertion(mocker, results, exception): mocker.patch("pactman.mock.mock_server.Process", autospec=True) + mocker.patch("pactman.mock.mock_server.SimpleQueue", autospec=True) s = mock_server.Server(Mock()) s.results = results with pytest.raises(exception) as e: s.verify() assert "spam" in str(e.value) + + +@pytest.fixture +def unused_port(): + with socket.socket() as s: + s.bind(("localhost", 0)) + _, port = s.getsockname()[:2] + return port + + +@pytest.fixture +def a_mock_server(tmpdir, unused_port): + from pactman import Consumer, Provider + + pact = Consumer("consumer").has_pact_with( + Provider("provider"), + pact_dir=str(tmpdir), + log_dir=str(tmpdir), + host_name="localhost", + port=unused_port, + ) + + server = mock_server.Server(pact) + yield server + server.terminate() + + +def test_mockserver_is_connectable(a_mock_server): + + pact = a_mock_server.pact + with socket.socket() as s: + # Will fail with ConnectionRefusedError if the server is not already + # bound and listening + s.connect((pact.host_name, pact.port))