22import json
33import os
44import re
5+ import sys
56from typing import Optional
67
78import requests
1718class CodegateTestRunner :
1819 def __init__ (self ):
1920 self .requester_factory = RequesterFactory ()
21+ self .failed_tests = [] # Track failed tests
2022
2123 def call_codegate (
2224 self , url : str , headers : dict , data : dict , provider : str
@@ -119,7 +121,7 @@ def replacement(match):
119121 pattern = r"ENV\w*"
120122 return re .sub (pattern , replacement , input_string )
121123
122- async def run_test (self , test : dict , test_headers : dict ) -> None :
124+ async def run_test (self , test : dict , test_headers : dict ) -> bool :
123125 test_name = test ["name" ]
124126 url = test ["url" ]
125127 data = json .loads (test ["data" ])
@@ -129,7 +131,7 @@ async def run_test(self, test: dict, test_headers: dict) -> None:
129131 response = self .call_codegate (url , test_headers , data , provider )
130132 if not response :
131133 logger .error (f"Test { test_name } failed: No response received" )
132- return
134+ return False
133135
134136 # Debug response info
135137 logger .debug (f"Response status: { response .status_code } " )
@@ -142,22 +144,29 @@ async def run_test(self, test: dict, test_headers: dict) -> None:
142144 checks = CheckLoader .load (test )
143145
144146 # Run all checks
145- passed = True
147+ all_passed = True
146148 for check in checks :
147149 passed_check = await check .run_check (parsed_response , test )
148150 if not passed_check :
149- passed = False
150- logger .info (f"Test { test_name } passed" if passed else f"Test { test_name } failed" )
151+ all_passed = False
152+
153+ if not all_passed :
154+ self .failed_tests .append (test_name )
155+
156+ logger .info (f"Test { test_name } { 'passed' if all_passed else 'failed' } " )
157+ return all_passed
151158
152159 except Exception as e :
153160 logger .exception ("Could not parse response: %s" , e )
161+ self .failed_tests .append (test_name )
162+ return False
154163
155164 async def run_tests (
156165 self ,
157166 testcases_file : str ,
158167 providers : Optional [list [str ]] = None ,
159168 test_names : Optional [list [str ]] = None ,
160- ) -> None :
169+ ) -> bool :
161170 with open (testcases_file , "r" ) as f :
162171 tests = yaml .safe_load (f )
163172
@@ -187,7 +196,7 @@ async def run_tests(
187196 if test_names :
188197 filter_msg .append (f"test names: { ', ' .join (test_names )} " )
189198 logger .warning (f"No tests found for { ' and ' .join (filter_msg )} " )
190- return
199+ return True # No tests is not a failure
191200
192201 test_count = len (testcases )
193202 filter_msg = []
@@ -201,12 +210,20 @@ async def run_tests(
201210 + (f" for { ' and ' .join (filter_msg )} " if filter_msg else "" )
202211 )
203212
213+ all_tests_passed = True
204214 for test_id , test_data in testcases .items ():
205215 test_headers = headers .get (test_data ["provider" ], {})
206216 test_headers = {
207217 k : self .replace_env_variables (v , os .environ ) for k , v in test_headers .items ()
208218 }
209- await self .run_test (test_data , test_headers )
219+ test_passed = await self .run_test (test_data , test_headers )
220+ if not test_passed :
221+ all_tests_passed = False
222+
223+ if not all_tests_passed :
224+ logger .error (f"The following tests failed: { ', ' .join (self .failed_tests )} " )
225+
226+ return all_tests_passed
210227
211228
212229async def main ():
@@ -225,10 +242,14 @@ async def main():
225242 if test_names_env :
226243 test_names = [t .strip () for t in test_names_env .split ("," ) if t .strip ()]
227244
228- await test_runner .run_tests (
245+ all_tests_passed = await test_runner .run_tests (
229246 "./tests/integration/testcases.yaml" , providers = providers , test_names = test_names
230247 )
231248
249+ # Exit with status code 1 if any tests failed
250+ if not all_tests_passed :
251+ sys .exit (1 )
252+
232253
233254if __name__ == "__main__" :
234255 asyncio .run (main ())
0 commit comments