github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/spyglass/lenses/junit/lens.go (about) 1 /* 2 Copyright 2018 The Kubernetes 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 provides a junit viewer for Spyglass 18 package junit 19 20 import ( 21 "bytes" 22 23 junit "github.com/joshdk/go-junit" 24 "github.com/sirupsen/logrus" 25 26 "fmt" 27 "html/template" 28 "path/filepath" 29 30 "k8s.io/test-infra/prow/spyglass/lenses" 31 ) 32 33 const ( 34 name = "junit" 35 title = "JUnit" 36 priority = 5 37 ) 38 39 func init() { 40 lenses.RegisterLens(Lens{}) 41 } 42 43 // Lens is the implementation of a JUnit-rendering Spyglass lens. 44 type Lens struct{} 45 46 // Name returns the name. 47 func (lens Lens) Name() string { 48 return name 49 } 50 51 // Title returns the title. 52 func (lens Lens) Title() string { 53 return title 54 } 55 56 // Priority returns the priority. 57 func (lens Lens) Priority() int { 58 return priority 59 } 60 61 // Header renders the content of <head> from template.html. 62 func (lens Lens) Header(artifacts []lenses.Artifact, resourceDir string) string { 63 t, err := template.ParseFiles(filepath.Join(resourceDir, "template.html")) 64 if err != nil { 65 return fmt.Sprintf("<!-- FAILED LOADING HEADER: %v -->", err) 66 } 67 var buf bytes.Buffer 68 if err := t.ExecuteTemplate(&buf, "header", nil); err != nil { 69 return fmt.Sprintf("<!-- FAILED EXECUTING HEADER TEMPLATE: %v -->", err) 70 } 71 return buf.String() 72 } 73 74 // Callback does nothing. 75 func (lens Lens) Callback(artifacts []lenses.Artifact, resourceDir string, data string) string { 76 return "" 77 } 78 79 // TestResult holds data about a test extracted from junit output 80 type TestResult struct { 81 Junit junit.Test 82 Link string 83 } 84 85 // Body renders the <body> for JUnit tests 86 func (lens Lens) Body(artifacts []lenses.Artifact, resourceDir string, data string) string { 87 type JunitViewData struct { 88 NumTests int 89 Passed []TestResult 90 Failed []TestResult 91 Skipped []TestResult 92 } 93 94 jvd := JunitViewData{ 95 Passed: []TestResult{}, 96 Failed: []TestResult{}, 97 Skipped: []TestResult{}, 98 NumTests: 0, 99 } 100 101 var err error 102 for _, a := range artifacts { 103 contents, err := a.ReadAll() 104 if err != nil { 105 logrus.WithError(err).Error("Error reading artifact") 106 continue 107 } 108 suites, err := junit.Ingest(contents) 109 if err != nil { 110 logrus.WithError(err).Error("Error parsing junit file.") 111 continue 112 } 113 for _, suite := range suites { 114 for _, test := range suite.Tests { 115 if test.Status == "failed" { 116 jvd.Failed = append(jvd.Failed, TestResult{ 117 Junit: test, 118 Link: a.CanonicalLink(), 119 }) 120 } else if test.Status == "skipped" { 121 jvd.Skipped = append(jvd.Skipped, TestResult{ 122 Junit: test, 123 Link: a.CanonicalLink(), 124 }) 125 } else if test.Status == "passed" { 126 jvd.Passed = append(jvd.Passed, TestResult{ 127 Junit: test, 128 Link: a.CanonicalLink(), 129 }) 130 } else { 131 err = fmt.Errorf("Invalid test status string: %s", test.Status) 132 logrus.Error(err) 133 } 134 } 135 } 136 jvd.NumTests = len(jvd.Passed) + len(jvd.Failed) + len(jvd.Skipped) 137 138 } 139 140 if jvd.NumTests == 0 { 141 if err != nil { 142 return fmt.Sprintf("Failed to parse JUnit test results: %v", err) 143 } 144 return "Found no JUnit tests" 145 } 146 147 junitTemplate, err := template.ParseFiles(filepath.Join(resourceDir, "template.html")) 148 if err != nil { 149 logrus.WithError(err).Error("Error executing template.") 150 return fmt.Sprintf("Failed to load template file: %v", err) 151 } 152 153 var buf bytes.Buffer 154 if err := junitTemplate.ExecuteTemplate(&buf, "body", jvd); err != nil { 155 logrus.WithError(err).Error("Error executing template.") 156 } 157 158 return buf.String() 159 }