11import json
22import logging
33import re
4- import sys
5- import threading
64import time
75from http import HTTPStatus
8- from http .server import HTTPServer , SimpleHTTPRequestHandler
9- from multiprocessing .context import Process
10- from typing import Type
11- from unittest import TestCase
12- from urllib .request import Request , urlopen
13-
14- from tests .helpers import get_mock_server_mode
6+ from http .server import SimpleHTTPRequestHandler
157
168
179class MockHandler (SimpleHTTPRequestHandler ):
@@ -32,6 +24,8 @@ def set_common_headers(self):
3224 self .end_headers ()
3325
3426 def do_GET (self ):
27+ # put_nowait is common between Queue & asyncio.Queue, it does not need to be awaited
28+ self .server .queue .put_nowait (self .path )
3529 if self .path == "/received_requests.json" :
3630 self .send_response (200 )
3731 self .set_common_headers ()
@@ -97,123 +91,3 @@ def do_GET(self):
9791 except Exception as e :
9892 self .logger .error (str (e ), exc_info = True )
9993 raise
100-
101-
102- class MockServerProcessTarget :
103- def __init__ (self , handler : Type [SimpleHTTPRequestHandler ] = MockHandler ):
104- self .handler = handler
105-
106- def run (self ):
107- self .handler .received_requests = {}
108- self .server = HTTPServer (("localhost" , 8888 ), self .handler )
109- try :
110- self .server .serve_forever (0.05 )
111- finally :
112- self .server .server_close ()
113-
114- def stop (self ):
115- self .handler .received_requests = {}
116- self .server .shutdown ()
117- self .join ()
118-
119-
120- class MonitorThread (threading .Thread ):
121- def __init__ (self , test : TestCase , handler : Type [SimpleHTTPRequestHandler ] = MockHandler ):
122- threading .Thread .__init__ (self , daemon = True )
123- self .handler = handler
124- self .test = test
125- self .test .mock_received_requests = None
126- self .is_running = True
127-
128- def run (self ) -> None :
129- while self .is_running :
130- try :
131- req = Request (f"{ self .test .server_url } /received_requests.json" )
132- resp = urlopen (req , timeout = 1 )
133- self .test .mock_received_requests = json .loads (resp .read ().decode ("utf-8" ))
134- except Exception as e :
135- # skip logging for the initial request
136- if self .test .mock_received_requests is not None :
137- logging .getLogger (__name__ ).exception (e )
138- time .sleep (0.01 )
139-
140- def stop (self ):
141- self .is_running = False
142- self .join ()
143-
144-
145- class MockServerThread (threading .Thread ):
146- def __init__ (self , test : TestCase , handler : Type [SimpleHTTPRequestHandler ] = MockHandler ):
147- threading .Thread .__init__ (self )
148- self .handler = handler
149- self .test = test
150-
151- def run (self ):
152- self .server = HTTPServer (("localhost" , 8888 ), self .handler )
153- self .test .server_url = "http://localhost:8888"
154- self .test .host , self .test .port = self .server .socket .getsockname ()
155- self .test .server_started .set () # threading.Event()
156-
157- self .test = None
158- try :
159- self .server .serve_forever ()
160- finally :
161- self .server .server_close ()
162-
163- def stop (self ):
164- self .server .shutdown ()
165- self .join ()
166-
167-
168- def setup_mock_web_api_server (test : TestCase ):
169- if get_mock_server_mode () == "threading" :
170- test .server_started = threading .Event ()
171- test .thread = MockServerThread (test )
172- test .thread .start ()
173- test .server_started .wait ()
174- else :
175- # start a mock server as another process
176- target = MockServerProcessTarget ()
177- test .server_url = "http://localhost:8888"
178- test .host , test .port = "localhost" , 8888
179- test .process = Process (target = target .run , daemon = True )
180- test .process .start ()
181-
182- time .sleep (0.1 )
183-
184- # start a thread in the current process
185- # this thread fetches mock_received_requests from the remote process
186- test .monitor_thread = MonitorThread (test )
187- test .monitor_thread .start ()
188- count = 0
189- # wait until the first successful data retrieval
190- while test .mock_received_requests is None :
191- time .sleep (0.01 )
192- count += 1
193- if count >= 100 :
194- raise Exception ("The mock server is not yet running!" )
195-
196-
197- def cleanup_mock_web_api_server (test : TestCase ):
198- if get_mock_server_mode () == "threading" :
199- test .thread .stop ()
200- test .thread = None
201- else :
202- # stop the thread to fetch mock_received_requests from the remote process
203- test .monitor_thread .stop ()
204-
205- retry_count = 0
206- # terminate the process
207- while test .process .is_alive ():
208- test .process .terminate ()
209- time .sleep (0.01 )
210- retry_count += 1
211- if retry_count >= 100 :
212- raise Exception ("Failed to stop the mock server!" )
213-
214- # Python 3.6 does not have this method
215- if sys .version_info .major == 3 and sys .version_info .minor > 6 :
216- # cleanup the process's resources
217- test .process .close ()
218-
219- test .process = None
0 commit comments