Skip to content

Commit aa7ae05

Browse files
ralopesskipi
andauthored
Storing test summaries (#49)
* feat(summary): add test summary file to artifacts * fix(summary): fix integration test * fix(summary): fix integration test implicit dependencies * fix(summary): add checkout command * fix(summary): add debug logs * fix(integration): add global job config * fix(integration): correct fixtures for test results summary * test(summary): unit test summary merge method * feat(publish): add job level summaries * chore: cleanup TODOs * fix: update fixture duration data Co-authored-by: Mikołaj Kutryj <[email protected]>
1 parent 9a2c1f4 commit aa7ae05

File tree

8 files changed

+96
-23
lines changed

8 files changed

+96
-23
lines changed

.semaphore/integration.yml

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ agent:
44
machine:
55
type: e1-standard-2
66
os_image: ubuntu2004
7+
global_job_config:
8+
prologue:
9+
commands:
10+
- artifact pull workflow bin/test-results -d /tmp/test-results
11+
- sudo mv /tmp/test-results /usr/local/bin/test-results
12+
- sudo chmod +x /usr/local/bin/test-results
13+
- test-results --version
14+
- checkout
715
blocks:
816
- name: Integration tests
917
dependencies: []
1018
task:
11-
prologue:
12-
commands:
13-
- artifact pull workflow bin/test-results -d /tmp/test-results
14-
- sudo mv /tmp/test-results /usr/local/bin/test-results
15-
- sudo chmod +x /usr/local/bin/test-results
16-
- test-results --version
17-
- checkout
1819
jobs:
1920
- name: "Parsers"
2021
matrix:
@@ -30,19 +31,29 @@ blocks:
3031
- test-results publish priv/merging
3132
- artifact pull job test-results/junit.json -d /tmp/junit.json
3233
- diff priv/merging/out.json /tmp/junit.json
34+
- name: Integration tests - generate pipeline report
35+
dependencies:
36+
- Integration tests
37+
task:
38+
jobs:
39+
- name: "generate pipeline report"
40+
commands:
41+
- test-results gen-pipeline-report
3342

3443
- name: Integration tests - workflow level
3544
dependencies:
36-
- Integration tests
45+
- Integration tests - generate pipeline report
3746
task:
3847
jobs:
3948
- name: "Generate pipeline report"
4049
commands:
41-
- checkout
42-
- test-results gen-pipeline-report
4350
- artifact pull workflow test-results/${SEMAPHORE_PIPELINE_ID}.json -d /tmp/junit.json
4451
- artifact push job /tmp/junit.json -d test-results/junit.json
4552
- diff /tmp/junit.json priv/workflow/out.json
53+
- name: "Generate pipeline summary"
54+
commands:
55+
- artifact pull workflow test-results/${SEMAPHORE_PIPELINE_ID}-summary.json -d /tmp/summary.json
56+
- diff /tmp/summary.json priv/workflow/summary-out.json
4657

4758
promotions:
4859
- name: Release

cmd/compile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var compileCmd = &cobra.Command{
3232
Short: "parses xml files to well defined json schema",
3333
Long: `Parses xml file to well defined json schema
3434
35-
It traverses through directory sturcture specificed by <xml-file-path> and compiles
35+
It traverses through directory structure specified by <xml-file-path> and compiles
3636
every .xml file.
3737
`,
3838
Args: cobra.MinimumNArgs(2),

cmd/gen-pipeline-report.go

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ limitations under the License.
1818

1919
import (
2020
"encoding/json"
21+
"github.com/semaphoreci/test-results/pkg/parser"
2122
"io/ioutil"
2223
"os"
2324
"path"
@@ -44,7 +45,6 @@ var genPipelineReportCmd = &cobra.Command{
4445
}
4546

4647
var dir string
47-
removeDir := true
4848

4949
pipelineID, found := os.LookupEnv("SEMAPHORE_PIPELINE_ID")
5050
if !found {
@@ -58,25 +58,21 @@ var genPipelineReportCmd = &cobra.Command{
5858
logger.Error("Creating temporary directory failed %v", err)
5959
return err
6060
}
61+
defer os.Remove(dir)
6162

6263
dir, err = cli.PullArtifacts("workflow", path.Join("test-results", pipelineID), dir, cmd)
6364
if err != nil {
6465
return err
6566
}
6667
} else {
6768
dir = args[0]
68-
removeDir = false
6969
}
7070

7171
result, err := cli.MergeFiles(dir, cmd)
7272
if err != nil {
7373
return err
7474
}
7575

76-
if removeDir {
77-
defer os.Remove(dir)
78-
}
79-
8076
jsonData, err := json.Marshal(result)
8177
if err != nil {
8278
logger.Error("Marshaling results failed with: %v", err)
@@ -87,16 +83,42 @@ var genPipelineReportCmd = &cobra.Command{
8783
if err != nil {
8884
return err
8985
}
86+
defer os.Remove(fileName)
9087

9188
_, err = cli.PushArtifacts("workflow", fileName, path.Join("test-results", pipelineID+".json"), cmd)
9289
if err != nil {
9390
return err
9491
}
9592

96-
defer os.Remove(fileName)
93+
return pushSummaries(result.TestResults, "workflow", path.Join("test-results", pipelineID+"-summary.json"), cmd)
94+
},
95+
}
9796

97+
func pushSummaries(testResult []parser.TestResults, level, path string, cmd *cobra.Command) error {
98+
if len(testResult) == 0 {
99+
logger.Info("no test results to process")
98100
return nil
99-
},
101+
}
102+
103+
logger.Info("starting to generate summary")
104+
summaryReport := parser.Summary{}
105+
for _, results := range testResult {
106+
summaryReport.Merge(&results.Summary)
107+
}
108+
109+
jsonSummary, err := json.Marshal(summaryReport)
110+
if err != nil {
111+
return err
112+
}
113+
114+
summaryFileName, err := cli.WriteToTmpFile(jsonSummary)
115+
if err != nil {
116+
return err
117+
}
118+
defer os.Remove(summaryFileName)
119+
120+
_, err = cli.PushArtifacts(level, summaryFileName, path, cmd)
121+
return err
100122
}
101123

102124
func init() {

cmd/publish.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var publishCmd = &cobra.Command{
3434
Short: "parses xml file to well defined json schema and publishes results to artifacts storage",
3535
Long: `Parses xml file to well defined json schema and publishes results to artifacts storage
3636
37-
It traverses through directory sturcture specificed by <xml-file-path>, compiles
37+
It traverses through directory structure specified by <xml-file-path>, compiles
3838
every .xml file and publishes it as one artifact.
3939
`,
4040
Args: cobra.MinimumNArgs(1),
@@ -104,6 +104,10 @@ var publishCmd = &cobra.Command{
104104
return err
105105
}
106106

107+
if err = pushSummaries(result.TestResults, "job", path.Join("test-results", "summary.json"), cmd); err != nil {
108+
return err
109+
}
110+
107111
pipelineID, found := os.LookupEnv("SEMAPHORE_PIPELINE_ID")
108112
if !found {
109113
logger.Error("SEMAPHORE_PIPELINE_ID env is missing")

pkg/cli/cli.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,6 @@ func MergeFiles(path string, cmd *cobra.Command) (*parser.Result, error) {
319319
}
320320

321321
// Load ...
322-
// [TODO]: Test this
323322
func Load(path string) (*parser.Result, error) {
324323
var result parser.Result
325324
jsonFile, err := os.Open(path) // #nosec

pkg/parser/types.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ const (
3939
)
4040

4141
// Result ...
42-
// [TODO] Better name is required...
4342
type Result struct {
4443
TestResults []TestResults `json:"testResults"`
4544
}
@@ -316,7 +315,6 @@ func (me *Suite) hasTest(test Test) bool {
316315
}
317316

318317
// Aggregate all tests in suite
319-
// TODO: add flag to skip aggregating already present data
320318
func (me *Suite) Aggregate() {
321319
summary := Summary{}
322320

@@ -440,6 +438,17 @@ type Summary struct {
440438
Duration time.Duration `json:"duration"`
441439
}
442440

441+
//Merge merges two summaries together summing each field
442+
func (s *Summary) Merge(withSummary *Summary) {
443+
s.Total += withSummary.Total
444+
s.Passed += withSummary.Passed
445+
s.Skipped += withSummary.Skipped
446+
s.Error += withSummary.Error
447+
s.Failed += withSummary.Failed
448+
s.Disabled += withSummary.Disabled
449+
s.Duration += withSummary.Duration
450+
}
451+
443452
// UUID ...
444453
func UUID(id uuid.UUID, str string) uuid.UUID {
445454
return uuid.NewMD5(id, []byte(str))

pkg/parser/types_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,33 @@ func Test_Suite_Aggregate(t *testing.T) {
309309
assert.Equal(t, Summary{Total: 5, Passed: 1, Failed: 1, Skipped: 1, Error: 1, Disabled: 1, Duration: 110}, suite.Summary, "should sum up tests duration when there is no suite duration present")
310310
}
311311

312+
func Test_Summary_Merge(t *testing.T) {
313+
summary1 := Summary{Total: 10, Passed: 6, Failed: 1, Skipped: 1, Error: 1, Disabled: 1, Duration: 10}
314+
summary2 := Summary{Total: 20, Passed: 1, Failed: 16, Skipped: 1, Error: 1, Disabled: 1, Duration: 100}
315+
summary3 := Summary{Total: 15, Passed: 10, Failed: 2, Skipped: 1, Error: 1, Disabled: 1, Duration: 10}
316+
summary4 := Summary{Total: 25, Passed: 2, Failed: 1, Skipped: 20, Error: 1, Disabled: 1, Duration: 105}
317+
318+
result := Summary{}
319+
for _, s := range []Summary{summary1, summary2, summary3, summary4} {
320+
result.Merge(&s)
321+
}
322+
323+
assert.Equal(t, Summary{
324+
Total: 70,
325+
Passed: 19,
326+
Skipped: 23,
327+
Error: 4,
328+
Failed: 20,
329+
Disabled: 4,
330+
Duration: 225,
331+
}, result)
332+
333+
result = Summary{}
334+
result.Merge(&Summary{})
335+
assert.Equal(t, Summary{}, result, "empty summaries should be zeroed")
336+
337+
}
338+
312339
func Test_NewTest(t *testing.T) {
313340
test := NewTest()
314341

priv/workflow/summary-out.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"total":92,"passed":88,"skipped":0,"error":0,"failed":4,"disabled":0,"duration":188211000}

0 commit comments

Comments
 (0)