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  }