k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/pkg/benchmarkjunit/integration_test.go (about) 1 /* 2 Copyright 2019 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 main 18 19 import ( 20 "flag" 21 "fmt" 22 "os" 23 "path" 24 "path/filepath" 25 "reflect" 26 "sort" 27 "strconv" 28 "strings" 29 "testing" 30 31 "github.com/GoogleCloudPlatform/testgrid/metadata/junit" 32 ) 33 34 func createTempFile() (string, error) { 35 outFile, err := os.CreateTemp("", "dummybenchmarks") 36 if err != nil { 37 return "", fmt.Errorf("create error: %w", err) 38 } 39 if err := outFile.Close(); err != nil { 40 return "", fmt.Errorf("close error: %w", err) 41 } 42 return outFile.Name(), nil 43 } 44 45 var goBinaryPath = flag.String("go", "go", "The location of the go binary. This flag is primarily intended for use with bazel.") 46 47 func TestDummybenchmarksIntegration(t *testing.T) { 48 // Set HOME and GOROOT envvars for bazel if needed. 49 if os.Getenv("TEST_WORKSPACE") != "" { // Running in bazel 50 if os.Getenv("HOME") == "" { 51 wd, _ := os.Getwd() // Just use `/home` if we can't determine working dir. 52 os.Setenv("HOME", wd+"/home") 53 } 54 if os.Getenv("GOROOT") == "" { 55 goRoot, _ := filepath.Abs("../../external/go_sdk") 56 os.Setenv("GOROOT", goRoot) 57 t.Logf("Setting GOROOT to %q.\n", goRoot) 58 } 59 } 60 61 outFile, err := createTempFile() 62 if err != nil { 63 t.Fatalf("Error creating output file: %v.", err) 64 } 65 defer os.Remove(outFile) 66 logFile, err := createTempFile() 67 if err != nil { 68 t.Fatalf("Error creating log file: %v.", err) 69 } 70 defer os.Remove(logFile) 71 t.Logf("Logging benchmark output to %q.", logFile) 72 opts := &options{ 73 outputFile: outFile, 74 logFile: logFile, 75 goBinaryPath: *goBinaryPath, 76 passOnError: true, 77 // Omit benchmarks that aren't in the core group to keep test time reasonable. 78 benchRegexp: "Core", 79 } 80 81 t.Logf("Starting benchmarkjunit outputting to %q...", opts.outputFile) 82 run(opts, []string{"../../experiment/dummybenchmarks/..."}) 83 t.Log("Finished running benchmarkjunit. Validating JUnit XML...") 84 85 // Print log file contents. 86 rawLog, err := os.ReadFile(opts.logFile) 87 if err != nil { 88 t.Fatalf("Error reading log file: %v.", err) 89 } 90 t.Logf("Log file output:\n%s\n\n", string(rawLog)) 91 92 // Read and parse JUnit output. 93 raw, err := os.ReadFile(opts.outputFile) 94 if err != nil { 95 t.Fatalf("Error reading output file: %v.", err) 96 } 97 suites, err := junit.Parse(raw) 98 if err != nil { 99 t.Fatalf("Error parsing JUnit XML testsuites: %v.", err) 100 } 101 102 if len(suites.Suites) != 2 { 103 t.Fatalf("Expected 2 testsuites, but found %d.", len(suites.Suites)) 104 } 105 // Validate the main 'dummybenchmarks' suite 106 s := suites.Suites[0] 107 if base := path.Base(s.Name); base != "dummybenchmarks" { 108 t.Errorf("Expected testsuites[0] to have basename \"dummybenchmarks\", but got %q.", base) 109 } 110 expectedBenchmarks := []string{ 111 "BenchmarkCoreSimple", 112 "BenchmarkCoreAllocsAndBytes", 113 "BenchmarkCoreParallel", 114 "BenchmarkCoreLog", 115 "BenchmarkCoreSkip", 116 "BenchmarkCoreSkipNow", 117 "BenchmarkCoreError", 118 "BenchmarkCoreFatal", 119 "BenchmarkCoreFailNow", 120 "BenchmarkCoreNestedShallow/simple", 121 "BenchmarkCoreNestedShallow/parallel", 122 } 123 var allocsAndBytes junit.Result 124 var foundBenchmarks []string 125 for _, result := range s.Results { 126 // Remove the trailing "-\d+" 127 name := strings.Split(result.Name, "-")[0] 128 foundBenchmarks = append(foundBenchmarks, name) 129 130 if name == "BenchmarkCoreAllocsAndBytes" { 131 allocsAndBytes = result 132 } 133 } 134 sort.Strings(expectedBenchmarks) 135 sort.Strings(foundBenchmarks) 136 if !reflect.DeepEqual(expectedBenchmarks, foundBenchmarks) { 137 t.Errorf("Expected benchmarks %q, but got %q.", expectedBenchmarks, foundBenchmarks) 138 } 139 // Check that all properties exist on the AllocsAndBytes benchmark and that 140 // all parse to float64. (This is the only benchmark that has all properties.) 141 foundProps := make(map[string]string) 142 for _, prop := range allocsAndBytes.Properties.PropertyList { 143 if val, ok := foundProps[prop.Name]; ok { 144 t.Errorf("BenchmarkCoreAllocsAndBytes has duplicated property %q. Values: %q, %q.", prop.Name, val, prop.Value) 145 } 146 foundProps[prop.Name] = prop.Value 147 } 148 expectedProps := []string{ 149 "op count", 150 "avg op duration (ns/op)", 151 "MB/s", 152 "alloced B/op", 153 "allocs/op", 154 } 155 for _, expectedProp := range expectedProps { 156 value, ok := foundProps[expectedProp] 157 if !ok { 158 t.Errorf("BenchmarkCoreAllocsAndBytes is missing property %q.", expectedProp) 159 continue 160 } 161 if _, err := strconv.ParseFloat(value, 64); err != nil { 162 t.Errorf("Failed to parse the %q=%q property of BenchmarkCoreAllocsAndBytes: %v.", expectedProp, value, err) 163 } 164 } 165 166 // Validate the 'subpkg' suite. 167 s = suites.Suites[1] 168 if base := path.Base(s.Name); base != "subpkg" { 169 t.Errorf("Expected testsuites[1] to have basename \"subpkg\", but got %q.", base) 170 } 171 if len(s.Results) != 1 || !strings.HasPrefix(s.Results[0].Name, "BenchmarkCoreSubPkg") { 172 t.Errorf("Expected one \"BenchmarkCoreSubPkg\" result, but found %+v.", s.Results) 173 } 174 }