2
2
import json
3
3
import os
4
4
import re
5
+ import sys
5
6
from typing import Optional
6
7
7
8
import requests
17
18
class CodegateTestRunner :
18
19
def __init__ (self ):
19
20
self .requester_factory = RequesterFactory ()
21
+ self .failed_tests = [] # Track failed tests
20
22
21
23
def call_codegate (
22
24
self , url : str , headers : dict , data : dict , provider : str
@@ -119,7 +121,7 @@ def replacement(match):
119
121
pattern = r"ENV\w*"
120
122
return re .sub (pattern , replacement , input_string )
121
123
122
- async def run_test (self , test : dict , test_headers : dict ) -> None :
124
+ async def run_test (self , test : dict , test_headers : dict ) -> bool :
123
125
test_name = test ["name" ]
124
126
url = test ["url" ]
125
127
data = json .loads (test ["data" ])
@@ -129,7 +131,7 @@ async def run_test(self, test: dict, test_headers: dict) -> None:
129
131
response = self .call_codegate (url , test_headers , data , provider )
130
132
if not response :
131
133
logger .error (f"Test { test_name } failed: No response received" )
132
- return
134
+ return False
133
135
134
136
# Debug response info
135
137
logger .debug (f"Response status: { response .status_code } " )
@@ -142,22 +144,29 @@ async def run_test(self, test: dict, test_headers: dict) -> None:
142
144
checks = CheckLoader .load (test )
143
145
144
146
# Run all checks
145
- passed = True
147
+ all_passed = True
146
148
for check in checks :
147
149
passed_check = await check .run_check (parsed_response , test )
148
150
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
151
158
152
159
except Exception as e :
153
160
logger .exception ("Could not parse response: %s" , e )
161
+ self .failed_tests .append (test_name )
162
+ return False
154
163
155
164
async def run_tests (
156
165
self ,
157
166
testcases_file : str ,
158
167
providers : Optional [list [str ]] = None ,
159
168
test_names : Optional [list [str ]] = None ,
160
- ) -> None :
169
+ ) -> bool :
161
170
with open (testcases_file , "r" ) as f :
162
171
tests = yaml .safe_load (f )
163
172
@@ -187,7 +196,7 @@ async def run_tests(
187
196
if test_names :
188
197
filter_msg .append (f"test names: { ', ' .join (test_names )} " )
189
198
logger .warning (f"No tests found for { ' and ' .join (filter_msg )} " )
190
- return
199
+ return True # No tests is not a failure
191
200
192
201
test_count = len (testcases )
193
202
filter_msg = []
@@ -201,12 +210,20 @@ async def run_tests(
201
210
+ (f" for { ' and ' .join (filter_msg )} " if filter_msg else "" )
202
211
)
203
212
213
+ all_tests_passed = True
204
214
for test_id , test_data in testcases .items ():
205
215
test_headers = headers .get (test_data ["provider" ], {})
206
216
test_headers = {
207
217
k : self .replace_env_variables (v , os .environ ) for k , v in test_headers .items ()
208
218
}
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
210
227
211
228
212
229
async def main ():
@@ -225,10 +242,14 @@ async def main():
225
242
if test_names_env :
226
243
test_names = [t .strip () for t in test_names_env .split ("," ) if t .strip ()]
227
244
228
- await test_runner .run_tests (
245
+ all_tests_passed = await test_runner .run_tests (
229
246
"./tests/integration/testcases.yaml" , providers = providers , test_names = test_names
230
247
)
231
248
249
+ # Exit with status code 1 if any tests failed
250
+ if not all_tests_passed :
251
+ sys .exit (1 )
252
+
232
253
233
254
if __name__ == "__main__" :
234
255
asyncio .run (main ())
0 commit comments