github.com/go-maxhub/gremlins@v1.0.1-0.20231227222204-b03a6a1e3e09/core/coverage/coverage_test.go (about) 1 /* 2 * Copyright 2022 The Gremlins 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 coverage_test 18 19 import ( 20 "fmt" 21 "os" 22 "os/exec" 23 "strings" 24 "testing" 25 26 "github.com/google/go-cmp/cmp" 27 "github.com/spf13/viper" 28 29 "github.com/go-maxhub/gremlins/core/coverage" 30 31 "github.com/go-maxhub/gremlins/core/configuration" 32 "github.com/go-maxhub/gremlins/core/gomodule" 33 ) 34 35 type commandHolder struct { 36 events []struct { 37 command string 38 args []string 39 } 40 } 41 42 func TestCoverageRun(t *testing.T) { 43 testCases := []struct { 44 name string 45 callPath string 46 wantPath string 47 intMode bool 48 }{ 49 { 50 name: "from root, normal mode", 51 callPath: ".", 52 wantPath: "./...", 53 intMode: false, 54 }, 55 { 56 name: "from folder, normal mode", 57 callPath: "test/pkg", 58 wantPath: "./test/pkg/...", 59 intMode: false, 60 }, 61 { 62 name: "from root, integration mode", 63 callPath: ".", 64 wantPath: "./...", 65 intMode: true, 66 }, 67 { 68 name: "from folder, integration mode", 69 callPath: "test/dir", 70 wantPath: "./...", 71 intMode: true, 72 }, 73 } 74 coverpkg := "./core/log,./pkg/..." 75 for _, tc := range testCases { 76 tc := tc 77 t.Run(tc.name, func(t *testing.T) { 78 viper.Set(configuration.UnleashTagsKey, "tag1 tag2") 79 viper.Set(configuration.UnleashCoverPkgKey, coverpkg) 80 viper.Set(configuration.UnleashIntegrationMode, tc.intMode) 81 defer viper.Reset() 82 83 wantWorkdir := "workdir" 84 wantFilename := "coverage" 85 wantFilePath := wantWorkdir + "/" + wantFilename 86 holder := &commandHolder{} 87 mod := gomodule.GoModule{ 88 Name: "example.com", 89 Root: ".", 90 CallingDir: tc.callPath, 91 } 92 cov := coverage.NewWithCmd(fakeExecCommandSuccess(holder), wantWorkdir, mod) 93 94 _, _ = cov.Run() 95 96 firstWant := "go mod download" 97 secondWant := fmt.Sprintf("go test -tags tag1 tag2 -coverpkg %s -cover -coverprofile %v %s", 98 coverpkg, wantFilePath, tc.wantPath) 99 100 if len(holder.events) != 2 { 101 t.Fatal("expected two commands to be executed") 102 } 103 firstGot := fmt.Sprintf("go %v", strings.Join(holder.events[0].args, " ")) 104 secondGot := fmt.Sprintf("go %v", strings.Join(holder.events[1].args, " ")) 105 106 if !cmp.Equal(firstGot, firstWant) { 107 t.Errorf(cmp.Diff(firstGot, firstWant)) 108 } 109 if !cmp.Equal(secondGot, secondWant) { 110 t.Errorf(cmp.Diff(secondGot, secondWant)) 111 } 112 }) 113 } 114 } 115 116 func TestCoverageRunFails(t *testing.T) { 117 mod := gomodule.GoModule{ 118 Name: "example.com", 119 CallingDir: "./...", 120 } 121 122 t.Run("failure of: go mod download", func(t *testing.T) { 123 cov := coverage.NewWithCmd(fakeExecCommandFailure(0), "workdir", mod) 124 if _, err := cov.Run(); err == nil { 125 t.Error("expected run to report an error") 126 } 127 }) 128 129 t.Run("failure of: go test", func(t *testing.T) { 130 cov := coverage.NewWithCmd(fakeExecCommandFailure(1), "workdir", mod) 131 if _, err := cov.Run(); err == nil { 132 t.Error("expected run to report an error") 133 } 134 }) 135 } 136 137 func TestCoverageParsesOutput(t *testing.T) { 138 module := "example.com" 139 mod := gomodule.GoModule{ 140 Name: module, 141 CallingDir: "path", 142 } 143 cov := coverage.NewWithCmd(fakeExecCommandSuccess(nil), "testdata/valid", mod) 144 profile := coverage.Profile{ 145 "file1.go": { 146 { 147 StartLine: 47, 148 StartCol: 2, 149 EndLine: 48, 150 EndCol: 16, 151 }, 152 }, 153 "file2.go": { 154 { 155 StartLine: 52, 156 StartCol: 2, 157 EndLine: 53, 158 EndCol: 16, 159 }, 160 }, 161 } 162 want := coverage.Result{ 163 Profile: profile, 164 } 165 166 got, err := cov.Run() 167 if err != nil { 168 t.Fatal(err) 169 } 170 171 if !cmp.Equal(got.Profile, want.Profile) { 172 t.Error(cmp.Diff(got, want)) 173 } 174 if got.Elapsed == 0 { 175 t.Errorf("expected elapsed time to be greater than 0") 176 } 177 } 178 179 func TestParseOutputFail(t *testing.T) { 180 mod := gomodule.GoModule{ 181 Name: "example.com", 182 CallingDir: "./...", 183 } 184 cov := coverage.NewWithCmd(fakeExecCommandSuccess(nil), "testdata/invalid", mod) 185 186 if _, err := cov.Run(); err == nil { 187 t.Errorf("espected an error") 188 } 189 } 190 191 func TestCoverageProcessSuccess(_ *testing.T) { 192 if os.Getenv("GO_TEST_PROCESS") != "1" { 193 return 194 } 195 os.Exit(0) // skipcq: RVV-A0003 196 } 197 198 func TestCoverageProcessFailure(_ *testing.T) { 199 if os.Getenv("GO_TEST_PROCESS") != "1" { 200 return 201 } 202 os.Exit(1) // skipcq: RVV-A0003 203 } 204 205 type execContext = func(name string, args ...string) *exec.Cmd 206 207 func fakeExecCommandSuccess(got *commandHolder) execContext { 208 return func(command string, args ...string) *exec.Cmd { 209 if got != nil { 210 got.events = append(got.events, struct { 211 command string 212 args []string 213 }{command: command, args: args}) 214 } 215 cs := []string{"-test.run=TestCoverageProcessSuccess", "--", command} 216 cs = append(cs, args...) 217 // #nosec G204 - We are in tests, we don't care 218 cmd := exec.Command(os.Args[0], cs...) 219 cmd.Env = []string{"GO_TEST_PROCESS=1"} 220 221 return cmd 222 } 223 } 224 225 func fakeExecCommandFailure(run int) execContext { 226 var executed int 227 228 return func(command string, args ...string) *exec.Cmd { 229 cs := []string{"-test.run=TestCoverageProcessSuccess", "--", command} 230 if executed == run { 231 cs = []string{"-test.run=TestCoverageProcessFailure", "--", command} 232 } 233 cs = append(cs, args...) 234 // #nosec G204 - We are in tests, we don't care 235 cmd := exec.Command(os.Args[0], cs...) 236 cmd.Env = []string{"GO_TEST_PROCESS=1"} 237 executed++ 238 239 return cmd 240 } 241 }