github.com/GoogleCloudPlatform/testgrid@v0.0.174/metadata/junit/junit_test.go (about) 1 /* 2 Copyright 2020 The TestGrid Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package junit 18 19 import ( 20 "bytes" 21 "encoding/xml" 22 "testing" 23 24 "github.com/google/go-cmp/cmp" 25 ) 26 27 func TestMessage(t *testing.T) { 28 pstr := func(s string) *string { 29 return &s 30 } 31 32 cases := []struct { 33 name string 34 jr Result 35 max int 36 expected string 37 }{ 38 { 39 name: "basically works", 40 }, 41 { 42 name: "errored takes top priority with message and value", 43 jr: Result{ 44 Errored: &Errored{Message: "errored-0-msg", Value: *pstr("errored-0")}, 45 Failure: &Failure{Message: "failure-1-msg", Value: *pstr("failure-1")}, 46 Skipped: &Skipped{Message: "skipped-2-msg", Value: *pstr("skipped-2")}, 47 Error: pstr("error-3"), 48 Output: pstr("output-4"), 49 }, 50 expected: "errored-0-msg\nerrored-0", 51 }, 52 { 53 name: "errored takes top priority with message", 54 jr: Result{ 55 Errored: &Errored{Message: "errored-0-msg"}, 56 Failure: &Failure{Message: "failure-1-msg"}, 57 Skipped: &Skipped{Message: "skipped-2-msg"}, 58 Error: pstr("error-3"), 59 Output: pstr("output-4"), 60 }, 61 expected: "errored-0-msg", 62 }, 63 { 64 name: "errored takes top priority with value", 65 jr: Result{ 66 Errored: &Errored{Value: *pstr("errored-0")}, 67 Failure: &Failure{Value: *pstr("failure-1")}, 68 Skipped: &Skipped{Value: *pstr("skipped-2")}, 69 Error: pstr("error-3"), 70 Output: pstr("output-4"), 71 }, 72 expected: "errored-0", 73 }, 74 75 { 76 name: "failure priorized over skipped, error and output with message and value", 77 jr: Result{ 78 Failure: &Failure{Message: "failure-0-msg", Value: *pstr("failure-0")}, 79 Skipped: &Skipped{Message: "skipped-1-msg", Value: *pstr("skipped-1")}, 80 Error: pstr("error-2"), 81 Output: pstr("output-3"), 82 }, 83 expected: "failure-0-msg\nfailure-0", 84 }, 85 { 86 name: "failure priorized over skipped, error and output with message", 87 jr: Result{ 88 Failure: &Failure{Message: "failure-0-msg"}, 89 Skipped: &Skipped{Message: "skipped-1-msg"}, 90 Error: pstr("error-2"), 91 Output: pstr("output-3"), 92 }, 93 expected: "failure-0-msg", 94 }, 95 { 96 name: "failure priorized over skipped, error and output with value", 97 jr: Result{ 98 Failure: &Failure{Value: *pstr("failure-0")}, 99 Skipped: &Skipped{Value: *pstr("skipped-1")}, 100 Error: pstr("error-2"), 101 Output: pstr("output-3"), 102 }, 103 expected: "failure-0", 104 }, 105 { 106 name: "skipped prioritized over error, output with message and value", 107 jr: Result{ 108 Skipped: &Skipped{Message: "skipped-1-msg", Value: *pstr("skipped-1")}, 109 Error: pstr("error-2"), 110 Output: pstr("output-3"), 111 }, 112 expected: "skipped-1-msg\nskipped-1", 113 }, 114 { 115 name: "skipped prioritized over error, output with message", 116 jr: Result{ 117 Skipped: &Skipped{Message: "skipped-1-msg"}, 118 Error: pstr("error-2"), 119 Output: pstr("output-3"), 120 }, 121 expected: "skipped-1-msg", 122 }, 123 { 124 name: "skipped prioritized over error, output with value", 125 jr: Result{ 126 Skipped: &Skipped{Value: *pstr("skipped-1")}, 127 Error: pstr("error-2"), 128 Output: pstr("output-3"), 129 }, 130 expected: "skipped-1", 131 }, 132 { 133 name: "error has higher priority than output", 134 jr: Result{ 135 Error: pstr("error-2"), 136 Output: pstr("output-3"), 137 }, 138 expected: "error-2", 139 }, 140 { 141 name: "return output when set", 142 jr: Result{ 143 Output: pstr("output-3"), 144 }, 145 expected: "output-3", 146 }, 147 { 148 name: "truncate long messages upon request", 149 jr: Result{ 150 Output: pstr("four by four"), 151 }, 152 max: 8, 153 expected: "four...four", 154 }, 155 { 156 name: "handle invalid UTF-8 strings", 157 jr: Result{ 158 Output: pstr("a\xc5z"), 159 }, 160 max: 8, 161 expected: "invalid utf8: a?z", 162 }, 163 } 164 165 for _, tc := range cases { 166 t.Run(tc.name, func(t *testing.T) { 167 if actual, expected := tc.jr.Message(tc.max), tc.expected; actual != expected { 168 t.Errorf("jr.Message(%d) got %q, want %q", tc.max, actual, expected) 169 } 170 }) 171 } 172 } 173 174 func TestParse(t *testing.T) { 175 pstr := func(s string) *string { 176 return &s 177 } 178 cases := []struct { 179 name string 180 buf []byte 181 expected *Suites 182 }{ 183 { 184 name: "parse empty file as empty suite", 185 expected: &Suites{}, 186 }, 187 { 188 name: "not xml fails", 189 buf: []byte("<hello"), 190 }, 191 { 192 name: "parse testsuite correctly", 193 buf: []byte(`<testsuite><testcase name="hi"/></testsuite>`), 194 expected: &Suites{ 195 Suites: []Suite{ 196 { 197 XMLName: xml.Name{Local: "testsuite"}, 198 Results: []Result{ 199 {Name: "hi"}, 200 }, 201 }, 202 }, 203 }, 204 }, 205 { 206 name: "parse testsuites correctly", 207 buf: []byte(` 208 <testsuites> 209 <testsuite name="fun" tests="10" disabled="1" skipped="2" errors="3" failures="4" time="100.1" timestamp="2023-08-28T17:15:04"> 210 <testsuite name="knee"> 211 <properties> 212 <property name="SuiteSucceeded" value="true"></property> 213 </properties> 214 <testcase name="bone" time="6" /> 215 <testcase name="head" time="3" > 216 <failure type="failure" message="failure message attribute"> failure message body </failure> 217 </testcase> 218 <testcase name="neck" time="2" > 219 <error type="error" message="error message attribute"> error message body </error> 220 </testcase> 221 </testsuite> 222 <testcase name="word" classname="E2E Suite" status="skipped" time="7"></testcase> 223 </testsuite> 224 </testsuites> 225 `), 226 expected: &Suites{ 227 XMLName: xml.Name{Local: "testsuites"}, 228 Suites: []Suite{ 229 { 230 XMLName: xml.Name{Local: "testsuite"}, 231 Name: "fun", 232 Failures: 4, 233 Tests: 10, 234 Disabled: 1, 235 Skipped: 2, 236 Errors: 3, 237 Time: 100.1, 238 TimeStamp: "2023-08-28T17:15:04", 239 Suites: []Suite{ 240 { 241 XMLName: xml.Name{Local: "testsuite"}, 242 Name: "knee", 243 Properties: &Properties{ 244 []Property{ 245 { 246 Name: "SuiteSucceeded", 247 Value: "true", 248 }, 249 }, 250 }, 251 Results: []Result{ 252 { 253 Name: "bone", 254 Time: 6, 255 }, 256 { 257 Name: "head", 258 Time: 3, 259 Failure: &Failure{Type: "failure", Message: "failure message attribute", Value: *pstr(" failure message body ")}, 260 }, 261 { 262 Name: "neck", 263 Time: 2, 264 Errored: &Errored{Type: "error", Message: "error message attribute", Value: *pstr(" error message body ")}, 265 }, 266 }, 267 }, 268 }, 269 Results: []Result{ 270 { 271 Name: "word", 272 Time: 7, 273 ClassName: "E2E Suite", 274 Status: "skipped", 275 }, 276 }, 277 }, 278 }, 279 }, 280 }, 281 } 282 283 for _, tc := range cases { 284 t.Run(tc.name, func(t *testing.T) { 285 actual, err := Parse(tc.buf) 286 str := string(tc.buf) 287 switch { 288 case err != nil: 289 if tc.expected != nil { 290 t.Errorf("Parse(%q) got unexpected error: %v", str, err) 291 } 292 case tc.expected == nil: 293 t.Errorf("Parse(%q) got %v, wanted an error", str, actual) 294 default: 295 if diff := cmp.Diff(actual, tc.expected); diff != "" { 296 t.Errorf("Parse(%q) got unexpected diff:\n%s", str, diff) 297 } 298 } 299 if err == nil { 300 streamActual, err := ParseStream(bytes.NewReader(tc.buf)) 301 if err != nil { 302 t.Errorf("ParseStream() got unexpected error: %v", err) 303 } 304 if diff := cmp.Diff(actual, streamActual); diff != "" { 305 t.Errorf("ParseStream() got unexpected diff:\n%s", diff) 306 } 307 } 308 }) 309 } 310 }