1
- use std:: collections:: HashMap ;
1
+ use std:: {
2
+ collections:: HashMap ,
3
+ io:: { BufReader , Read } ,
4
+ } ;
2
5
3
6
use api:: { client:: ApiClient , urls:: url_for_test_case} ;
4
- use bundle:: { FileSet , FileSetBuilder , QuarantineBulkTestStatus , Test } ;
7
+ use bundle:: { FileSet , FileSetBuilder , FileSetType , QuarantineBulkTestStatus , Test } ;
5
8
use constants:: { EXIT_FAILURE , EXIT_SUCCESS } ;
6
9
use context:: {
7
- junit:: { junit_path:: JunitReportStatus , parser:: JunitParser } ,
10
+ junit:: {
11
+ bindings:: {
12
+ BindingsReport , BindingsTestCase , BindingsTestCaseStatusStatus , BindingsTestSuite ,
13
+ } ,
14
+ junit_path:: JunitReportStatus ,
15
+ parser:: JunitParser ,
16
+ } ,
8
17
repo:: RepoUrlParts ,
9
18
} ;
10
- use quick_junit :: TestCaseStatus ;
19
+ use prost :: Message ;
11
20
12
21
use crate :: error_report:: { log_error, Context } ;
13
22
@@ -21,27 +30,28 @@ fn convert_case_to_test<T: AsRef<str>>(
21
30
repo : & RepoUrlParts ,
22
31
org_slug : T ,
23
32
parent_name : String ,
24
- case : & quick_junit :: TestCase ,
25
- suite : & quick_junit :: TestSuite ,
33
+ case : & BindingsTestCase ,
34
+ suite : & BindingsTestSuite ,
26
35
) -> Test {
27
36
let name = String :: from ( case. name . as_str ( ) ) ;
28
- let xml_string_to_string = |s : & quick_junit:: XmlString | String :: from ( s. as_str ( ) ) ;
29
- let class_name = case. classname . as_ref ( ) . map ( xml_string_to_string) ;
30
- let file = case. extra . get ( "file" ) . map ( xml_string_to_string) ;
31
- let timestamp_millis = case
32
- . timestamp
33
- . or ( suite. timestamp )
34
- . map ( |t| t. timestamp_millis ( ) ) ;
37
+ let class_name = case. classname . clone ( ) ;
38
+ let file = case. extra ( ) . get ( "file" ) . cloned ( ) ;
39
+ let timestamp_millis = case. timestamp . or ( suite. timestamp ) ;
35
40
let mut test = Test {
36
41
name,
37
42
parent_name,
38
43
class_name,
39
44
file,
40
45
id : String :: with_capacity ( 0 ) ,
41
46
timestamp_millis,
47
+ is_quarantined : case. status . status == BindingsTestCaseStatusStatus :: Quarantined ,
42
48
} ;
43
- if let Some ( id) = case. extra . get ( "id" ) . map ( xml_string_to_string) {
44
- test. id = id;
49
+ if let Some ( id) = case. extra ( ) . get ( "id" ) {
50
+ if id. is_empty ( ) {
51
+ test. set_id ( org_slug, repo) ;
52
+ } else {
53
+ test. id = id. clone ( ) ;
54
+ }
45
55
} else {
46
56
test. set_id ( org_slug, repo) ;
47
57
}
@@ -65,39 +75,59 @@ impl FailedTestsExtractor {
65
75
continue ;
66
76
}
67
77
}
68
- for file in & file_set. files {
69
- let file = match std:: fs:: File :: open ( & file . original_path ) {
78
+ for base_file in & file_set. files {
79
+ let file = match std:: fs:: File :: open ( & base_file . original_path ) {
70
80
Ok ( file) => file,
71
81
Err ( e) => {
72
- tracing:: warn!( "Error opening file: {}" , e) ;
73
82
continue ;
74
83
}
75
84
} ;
76
- let reader = std:: io:: BufReader :: new ( file) ;
77
- let mut junitxml = JunitParser :: new ( ) ;
78
- match junitxml. parse ( reader) {
79
- Ok ( junitxml) => junitxml,
80
- Err ( e) => {
81
- tracing:: warn!( "Error parsing junitxml: {}" , e) ;
85
+ let mut reader = BufReader :: new ( file) ;
86
+ // check if the extension ends with xml
87
+ let bindings_reports = if file_set. file_set_type == FileSetType :: Junit {
88
+ let mut junitxml = JunitParser :: new ( ) ;
89
+ match junitxml. parse ( reader) {
90
+ Ok ( junitxml) => junitxml,
91
+ Err ( e) => {
92
+ continue ;
93
+ }
94
+ } ;
95
+ junitxml
96
+ . into_reports ( )
97
+ . iter ( )
98
+ . map ( |report| BindingsReport :: from ( report. clone ( ) ) )
99
+ . collect :: < Vec < BindingsReport > > ( )
100
+ } else {
101
+ // Create a vector to hold the contents
102
+ let mut buffer = Vec :: new ( ) ;
103
+
104
+ // Read all the bytes into the vector
105
+ let result = reader. read_to_end ( & mut buffer) ;
106
+ if let Err ( e) = result {
82
107
continue ;
83
108
}
109
+ let test_result =
110
+ proto:: test_context:: test_run:: TestResult :: decode ( buffer. as_slice ( ) )
111
+ . unwrap ( ) ;
112
+ vec ! [ BindingsReport :: from( test_result) ]
84
113
} ;
85
- for report in junitxml . reports ( ) {
86
- for suite in & report. test_suites {
114
+ for report in bindings_reports {
115
+ for suite in report. test_suites {
87
116
let parent_name = String :: from ( suite. name . as_str ( ) ) ;
88
117
for case in & suite. test_cases {
89
118
let test = convert_case_to_test (
90
119
repo,
91
120
org_slug. as_ref ( ) ,
92
121
parent_name. clone ( ) ,
93
122
case,
94
- suite,
123
+ & suite,
95
124
) ;
96
- match & case. status {
97
- TestCaseStatus :: Skipped { .. } => {
125
+ match & case. status . status {
126
+ BindingsTestCaseStatusStatus :: Unspecified
127
+ | BindingsTestCaseStatusStatus :: Skipped { .. } => {
98
128
continue ;
99
129
}
100
- TestCaseStatus :: Success { .. } => {
130
+ BindingsTestCaseStatusStatus :: Success { .. } => {
101
131
if let Some ( existing_timestamp) = successes. get ( & test. id ) {
102
132
if * existing_timestamp > test. timestamp_millis . unwrap_or ( 0 )
103
133
{
@@ -109,7 +139,8 @@ impl FailedTestsExtractor {
109
139
test. timestamp_millis . unwrap_or ( 0 ) ,
110
140
) ;
111
141
}
112
- TestCaseStatus :: NonSuccess { .. } => {
142
+ BindingsTestCaseStatusStatus :: Quarantined
143
+ | BindingsTestCaseStatusStatus :: NonSuccess { .. } => {
113
144
// Only store the most recent failure of a given test run ID
114
145
if let Some ( existing_test) = failures. get ( & test. id ) {
115
146
if existing_test. timestamp_millis > test. timestamp_millis {
@@ -179,7 +210,13 @@ pub async fn gather_quarantine_context(
179
210
} ;
180
211
}
181
212
182
- let quarantine_config = if !failed_tests_extractor. failed_tests ( ) . is_empty ( ) {
213
+ let quarantine_config = if !failed_tests_extractor. failed_tests ( ) . is_empty ( )
214
+ && file_set_builder
215
+ . file_sets ( )
216
+ . iter ( )
217
+ // internal files track quarantine status directly, so we don't need to check them
218
+ . any ( |file_set| file_set. file_set_type == FileSetType :: Junit )
219
+ {
183
220
tracing:: info!( "Checking if failed tests can be quarantined" ) ;
184
221
let result = api_client. get_quarantining_config ( request) . await ;
185
222
@@ -195,7 +232,7 @@ pub async fn gather_quarantine_context(
195
232
196
233
result. unwrap_or_default ( )
197
234
} else {
198
- tracing:: debug!( "No failed tests to quarantine" ) ;
235
+ tracing:: debug!( "Skipping quarantine check. " ) ;
199
236
api:: message:: GetQuarantineConfigResponse :: default ( )
200
237
} ;
201
238
@@ -223,7 +260,7 @@ pub async fn gather_quarantine_context(
223
260
. iter ( )
224
261
. cloned ( )
225
262
. for_each ( |failure| {
226
- let quarantine_failure = quarantined. contains ( & failure. id ) ;
263
+ let quarantine_failure = quarantined. contains ( & failure. id ) || failure . is_quarantined ;
227
264
if quarantine_failure {
228
265
quarantined_failures. push ( failure) ;
229
266
} else {
0 commit comments