github.com/rainforestapp/rainforest-cli@v2.12.0+incompatible/reporter_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "reflect" 10 "testing" 11 "time" 12 13 "log" 14 15 "github.com/rainforestapp/rainforest-cli/rainforest" 16 "github.com/urfave/cli" 17 ) 18 19 func newFakeReporter() *reporter { 20 r := newReporter() 21 22 r.createJUnitReportSchema = func(*rainforest.RunDetails, reporterAPI) (*jUnitReportSchema, error) { 23 return &jUnitReportSchema{}, nil 24 } 25 26 r.writeJUnitReport = func(*jUnitReportSchema, *os.File) error { 27 return nil 28 } 29 30 r.getRunDetails = func(int, reporterAPI) (*rainforest.RunDetails, error) { 31 return &rainforest.RunDetails{}, nil 32 } 33 34 r.createOutputFile = func(path string) (*os.File, error) { 35 return os.NewFile(1, "test"), nil 36 } 37 38 return r 39 } 40 41 func TestReporterCreateReport_WithoutFlags(t *testing.T) { 42 // No Flags 43 r := newReporter() 44 c := newFakeContext(make(map[string]interface{}), cli.Args{}) 45 46 err := r.createReport(c) 47 48 if err == nil { 49 t.Error("No error produced in reporter.reportForRun when Run ID is omitted") 50 } else { 51 if err.Error() != "No run ID argument found." { 52 t.Errorf("Unexpected error in reporter.reportForRun when Run ID is omitted: %v", err.Error()) 53 } 54 } 55 } 56 57 func TestReporterCreateReport(t *testing.T) { 58 var expectedFileName string 59 var expectedRunID int 60 61 r := newFakeReporter() 62 63 r.getRunDetails = func(runID int, client reporterAPI) (*rainforest.RunDetails, error) { 64 runDetails := rainforest.RunDetails{} 65 if runID != expectedRunID { 66 t.Errorf("Unexpected run ID given to createJunitReport.\nExpected: %v\nActual: %v", expectedRunID, runID) 67 return &runDetails, fmt.Errorf("Test failed") 68 } 69 70 return &runDetails, nil 71 } 72 73 r.createOutputFile = func(path string) (*os.File, error) { 74 filename := filepath.Base(path) 75 76 if filename != expectedFileName { 77 t.Errorf("Unexpected filename given to createJunitReport.\nExpected: %v\nActual: %v", expectedFileName, filename) 78 } 79 80 return os.Create("myfilename.xml") 81 } 82 83 defer os.Remove("myfilename.xml") 84 85 testCases := []struct { 86 mappings map[string]interface{} 87 args []string 88 runID int 89 filename string 90 }{ 91 { 92 mappings: map[string]interface{}{ 93 "junit-file": "myfilename.xml", 94 }, 95 args: []string{"112233"}, 96 runID: 112233, 97 filename: "myfilename.xml", 98 }, 99 { 100 mappings: map[string]interface{}{ 101 "junit-file": "myfilename.xml", 102 "run-id": "112233", 103 }, 104 args: []string{}, 105 runID: 112233, 106 filename: "myfilename.xml", 107 }, 108 } 109 110 for _, testCase := range testCases { 111 c := newFakeContext(testCase.mappings, testCase.args) 112 expectedRunID = testCase.runID 113 expectedFileName = testCase.filename 114 115 log.SetOutput(ioutil.Discard) 116 defer log.SetOutput(os.Stdout) 117 err := r.createReport(c) 118 if err != nil { 119 t.Errorf("Unexpected error in reporter.createReport: %v", err.Error()) 120 } 121 } 122 } 123 124 type fakeReporterAPI struct { 125 RunMappings map[int][]rainforest.RunTestDetails 126 } 127 128 func (api fakeReporterAPI) GetRunTestDetails(runID int, testID int) (*rainforest.RunTestDetails, error) { 129 runTests, ok := api.RunMappings[runID] 130 if !ok { 131 return nil, fmt.Errorf("No Run found with ID %v", runID) 132 } 133 134 for _, runTestDetails := range runTests { 135 if runTestDetails.ID == testID { 136 return &runTestDetails, nil 137 } 138 } 139 140 return nil, fmt.Errorf("No RunTest found with ID %v", testID) 141 } 142 143 func (api fakeReporterAPI) GetRunDetails(int) (*rainforest.RunDetails, error) { 144 // implement when needed 145 return nil, errStub 146 } 147 148 func newFakeReporterAPI(runID int, runTestDetails []rainforest.RunTestDetails) *fakeReporterAPI { 149 return &fakeReporterAPI{ 150 RunMappings: map[int][]rainforest.RunTestDetails{ 151 runID: runTestDetails, 152 }, 153 } 154 } 155 156 func TestCreateJUnitReportSchema(t *testing.T) { 157 // Without failures 158 now := time.Now() 159 runDesc := "very descriptive description" 160 runRelease := "1a2b3c" 161 totalTests := 1 162 totalNoResultTests := 0 163 totalFailedTests := 0 164 stateName := "complete" 165 166 runDetails := rainforest.RunDetails{ 167 ID: 123, 168 Description: runDesc, 169 Release: runRelease, 170 TotalTests: totalTests, 171 TotalNoResultTests: totalNoResultTests, 172 TotalFailedTests: totalFailedTests, 173 StateDetails: rainforest.RunStateDetails{ 174 Name: stateName, 175 IsFinalState: true, 176 }, 177 Timestamps: map[string]time.Time{ 178 "created_at": now.Add(-30 * time.Minute), 179 "in_progress": now.Add(-25 * time.Minute), 180 stateName: now, 181 }, 182 Tests: []rainforest.RunTestDetails{ 183 { 184 Title: "My test title", 185 CreatedAt: now.Add(-25 * time.Minute), 186 UpdatedAt: now, 187 Result: "passed", 188 }, 189 }, 190 } 191 192 // Dummy API - should not be used when there are no failed tests 193 api := newFakeReporterAPI(-1, []rainforest.RunTestDetails{}) 194 195 schema, err := createJUnitReportSchema(&runDetails, api) 196 if err != nil { 197 t.Errorf("Unexpected error returned by createJunitTestReportSchema: %v", err) 198 } 199 200 expectedSchema := jUnitReportSchema{ 201 Name: runDesc, 202 Errors: totalNoResultTests, 203 Failures: totalFailedTests, 204 Tests: totalTests, 205 Time: 30 * time.Minute.Seconds(), 206 TestCases: []jUnitTestReportSchema{ 207 { 208 Name: runDetails.Tests[0].Title, 209 Time: 25 * time.Minute.Seconds(), 210 }, 211 }, 212 } 213 214 if !reflect.DeepEqual(expectedSchema, *schema) { 215 t.Error("Incorrect JUnitTestReportSchema returned by createJunitTestReportSchema") 216 t.Errorf("Expected: %#v", expectedSchema) 217 t.Errorf("Actual: %#v", schema) 218 } 219 220 // Run has no description 221 runDetails.Description = "" 222 schema, err = createJUnitReportSchema(&runDetails, api) 223 if err != nil { 224 t.Errorf(err.Error()) 225 } 226 227 expectedSchemaName := fmt.Sprintf("Run #%v", runDetails.ID) 228 if schema.Name != expectedSchemaName { 229 t.Errorf("Unexpected schema name. Expected: %v. Got %v.", expectedSchemaName, schema.Name) 230 } 231 232 runDetails.Description = runDesc // add description to the run again for next tests 233 234 // With failures 235 failedBrowser := "chrome" 236 failedNote := "This note should appear" 237 238 runDetails.TotalFailedTests = 1 239 240 failedTest := rainforest.RunTestDetails{ 241 ID: 999888, 242 Title: "My failed test", 243 CreatedAt: now.Add(-25 * time.Minute), 244 UpdatedAt: now, 245 Result: "failed", 246 } 247 runDetails.Tests = []rainforest.RunTestDetails{failedTest} 248 249 apiTests := []rainforest.RunTestDetails{ 250 { 251 ID: failedTest.ID, 252 Title: failedTest.Title, 253 CreatedAt: failedTest.CreatedAt, 254 UpdatedAt: failedTest.UpdatedAt, 255 Result: failedTest.Result, 256 Steps: []rainforest.RunStepDetails{ 257 { 258 Browsers: []rainforest.RunBrowserDetails{ 259 { 260 Name: failedBrowser, 261 Feedback: []rainforest.RunFeedback{ 262 { 263 Result: "failed", 264 JobState: "approved", 265 FailureNote: failedNote, 266 }, 267 { 268 Result: "yes", 269 JobState: "approved", 270 FailureNote: "This note should not appear", 271 }, 272 { 273 Result: "no", 274 JobState: "rejected", 275 FailureNote: "This note should not appear either", 276 }, 277 }, 278 }, 279 }, 280 }, 281 }, 282 }, 283 } 284 285 api = newFakeReporterAPI(runDetails.ID, apiTests) 286 287 expectedSchema.Failures = 1 288 expectedSchema.TestCases = []jUnitTestReportSchema{ 289 { 290 Name: failedTest.Title, 291 Time: 25 * time.Minute.Seconds(), 292 Failures: []jUnitTestReportFailure{ 293 { 294 Type: failedBrowser, 295 Message: failedNote, 296 }, 297 }, 298 }, 299 } 300 301 var out bytes.Buffer 302 log.SetOutput(&out) 303 schema, err = createJUnitReportSchema(&runDetails, api) 304 log.SetOutput(os.Stdout) 305 306 if err != nil { 307 t.Errorf("Unexpected error returned by createJunitTestReportSchema: %v", err) 308 } 309 310 if !reflect.DeepEqual(expectedSchema, *schema) { 311 t.Error("Incorrect JUnitTestReportSchema returned by createJunitTestReportSchema") 312 t.Errorf("Expected: %#v", expectedSchema) 313 t.Errorf("Actual: %#v", schema) 314 } 315 316 // Failures due to Rainforest overriding tester result 317 commentReason := "unexpected_popup" 318 comment := "Where did this pop up come from?" 319 apiTests = []rainforest.RunTestDetails{ 320 { 321 ID: failedTest.ID, 322 Title: failedTest.Title, 323 CreatedAt: failedTest.CreatedAt, 324 UpdatedAt: failedTest.UpdatedAt, 325 Result: failedTest.Result, 326 Steps: []rainforest.RunStepDetails{ 327 { 328 Browsers: []rainforest.RunBrowserDetails{ 329 { 330 Name: failedBrowser, 331 Feedback: []rainforest.RunFeedback{ 332 { 333 Result: "failed", 334 JobState: "approved", 335 CommentReason: commentReason, 336 Comment: comment, 337 }, 338 { 339 Result: "passed", 340 JobState: "approved", 341 }, 342 { 343 Result: "failed", 344 JobState: "rejected", 345 FailureNote: "This note should not appear either", 346 }, 347 }, 348 }, 349 }, 350 }, 351 }, 352 }, 353 } 354 355 api = newFakeReporterAPI(runDetails.ID, apiTests) 356 357 expectedSchema.TestCases = []jUnitTestReportSchema{ 358 { 359 Name: failedTest.Title, 360 Time: 25 * time.Minute.Seconds(), 361 Failures: []jUnitTestReportFailure{ 362 { 363 Type: failedBrowser, 364 Message: fmt.Sprintf("%v: %v", commentReason, comment), 365 }, 366 }, 367 }, 368 } 369 370 log.SetOutput(&out) 371 schema, err = createJUnitReportSchema(&runDetails, api) 372 log.SetOutput(os.Stdout) 373 374 if err != nil { 375 t.Errorf("Unexpected error returned by createJunitTestReportSchema: %v", err) 376 } 377 378 if !reflect.DeepEqual(expectedSchema, *schema) { 379 t.Error("Incorrect JUnitTestReportSchema returned by createJunitTestReportSchema") 380 t.Errorf("Expected: %#v", expectedSchema) 381 t.Errorf("Actual: %#v", schema) 382 } 383 }