From fcc6d71be2c3ce7d9305c04fc2e87af554571bac Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 22 Feb 2021 20:37:25 +0100 Subject: go.mod: update golangci-lint to v1.37 --- vendor/github.com/moricho/tparallel/.gitignore | 3 + .../github.com/moricho/tparallel/.goreleaser.yml | 38 ++++++++ vendor/github.com/moricho/tparallel/LICENSE | 21 +++++ vendor/github.com/moricho/tparallel/Makefile | 13 +++ vendor/github.com/moricho/tparallel/README.md | 100 +++++++++++++++++++++ vendor/github.com/moricho/tparallel/go.mod | 8 ++ vendor/github.com/moricho/tparallel/go.sum | 34 +++++++ .../moricho/tparallel/pkg/ssafunc/ssafunc.go | 34 +++++++ .../moricho/tparallel/pkg/ssainstr/ssainstr.go | 63 +++++++++++++ vendor/github.com/moricho/tparallel/testmap.go | 63 +++++++++++++ vendor/github.com/moricho/tparallel/tparallel.go | 72 +++++++++++++++ 11 files changed, 449 insertions(+) create mode 100644 vendor/github.com/moricho/tparallel/.gitignore create mode 100644 vendor/github.com/moricho/tparallel/.goreleaser.yml create mode 100644 vendor/github.com/moricho/tparallel/LICENSE create mode 100644 vendor/github.com/moricho/tparallel/Makefile create mode 100644 vendor/github.com/moricho/tparallel/README.md create mode 100644 vendor/github.com/moricho/tparallel/go.mod create mode 100644 vendor/github.com/moricho/tparallel/go.sum create mode 100644 vendor/github.com/moricho/tparallel/pkg/ssafunc/ssafunc.go create mode 100644 vendor/github.com/moricho/tparallel/pkg/ssainstr/ssainstr.go create mode 100644 vendor/github.com/moricho/tparallel/testmap.go create mode 100644 vendor/github.com/moricho/tparallel/tparallel.go (limited to 'vendor/github.com/moricho') diff --git a/vendor/github.com/moricho/tparallel/.gitignore b/vendor/github.com/moricho/tparallel/.gitignore new file mode 100644 index 000000000..71342280e --- /dev/null +++ b/vendor/github.com/moricho/tparallel/.gitignore @@ -0,0 +1,3 @@ +/tparallel +.envrc +/dist diff --git a/vendor/github.com/moricho/tparallel/.goreleaser.yml b/vendor/github.com/moricho/tparallel/.goreleaser.yml new file mode 100644 index 000000000..e9f6d727e --- /dev/null +++ b/vendor/github.com/moricho/tparallel/.goreleaser.yml @@ -0,0 +1,38 @@ +project_name: tparallel +env: + - GO111MODULE=on +before: + hooks: + - go mod tidy +builds: + - main: ./cmd/tparallel + binary: tparallel + ldflags: + - -s -w + - -X main.Version={{.Version}} + - -X main.Revision={{.ShortCommit}} + env: + - CGO_ENABLED=0 +archives: + - name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' + replacements: + darwin: darwin + linux: linux + windows: windows + 386: i386 + amd64: x86_64 + format_overrides: + - goos: windows + format: zip +release: + prerelease: auto +brews: + - tap: + owner: moricho + name: homebrew-tparallel + homepage: https://github.com/moricho/tparallel + description: tparallel detects inappropriate usage of t.Parallel() method in your Go test codes + install: | + bin.install "tparallel" + test: | + system "#{bin}/goreleaser -v" diff --git a/vendor/github.com/moricho/tparallel/LICENSE b/vendor/github.com/moricho/tparallel/LICENSE new file mode 100644 index 000000000..4f029982f --- /dev/null +++ b/vendor/github.com/moricho/tparallel/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 moricho + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/moricho/tparallel/Makefile b/vendor/github.com/moricho/tparallel/Makefile new file mode 100644 index 000000000..fb3588069 --- /dev/null +++ b/vendor/github.com/moricho/tparallel/Makefile @@ -0,0 +1,13 @@ +all: build + +.PHONY: build +build: + go build -o tparallel ./cmd/tparallel + +.PHONY: build_race +build_race: + go build -race -o tparallel ./cmd/tparallel + +.PHONY: test +test: build_race + go test -v ./... diff --git a/vendor/github.com/moricho/tparallel/README.md b/vendor/github.com/moricho/tparallel/README.md new file mode 100644 index 000000000..cd358d155 --- /dev/null +++ b/vendor/github.com/moricho/tparallel/README.md @@ -0,0 +1,100 @@ +# tparallel +[![tparallel](https://github.com/moricho/tparallel/workflows/tparallel/badge.svg?branch=master)](https://github.com/moricho/tparallel/actions) +[![Go Report Card](https://goreportcard.com/badge/github.com/moricho/tparallel)](https://goreportcard.com/report/github.com/moricho/tparallel) +[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE) + +`tparallel` finds inappropriate usage of `t.Parallel()` method in your Go test codes. +It detects the following: +- `t.Parallel()` is called in either a top-level test function or a sub-test function only +- Although `t.Parallel()` is called in the sub-test function, it is post-processed by `defer` instead of `t.Cleanup()` + +This tool was inspired by this blog: [Go言語でのテストの並列化 〜t.Parallel()メソッドを理解する〜](https://engineering.mercari.com/blog/entry/how_to_use_t_parallel/) + +## Installation + +### From GitHub Releases +Please see [GitHub Releases](https://github.com/moricho/tparallel/releases). +Available binaries are: +- macOS +- Linux +- Windows + +### macOS +``` sh +$ brew tap moricho/tparallel +$ brew install tparallel +``` + +### go get +```sh +$ go get -u github.com/moricho/tparallel/cmd/tparallel +``` + +## Usage + +```sh +$ go vet -vettool=`which tparallel` +``` + +## Example + +```go +package sample + +import ( + "testing" +) + +func Test_Table1(t *testing.T) { + teardown := setup("Test_Table1") + defer teardown() + + tests := []struct { + name string + }{ + { + name: "Table1_Sub1", + }, + { + name: "Table1_Sub2", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + call(tt.name) + }) + } +} + +func Test_Table2(t *testing.T) { + teardown := setup("Test_Table2") + t.Cleanup(teardown) + t.Parallel() + + tests := []struct { + name string + }{ + { + name: "Table2_Sub1", + }, + { + name: "Table2_Sub2", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + call(tt.name) + }) + } +} +``` + +```console +# github.com/moricho/tparallel/testdata/src/sample +testdata/src/sample/table_test.go:7:6: Test_Table1 should use t.Cleanup +testdata/src/sample/table_test.go:7:6: Test_Table1 should call t.Parallel on the top level as well as its subtests +testdata/src/sample/table_test.go:30:6: Test_Table2's subtests should call t.Parallel +``` diff --git a/vendor/github.com/moricho/tparallel/go.mod b/vendor/github.com/moricho/tparallel/go.mod new file mode 100644 index 000000000..9947ccb60 --- /dev/null +++ b/vendor/github.com/moricho/tparallel/go.mod @@ -0,0 +1,8 @@ +module github.com/moricho/tparallel + +go 1.15 + +require ( + github.com/gostaticanalysis/analysisutil v0.1.0 + golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65 +) diff --git a/vendor/github.com/moricho/tparallel/go.sum b/vendor/github.com/moricho/tparallel/go.sum new file mode 100644 index 000000000..bcc4158da --- /dev/null +++ b/vendor/github.com/moricho/tparallel/go.sum @@ -0,0 +1,34 @@ +github.com/gostaticanalysis/analysisutil v0.1.0 h1:E4c8Y1EQURbBEAHoXc/jBTK7Np14ArT8NPUiSFOl9yc= +github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= +github.com/gostaticanalysis/comment v1.3.0 h1:wTVgynbFu8/nz6SGgywA0TcyIoAVsYc7ai/Zp5xNGlw= +github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65 h1:DajXNh69ob79PCQz1N7OHxmqq6ASZC5xAnJJWIQGR6I= +golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/moricho/tparallel/pkg/ssafunc/ssafunc.go b/vendor/github.com/moricho/tparallel/pkg/ssafunc/ssafunc.go new file mode 100644 index 000000000..5a8e637bd --- /dev/null +++ b/vendor/github.com/moricho/tparallel/pkg/ssafunc/ssafunc.go @@ -0,0 +1,34 @@ +package ssafunc + +import ( + "go/types" + + "github.com/gostaticanalysis/analysisutil" + "github.com/moricho/tparallel/pkg/ssainstr" + "golang.org/x/tools/go/ssa" +) + +// IsDeferCalled returns whether the given ssa.Function calls `defer` +func IsDeferCalled(f *ssa.Function) bool { + for _, block := range f.Blocks { + for _, instr := range block.Instrs { + switch instr.(type) { + case *ssa.Defer: + return true + } + } + } + return false +} + +// IsCalled returns whether the given ssa.Function calls `fn` func +func IsCalled(f *ssa.Function, fn *types.Func) bool { + block := f.Blocks[0] + for _, instr := range block.Instrs { + called := analysisutil.Called(instr, nil, fn) + if _, ok := ssainstr.LookupCalled(instr, fn); ok || called { + return true + } + } + return false +} diff --git a/vendor/github.com/moricho/tparallel/pkg/ssainstr/ssainstr.go b/vendor/github.com/moricho/tparallel/pkg/ssainstr/ssainstr.go new file mode 100644 index 000000000..374553f5e --- /dev/null +++ b/vendor/github.com/moricho/tparallel/pkg/ssainstr/ssainstr.go @@ -0,0 +1,63 @@ +package ssainstr + +import ( + "go/types" + + "github.com/gostaticanalysis/analysisutil" + "golang.org/x/tools/go/ssa" +) + +// LookupCalled looks up ssa.Instruction that call the `fn` func in the given instr +func LookupCalled(instr ssa.Instruction, fn *types.Func) ([]ssa.Instruction, bool) { + instrs := []ssa.Instruction{} + + call, ok := instr.(ssa.CallInstruction) + if !ok { + return instrs, false + } + + ssaCall := call.Value() + if ssaCall == nil { + return instrs, false + } + common := ssaCall.Common() + if common == nil { + return instrs, false + } + val := common.Value + + called := false + switch fnval := val.(type) { + case *ssa.Function: + for _, block := range fnval.Blocks { + for _, instr := range block.Instrs { + if analysisutil.Called(instr, nil, fn) { + called = true + instrs = append(instrs, instr) + } + } + } + } + + return instrs, called +} + +// HasArgs returns whether the given ssa.Instruction has `typ` type args +func HasArgs(instr ssa.Instruction, typ types.Type) bool { + call, ok := instr.(ssa.CallInstruction) + if !ok { + return false + } + + ssaCall := call.Value() + if ssaCall == nil { + return false + } + + for _, arg := range ssaCall.Call.Args { + if types.Identical(arg.Type(), typ) { + return true + } + } + return false +} diff --git a/vendor/github.com/moricho/tparallel/testmap.go b/vendor/github.com/moricho/tparallel/testmap.go new file mode 100644 index 000000000..fa9bed708 --- /dev/null +++ b/vendor/github.com/moricho/tparallel/testmap.go @@ -0,0 +1,63 @@ +package tparallel + +import ( + "go/types" + "strings" + + "github.com/gostaticanalysis/analysisutil" + "golang.org/x/tools/go/analysis/passes/buildssa" + "golang.org/x/tools/go/ssa" + + "github.com/moricho/tparallel/pkg/ssainstr" +) + +// getTestMap gets a set of a top-level test and its sub-tests +func getTestMap(ssaanalyzer *buildssa.SSA, testTyp types.Type) map[*ssa.Function][]*ssa.Function { + testMap := map[*ssa.Function][]*ssa.Function{} + + trun := analysisutil.MethodOf(testTyp, "Run") + for _, f := range ssaanalyzer.SrcFuncs { + if !strings.HasPrefix(f.Name(), "Test") || !(f.Parent() == (*ssa.Function)(nil)) { + continue + } + testMap[f] = []*ssa.Function{} + for _, block := range f.Blocks { + for _, instr := range block.Instrs { + called := analysisutil.Called(instr, nil, trun) + + if !called && ssainstr.HasArgs(instr, types.NewPointer(testTyp)) { + if instrs, ok := ssainstr.LookupCalled(instr, trun); ok { + for _, v := range instrs { + testMap[f] = appendTestMap(testMap[f], v) + } + } + } else if called { + testMap[f] = appendTestMap(testMap[f], instr) + } + } + } + } + + return testMap +} + +// appendTestMap converts ssa.Instruction to ssa.Function and append it to a given sub-test slice +func appendTestMap(subtests []*ssa.Function, instr ssa.Instruction) []*ssa.Function { + call, ok := instr.(ssa.CallInstruction) + if !ok { + return subtests + } + + ssaCall := call.Value() + for _, arg := range ssaCall.Call.Args { + switch arg := arg.(type) { + case *ssa.Function: + subtests = append(subtests, arg) + case *ssa.MakeClosure: + fn, _ := arg.Fn.(*ssa.Function) + subtests = append(subtests, fn) + } + } + + return subtests +} diff --git a/vendor/github.com/moricho/tparallel/tparallel.go b/vendor/github.com/moricho/tparallel/tparallel.go new file mode 100644 index 000000000..3139e0425 --- /dev/null +++ b/vendor/github.com/moricho/tparallel/tparallel.go @@ -0,0 +1,72 @@ +package tparallel + +import ( + "go/types" + + "github.com/gostaticanalysis/analysisutil" + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/buildssa" + + "github.com/moricho/tparallel/pkg/ssafunc" +) + +const doc = "tparallel detects inappropriate usage of t.Parallel() method in your Go test codes." + +// Analyzer analyzes Go test codes whether they use t.Parallel() appropriately +// by using SSA (Single Static Assignment) +var Analyzer = &analysis.Analyzer{ + Name: "tparallel", + Doc: doc, + Run: run, + Requires: []*analysis.Analyzer{ + buildssa.Analyzer, + }, +} + +func run(pass *analysis.Pass) (interface{}, error) { + ssaanalyzer := pass.ResultOf[buildssa.Analyzer].(*buildssa.SSA) + + obj := analysisutil.ObjectOf(pass, "testing", "T") + if obj == nil { + // skip checking + return nil, nil + } + testTyp, testPkg := obj.Type(), obj.Pkg() + + p, _, _ := types.LookupFieldOrMethod(testTyp, true, testPkg, "Parallel") + parallel, _ := p.(*types.Func) + c, _, _ := types.LookupFieldOrMethod(testTyp, true, testPkg, "Cleanup") + cleanup, _ := c.(*types.Func) + + testMap := getTestMap(ssaanalyzer, testTyp) // ex. {Test1: [TestSub1, TestSub2], Test2: [TestSub1, TestSub2, TestSub3], ...} + for top, subs := range testMap { + if len(subs) == 0 { + continue + } + isParallelTop := ssafunc.IsCalled(top, parallel) + isPararellSub := false + for _, sub := range subs { + isPararellSub = ssafunc.IsCalled(sub, parallel) + if isPararellSub { + break + } + } + + if ssafunc.IsDeferCalled(top) { + useCleanup := ssafunc.IsCalled(top, cleanup) + if isPararellSub && !useCleanup { + pass.Reportf(top.Pos(), "%s should use t.Cleanup instead of defer", top.Name()) + } + } + + if isParallelTop == isPararellSub { + continue + } else if isPararellSub { + pass.Reportf(top.Pos(), "%s should call t.Parallel on the top level as well as its subtests", top.Name()) + } else if isParallelTop { + pass.Reportf(top.Pos(), "%s's subtests should call t.Parallel", top.Name()) + } + } + + return nil, nil +} -- cgit mrf-deployment