github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/cmd/roachtest/test_test.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package main 12 13 import ( 14 "bytes" 15 "context" 16 "io/ioutil" 17 "regexp" 18 "sort" 19 "strings" 20 "testing" 21 "time" 22 23 "github.com/cockroachdb/cockroach/pkg/testutils" 24 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 25 "github.com/cockroachdb/cockroach/pkg/util/version" 26 "github.com/kr/pretty" 27 ) 28 29 const OwnerUnitTest Owner = `unittest` 30 31 const defaultParallelism = 10 32 33 func TestMatchOrSkip(t *testing.T) { 34 testCases := []struct { 35 filter []string 36 name string 37 tags []string 38 expected bool 39 expectedSkip string 40 }{ 41 {nil, "foo", nil, true, ""}, 42 {nil, "foo", []string{"bar"}, true, "[tag:default] does not match [bar]"}, 43 {[]string{"tag:b"}, "foo", []string{"bar"}, true, ""}, 44 {[]string{"tag:b"}, "foo", nil, true, "[tag:b] does not match [default]"}, 45 {[]string{"tag:default"}, "foo", nil, true, ""}, 46 {[]string{"tag:f"}, "foo", []string{"bar"}, true, "[tag:f] does not match [bar]"}, 47 {[]string{"f"}, "foo", []string{"bar"}, true, "[tag:default] does not match [bar]"}, 48 {[]string{"f"}, "bar", []string{"bar"}, false, ""}, 49 {[]string{"f", "tag:b"}, "foo", []string{"bar"}, true, ""}, 50 {[]string{"f", "tag:f"}, "foo", []string{"bar"}, true, "[tag:f] does not match [bar]"}, 51 } 52 for _, c := range testCases { 53 t.Run("", func(t *testing.T) { 54 f := newFilter(c.filter) 55 spec := &testSpec{Name: c.name, Owner: OwnerUnitTest, Tags: c.tags} 56 if value := spec.matchOrSkip(f); c.expected != value { 57 t.Fatalf("expected %t, but found %t", c.expected, value) 58 } else if value && c.expectedSkip != spec.Skip { 59 t.Fatalf("expected %s, but found %s", c.expectedSkip, spec.Skip) 60 } 61 }) 62 } 63 } 64 65 func nilLogger() *logger { 66 lcfg := loggerConfig{ 67 stdout: ioutil.Discard, 68 stderr: ioutil.Discard, 69 } 70 l, err := lcfg.newLogger("" /* path */) 71 if err != nil { 72 panic(err) 73 } 74 return l 75 } 76 77 func TestRunnerRun(t *testing.T) { 78 ctx := context.Background() 79 r, err := makeTestRegistry() 80 if err != nil { 81 t.Fatal(err) 82 } 83 r.Add(testSpec{ 84 Name: "pass", 85 Owner: OwnerUnitTest, 86 Run: func(ctx context.Context, t *test, c *cluster) {}, 87 Cluster: makeClusterSpec(0), 88 }) 89 r.Add(testSpec{ 90 Name: "fail", 91 Owner: OwnerUnitTest, 92 Run: func(ctx context.Context, t *test, c *cluster) { 93 t.Fatal("failed") 94 }, 95 Cluster: makeClusterSpec(0), 96 }) 97 98 testCases := []struct { 99 filters []string 100 expErr string 101 }{ 102 {nil, "some tests failed"}, 103 {[]string{"pass"}, ""}, 104 {[]string{"fail"}, "some tests failed"}, 105 {[]string{"pass|fail"}, "some tests failed"}, 106 {[]string{"pass", "fail"}, "some tests failed"}, 107 {[]string{"notests"}, "no test"}, 108 } 109 for _, c := range testCases { 110 t.Run("", func(t *testing.T) { 111 tests := testsToRun(ctx, r, newFilter(c.filters)) 112 cr := newClusterRegistry() 113 runner := newTestRunner(cr, r.buildVersion) 114 115 lopt := loggingOpt{ 116 l: nilLogger(), 117 tee: noTee, 118 stdout: ioutil.Discard, 119 stderr: ioutil.Discard, 120 artifactsDir: "", 121 } 122 copt := clustersOpt{ 123 typ: roachprodCluster, 124 user: "test_user", 125 cpuQuota: 1000, 126 keepClustersOnTestFailure: false, 127 } 128 err := runner.Run(ctx, tests, 1, /* count */ 129 defaultParallelism, copt, "" /* artifactsDir */, lopt) 130 131 if !testutils.IsError(err, c.expErr) { 132 t.Fatalf("expected err: %q, but found %v. Filters: %s", c.expErr, err, c.filters) 133 } 134 }) 135 } 136 } 137 138 type syncedBuffer struct { 139 mu syncutil.Mutex 140 buf bytes.Buffer 141 } 142 143 func (b *syncedBuffer) Write(p []byte) (n int, err error) { 144 b.mu.Lock() 145 defer b.mu.Unlock() 146 return b.buf.Write(p) 147 } 148 149 func (b *syncedBuffer) String() string { 150 b.mu.Lock() 151 defer b.mu.Unlock() 152 return b.buf.String() 153 } 154 155 func TestRunnerTestTimeout(t *testing.T) { 156 ctx := context.Background() 157 158 cr := newClusterRegistry() 159 runner := newTestRunner(cr, version.Version{}) 160 161 var buf syncedBuffer 162 lopt := loggingOpt{ 163 l: nilLogger(), 164 tee: noTee, 165 stdout: &buf, 166 stderr: &buf, 167 artifactsDir: "", 168 } 169 copt := clustersOpt{ 170 typ: roachprodCluster, 171 user: "test_user", 172 cpuQuota: 1000, 173 keepClustersOnTestFailure: false, 174 } 175 test := testSpec{ 176 Name: `timeout`, 177 Owner: OwnerUnitTest, 178 Timeout: 10 * time.Millisecond, 179 Cluster: makeClusterSpec(0), 180 Run: func(ctx context.Context, t *test, c *cluster) { 181 <-ctx.Done() 182 }, 183 } 184 err := runner.Run(ctx, []testSpec{test}, 1, /* count */ 185 defaultParallelism, copt, "" /* artifactsDir */, lopt) 186 if !testutils.IsError(err, "some tests failed") { 187 t.Fatalf("expected error \"some tests failed\", got: %v", err) 188 } 189 190 out := buf.String() 191 timeoutRE := regexp.MustCompile(`(?m)^.*test timed out \(.*\)$`) 192 if !timeoutRE.MatchString(out) { 193 t.Fatalf("unable to find \"timed out\" message:\n%s", out) 194 } 195 } 196 197 func TestRegistryPrepareSpec(t *testing.T) { 198 dummyRun := func(context.Context, *test, *cluster) {} 199 200 var listTests = func(t *testSpec) []string { 201 return []string{t.Name} 202 } 203 204 testCases := []struct { 205 spec testSpec 206 expectedErr string 207 expectedTests []string 208 }{ 209 { 210 testSpec{ 211 Name: "a", 212 Owner: OwnerUnitTest, 213 Run: dummyRun, 214 Cluster: makeClusterSpec(0), 215 }, 216 "", 217 []string{"a"}, 218 }, 219 { 220 testSpec{ 221 Name: "a", 222 Owner: OwnerUnitTest, 223 MinVersion: "v2.1.0", 224 Run: dummyRun, 225 Cluster: makeClusterSpec(0), 226 }, 227 "", 228 []string{"a"}, 229 }, 230 { 231 testSpec{ 232 Name: "a", 233 Owner: OwnerUnitTest, 234 MinVersion: "foo", 235 Run: dummyRun, 236 Cluster: makeClusterSpec(0), 237 }, 238 "a: unable to parse min-version: invalid version string 'foo'", 239 nil, 240 }, 241 } 242 for _, c := range testCases { 243 t.Run("", func(t *testing.T) { 244 r, err := makeTestRegistry() 245 if err != nil { 246 t.Fatal(err) 247 } 248 err = r.prepareSpec(&c.spec) 249 if !testutils.IsError(err, c.expectedErr) { 250 t.Fatalf("expected %q, but found %q", c.expectedErr, err.Error()) 251 } 252 if c.expectedErr == "" { 253 tests := listTests(&c.spec) 254 sort.Strings(tests) 255 if diff := pretty.Diff(c.expectedTests, tests); len(diff) != 0 { 256 t.Fatalf("unexpected tests:\n%s", strings.Join(diff, "\n")) 257 } 258 } 259 }) 260 } 261 } 262 263 func TestRegistryMinVersion(t *testing.T) { 264 ctx := context.Background() 265 testCases := []struct { 266 buildVersion string 267 expectedA bool 268 expectedB bool 269 expErr string 270 }{ 271 {"v1.1.0", false, false, "no test matched filters"}, 272 {"v2.0.0", true, false, ""}, 273 {"v2.1.0", true, true, ""}, 274 } 275 for _, c := range testCases { 276 t.Run(c.buildVersion, func(t *testing.T) { 277 var runA, runB bool 278 r, err := makeTestRegistry() 279 if err != nil { 280 t.Fatal(err) 281 } 282 r.Add(testSpec{ 283 Name: "a", 284 Owner: OwnerUnitTest, 285 MinVersion: "v2.0.0", 286 Cluster: makeClusterSpec(0), 287 Run: func(ctx context.Context, t *test, c *cluster) { 288 runA = true 289 }, 290 }) 291 r.Add(testSpec{ 292 Name: "b", 293 Owner: OwnerUnitTest, 294 MinVersion: "v2.1.0", 295 Cluster: makeClusterSpec(0), 296 Run: func(ctx context.Context, t *test, c *cluster) { 297 runB = true 298 }, 299 }) 300 if err := r.setBuildVersion(c.buildVersion); err != nil { 301 t.Fatal(err) 302 } 303 tests := testsToRun(ctx, r, newFilter(nil)) 304 305 var buf syncedBuffer 306 lopt := loggingOpt{ 307 l: nilLogger(), 308 tee: noTee, 309 stdout: &buf, 310 stderr: &buf, 311 artifactsDir: "", 312 } 313 copt := clustersOpt{ 314 typ: roachprodCluster, 315 user: "test_user", 316 cpuQuota: 1000, 317 keepClustersOnTestFailure: false, 318 } 319 cr := newClusterRegistry() 320 runner := newTestRunner(cr, r.buildVersion) 321 err = runner.Run(ctx, tests, 1, /* count */ 322 defaultParallelism, copt, "" /* artifactsDir */, lopt) 323 if !testutils.IsError(err, c.expErr) { 324 t.Fatalf("expected err: %q, got: %v", c.expErr, err) 325 } 326 327 if c.expectedA != runA || c.expectedB != runB { 328 t.Fatalf("expected %t,%t, but got %t,%t\n%s", 329 c.expectedA, c.expectedB, runA, runB, buf.String()) 330 } 331 }) 332 } 333 }