github.com/v2fly/tools@v0.100.0/internal/lsp/regtest/regtest.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package regtest 6 7 import ( 8 "context" 9 "flag" 10 "fmt" 11 "io/ioutil" 12 "os" 13 "runtime" 14 "testing" 15 "time" 16 17 "github.com/v2fly/tools/internal/lsp/cmd" 18 "github.com/v2fly/tools/internal/lsp/source" 19 "github.com/v2fly/tools/internal/testenv" 20 "github.com/v2fly/tools/internal/tool" 21 ) 22 23 var ( 24 runSubprocessTests = flag.Bool("enable_gopls_subprocess_tests", false, "run regtests against a gopls subprocess") 25 goplsBinaryPath = flag.String("gopls_test_binary", "", "path to the gopls binary for use as a remote, for use with the -enable_gopls_subprocess_tests flag") 26 regtestTimeout = flag.Duration("regtest_timeout", 20*time.Second, "default timeout for each regtest") 27 skipCleanup = flag.Bool("regtest_skip_cleanup", false, "whether to skip cleaning up temp directories") 28 printGoroutinesOnFailure = flag.Bool("regtest_print_goroutines", false, "whether to print goroutines info on failure") 29 ) 30 31 var runner *Runner 32 33 type regtestRunner interface { 34 Run(t *testing.T, files string, f TestFunc) 35 } 36 37 func Run(t *testing.T, files string, f TestFunc) { 38 runner.Run(t, files, f) 39 } 40 41 func WithOptions(opts ...RunOption) configuredRunner { 42 return configuredRunner{opts: opts} 43 } 44 45 type configuredRunner struct { 46 opts []RunOption 47 } 48 49 func (r configuredRunner) Run(t *testing.T, files string, f TestFunc) { 50 runner.Run(t, files, f, r.opts...) 51 } 52 53 type RunMultiple []struct { 54 Name string 55 Runner regtestRunner 56 } 57 58 func (r RunMultiple) Run(t *testing.T, files string, f TestFunc) { 59 for _, runner := range r { 60 t.Run(runner.Name, func(t *testing.T) { 61 runner.Runner.Run(t, files, f) 62 }) 63 } 64 } 65 66 // The regtests run significantly slower on these operating systems, due to (we 67 // believe) kernel locking behavior. Only run in singleton mode on these 68 // operating system when using -short. 69 var slowGOOS = map[string]bool{ 70 "darwin": true, 71 "openbsd": true, 72 "plan9": true, 73 } 74 75 func DefaultModes() Mode { 76 normal := Singleton | Experimental 77 if slowGOOS[runtime.GOOS] && testing.Short() { 78 normal = Singleton 79 } 80 if *runSubprocessTests { 81 return normal | SeparateProcess 82 } 83 return normal 84 } 85 86 // Main sets up and tears down the shared regtest state. 87 func Main(m *testing.M, hook func(*source.Options)) { 88 testenv.ExitIfSmallMachine() 89 90 // Disable GOPACKAGESDRIVER, as it can cause spurious test failures. 91 os.Setenv("GOPACKAGESDRIVER", "off") 92 93 flag.Parse() 94 if os.Getenv("_GOPLS_TEST_BINARY_RUN_AS_GOPLS") == "true" { 95 tool.Main(context.Background(), cmd.New("gopls", "", nil, nil), os.Args[1:]) 96 os.Exit(0) 97 } 98 99 runner = &Runner{ 100 DefaultModes: DefaultModes(), 101 Timeout: *regtestTimeout, 102 PrintGoroutinesOnFailure: *printGoroutinesOnFailure, 103 SkipCleanup: *skipCleanup, 104 OptionsHook: hook, 105 } 106 if *runSubprocessTests { 107 goplsPath := *goplsBinaryPath 108 if goplsPath == "" { 109 var err error 110 goplsPath, err = os.Executable() 111 if err != nil { 112 panic(fmt.Sprintf("finding test binary path: %v", err)) 113 } 114 } 115 runner.GoplsPath = goplsPath 116 } 117 dir, err := ioutil.TempDir("", "gopls-regtest-") 118 if err != nil { 119 panic(fmt.Errorf("creating regtest temp directory: %v", err)) 120 } 121 runner.TempDir = dir 122 123 code := m.Run() 124 if err := runner.Close(); err != nil { 125 fmt.Fprintf(os.Stderr, "closing test runner: %v\n", err) 126 // Regtest cleanup is broken in go1.12 and earlier, and sometimes flakes on 127 // Windows due to file locking, but this is OK for our CI. 128 // 129 // Fail on go1.13+, except for windows and android which have shutdown problems. 130 if testenv.Go1Point() >= 13 && runtime.GOOS != "windows" && runtime.GOOS != "android" { 131 os.Exit(1) 132 } 133 } 134 os.Exit(code) 135 }