33import shutil
44import subprocess
55import time
6+ import socket
7+
8+
9+ def find_free_port ():
10+ with socket .socket (socket .AF_INET , socket .SOCK_STREAM ) as s :
11+ s .bind (("" , 0 ))
12+ s .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
13+ return s .getsockname ()[1 ]
614
715
816def main ():
@@ -16,6 +24,7 @@ def main():
1624
1725 json_file = sys .argv [1 ]
1826 tmp_dir = sys .argv [2 ]
27+ tmp_server_dir = tmp_dir + "_server"
1928
2029 input_path = os .path .join (test_harness_dir , json_file )
2130 if not os .path .exists (input_path ):
@@ -38,40 +47,102 @@ def main():
3847 print (f"Running petstore SDK generation against { input_path } -> { tmp_dir } " )
3948 subprocess .run (cmd , check = True )
4049
41- # Test against Docker JVM Petstore server
42- container_name = f"petstore_server_{ os .getpid ()} "
43- image_name = (
44- "swaggerapi/petstore-v3"
45- if "oas3" in json_file .lower ()
46- else "swaggerapi/petstore"
47- )
48-
49- fallback_image_name = (
50- "openapitools/openapi-petstore"
51- if "oas3" in json_file .lower ()
52- else "swaggerapi/swagger-petstore" # Fallback guess
53- )
50+ # Try to run Python-based generated server first
51+ host_port = None
52+ server_process = None
53+ is_oas3 = "oas3" in json_file .lower ()
5454
5555 try :
56- print (f"Starting docker container { image_name } ..." )
56+ print ("Attempting to run Python-based mock server ..." )
5757 subprocess .run (
5858 [
59- "docker " ,
59+ "uv " ,
6060 "run" ,
61- "-d" ,
62- "-P" ,
63- "--name" ,
64- container_name ,
65- image_name ,
61+ "cdd-python" ,
62+ "from_openapi" ,
63+ "to_server" ,
64+ "-i" ,
65+ input_path ,
66+ "-o" ,
67+ tmp_server_dir ,
6668 ],
6769 check = True ,
68- capture_output = True ,
6970 )
71+ host_port = str (find_free_port ())
72+
73+ env = os .environ .copy ()
74+ env ["PORT" ] = host_port
75+ env .pop ("VIRTUAL_ENV" , None )
76+
77+ subprocess .run (["uv" , "venv" ], cwd = tmp_server_dir , env = env , check = True )
78+ subprocess .run (
79+ ["uv" , "pip" , "install" , "-e" , "." ],
80+ cwd = tmp_server_dir ,
81+ env = env ,
82+ check = True ,
83+ )
84+
85+ server_process = subprocess .Popen (
86+ [
87+ os .path .join (".venv" , "bin" , "python" ),
88+ "main.py" ,
89+ "--ephemeral" ,
90+ "--seed" ,
91+ ],
92+ cwd = tmp_server_dir ,
93+ env = env ,
94+ stdout = subprocess .PIPE ,
95+ stderr = subprocess .STDOUT ,
96+ )
97+
98+ import urllib .request
99+
100+ server_ready = False
101+ for _ in range (30 ):
102+ time .sleep (1 )
103+ try :
104+ urllib .request .urlopen (
105+ f"http://localhost:{ host_port } /openapi.json" , timeout = 1
106+ )
107+ server_ready = True
108+ break
109+ except Exception :
110+ pass
111+
112+ if not server_ready :
113+ print ("Python mock server failed to start. Output:" )
114+ server_process .terminate ()
115+ try :
116+ stdout , _ = server_process .communicate (timeout = 5 )
117+ print (
118+ f"--- SERVER OUTPUT ---\n { stdout .decode ('utf-8' , errors = 'ignore' )} \n -------------------"
119+ )
120+ except Exception as e :
121+ print (f"Failed to get server output: { e } " )
122+ server_process = None
123+ host_port = None
124+
70125 except Exception as e :
71- print (
72- f"Failed to start JVM image { image_name } , falling back to { fallback_image_name } : { e } "
126+ print (f"Failed to start Python mock server: { e } " )
127+ if server_process :
128+ server_process .terminate ()
129+ server_process = None
130+ host_port = None
131+
132+ container_name = None
133+ if not host_port :
134+ print ("Falling back to Docker JVM Petstore server..." )
135+ container_name = f"petstore_server_{ os .getpid ()} "
136+ image_name = "swaggerapi/petstore-v3" if is_oas3 else "swaggerapi/petstore"
137+
138+ fallback_image_name = (
139+ "openapitools/openapi-petstore"
140+ if is_oas3
141+ else "swaggerapi/swagger-petstore" # Fallback guess
73142 )
143+
74144 try :
145+ print (f"Starting docker container { image_name } ..." )
75146 subprocess .run (
76147 [
77148 "docker" ,
@@ -80,20 +151,55 @@ def main():
80151 "-P" ,
81152 "--name" ,
82153 container_name ,
83- fallback_image_name ,
154+ image_name ,
84155 ],
85156 check = True ,
86157 capture_output = True ,
87158 )
88- except Exception as e2 :
159+ except Exception as e :
89160 print (
90- f"Fallback docker test failed (maybe docker not available?) : { e2 } "
161+ f"Failed to start JVM image { image_name } , falling back to { fallback_image_name } : { e } "
91162 )
92- return
163+ try :
164+ subprocess .run (
165+ [
166+ "docker" ,
167+ "run" ,
168+ "-d" ,
169+ "-P" ,
170+ "--name" ,
171+ container_name ,
172+ fallback_image_name ,
173+ ],
174+ check = True ,
175+ capture_output = True ,
176+ )
177+ except Exception as e2 :
178+ print (
179+ f"Fallback docker test failed (maybe docker not available?): { e2 } "
180+ )
181+ return
182+
183+ try :
184+ import urllib .request
185+
186+ for _ in range (10 ):
187+ time .sleep (3 )
188+ try :
189+ port_res = subprocess .run (
190+ ["docker" , "port" , container_name , "8080" ],
191+ check = True ,
192+ capture_output = True ,
193+ text = True ,
194+ )
195+ host_port = port_res .stdout .strip ().split (":" )[- 1 ]
196+ urllib .request .urlopen (
197+ f"http://localhost:{ host_port } /api/swagger.json"
198+ )
199+ break
200+ except Exception :
201+ pass
93202
94- try :
95- for _ in range (10 ):
96- time .sleep (3 )
97203 try :
98204 port_res = subprocess .run (
99205 ["docker" , "port" , container_name , "8080" ],
@@ -102,35 +208,27 @@ def main():
102208 text = True ,
103209 )
104210 host_port = port_res .stdout .strip ().split (":" )[- 1 ]
105- import urllib .request
106-
107- urllib .request .urlopen (
108- f"http://localhost:{ host_port } /api/swagger.json"
109- )
110- break
111- except Exception :
112- pass
113-
114- try :
115- port_res = subprocess .run (
116- ["docker" , "port" , container_name , "8080" ],
117- check = True ,
118- capture_output = True ,
119- text = True ,
120- )
121- host_port = port_res .stdout .strip ().split (":" )[- 1 ]
122- except subprocess .CalledProcessError as e :
123- print ("Failed to get docker port:" , e .stderr )
124- print ("Failing gracefully." )
211+ except subprocess .CalledProcessError as e :
212+ print ("Failed to get docker port:" , e .stderr )
213+ print ("Failing gracefully." )
214+ return
215+ except Exception as e :
216+ print (f"Docker fallback setup failed: { e } " )
125217 return
126218
219+ try :
127220 # Use SDK to get inventory
128221 env = os .environ .copy ()
129- env ["API_BASE_URL" ] = (
130- f"http://localhost:{ host_port } /api/v3"
131- if "oas3" in json_file .lower ()
132- else f"http://localhost:{ host_port } /api"
133- )
222+ if server_process :
223+ # Python mock server has endpoints at root
224+ env ["API_BASE_URL" ] = f"http://localhost:{ host_port } "
225+ else :
226+ env ["API_BASE_URL" ] = (
227+ f"http://localhost:{ host_port } /api/v3"
228+ if is_oas3
229+ else f"http://localhost:{ host_port } /api"
230+ )
231+
134232 test_cmd = [
135233 "uv" ,
136234 "run" ,
@@ -143,16 +241,27 @@ def main():
143241 _ = subprocess .run (
144242 test_cmd , env = env , check = True , capture_output = True , text = True
145243 )
244+ print ("SDK test passed." )
146245 except subprocess .CalledProcessError as e :
147246 print ("SDK test failed with error:" , e .stderr )
148247 print ("Failing gracefully." )
149- pass
150248 finally :
151- subprocess .run (["docker" , "rm" , "-f" , container_name ], capture_output = True )
249+ if server_process :
250+ server_process .terminate ()
251+ try :
252+ server_process .wait (timeout = 5 )
253+ except subprocess .TimeoutExpired :
254+ server_process .kill ()
255+ if container_name :
256+ subprocess .run (
257+ ["docker" , "rm" , "-f" , container_name ], capture_output = True
258+ )
152259
153260 finally :
154261 if os .path .exists (tmp_dir ):
155262 shutil .rmtree (tmp_dir )
263+ if os .path .exists (tmp_server_dir ):
264+ shutil .rmtree (tmp_server_dir )
156265
157266
158267if __name__ == "__main__" : # pragma: no cover
0 commit comments