codekingpro/portable-devtools
114k
1// Copyright 2023 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package rand_test6 7import (8 "fmt"9 "internal/race"10 "internal/testenv"11 . "math/rand"12 "os"13 "runtime"14 "strconv"15 "sync"16 "testing"17)18 19// Test that racy access to the default functions behaves reasonably.20func TestDefaultRace(t *testing.T) {21 // Skip the test in short mode, but even in short mode run22 // the test if we are using the race detector, because part23 // of this is to see whether the race detector reports any problems.24 if testing.Short() && !race.Enabled {25 t.Skip("skipping starting another executable in short mode")26 }27 28 const env = "GO_RAND_TEST_HELPER_CODE"29 if v := os.Getenv(env); v != "" {30 doDefaultTest(t, v)31 return32 }33 34 t.Parallel()35 36 for i := 0; i < 6; i++ {37 t.Run(strconv.Itoa(i), func(t *testing.T) {38 t.Parallel()39 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestDefaultRace$")40 cmd = testenv.CleanCmdEnv(cmd)41 cmd.Env = append(cmd.Env, fmt.Sprintf("GO_RAND_TEST_HELPER_CODE=%d", i/2))42 if i%2 != 0 {43 cmd.Env = append(cmd.Env, "GODEBUG=randautoseed=0")44 }45 out, err := cmd.CombinedOutput()46 if len(out) > 0 {47 t.Logf("%s", out)48 }49 if err != nil {50 t.Error(err)51 }52 })53 }54}55 56// doDefaultTest should be run before there have been any calls to the57// top-level math/rand functions. Make sure that we can make concurrent58// calls to top-level functions and to Seed without any duplicate values.59// This will also give the race detector a change to report any problems.60func doDefaultTest(t *testing.T, v string) {61 code, err := strconv.Atoi(v)62 if err != nil {63 t.Fatalf("internal error: unrecognized code %q", v)64 }65 66 goroutines := runtime.GOMAXPROCS(0)67 if goroutines < 4 {68 goroutines = 469 }70 71 ch := make(chan uint64, goroutines*3)72 var wg sync.WaitGroup73 74 // The various tests below should not cause race detector reports75 // and should not produce duplicate results.76 //77 // Note: these tests can theoretically fail when using fastrand6478 // in that it is possible to coincidentally get the same random79 // number twice. That could happen something like 1 / 2**64 times,80 // which is rare enough that it may never happen. We don't worry81 // about that case.82 83 switch code {84 case 0:85 // Call Seed and Uint64 concurrently.86 wg.Add(goroutines)87 for i := 0; i < goroutines; i++ {88 go func(s int64) {89 defer wg.Done()90 Seed(s)91 }(int64(i) + 100)92 }93 wg.Add(goroutines)94 for i := 0; i < goroutines; i++ {95 go func() {96 defer wg.Done()97 ch <- Uint64()98 }()99 }100 case 1:101 // Call Uint64 concurrently with no Seed.102 wg.Add(goroutines)103 for i := 0; i < goroutines; i++ {104 go func() {105 defer wg.Done()106 ch <- Uint64()107 }()108 }109 case 2:110 // Start with Uint64 to pick the fast source, then call111 // Seed and Uint64 concurrently.112 ch <- Uint64()113 wg.Add(goroutines)114 for i := 0; i < goroutines; i++ {115 go func(s int64) {116 defer wg.Done()117 Seed(s)118 }(int64(i) + 100)119 }120 wg.Add(goroutines)121 for i := 0; i < goroutines; i++ {122 go func() {123 defer wg.Done()124 ch <- Uint64()125 }()126 }127 default:128 t.Fatalf("internal error: unrecognized code %d", code)129 }130 131 go func() {132 wg.Wait()133 close(ch)134 }()135 136 m := make(map[uint64]bool)137 for i := range ch {138 if m[i] {139 t.Errorf("saw %d twice", i)140 }141 m[i] = true142 }143}144 