From b2f2446b46bf02821d90ebedadae2bf7ae0e880e Mon Sep 17 00:00:00 2001 From: Taras Madan Date: Mon, 5 Sep 2022 14:27:54 +0200 Subject: go.mod, vendor: update (#3358) * go.mod, vendor: remove unnecessary dependencies Commands: 1. go mod tidy 2. go mod vendor * go.mod, vendor: update cloud.google.com/go Commands: 1. go get -u cloud.google.com/go 2. go mod tidy 3. go mod vendor * go.mod, vendor: update cloud.google.com/* Commands: 1. go get -u cloud.google.com/storage cloud.google.com/logging 2. go mod tidy 3. go mod vendor * go.mod, .golangci.yml, vendor: update *lint* Commands: 1. go get -u golang.org/x/tools github.com/golangci/golangci-lint@v1.47.0 2. go mod tidy 3. go mod vendor 4. edit .golangci.yml to suppress new errors (resolved in the same PR later) * all: fix lint errors hash.go: copy() recommended by gosimple parse.go: ent is never nil verifier.go: signal.Notify() with unbuffered channel is bad. Have no idea why. * .golangci.yml: adjust godot rules check-all is deprecated, but still work if you're hesitating too - I'll remove this commit --- vendor/github.com/kunwardeep/paralleltest/LICENSE | 2 +- .../paralleltest/pkg/paralleltest/paralleltest.go | 226 ++++++++++++--------- 2 files changed, 126 insertions(+), 102 deletions(-) (limited to 'vendor/github.com/kunwardeep') diff --git a/vendor/github.com/kunwardeep/paralleltest/LICENSE b/vendor/github.com/kunwardeep/paralleltest/LICENSE index d06a809c2..77f0d26a6 100644 --- a/vendor/github.com/kunwardeep/paralleltest/LICENSE +++ b/vendor/github.com/kunwardeep/paralleltest/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Isaev Denis +Copyright (c) 2020 Kunwardeep Bedi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/kunwardeep/paralleltest/pkg/paralleltest/paralleltest.go b/vendor/github.com/kunwardeep/paralleltest/pkg/paralleltest/paralleltest.go index 31f6f2946..c7da52a20 100644 --- a/vendor/github.com/kunwardeep/paralleltest/pkg/paralleltest/paralleltest.go +++ b/vendor/github.com/kunwardeep/paralleltest/pkg/paralleltest/paralleltest.go @@ -1,7 +1,9 @@ package paralleltest import ( + "flag" "go/ast" + "go/types" "strings" "golang.org/x/tools/go/analysis" @@ -14,16 +16,28 @@ It also checks that the t.Parallel is used if multiple tests cases are run as pa As part of ensuring parallel tests works as expected it checks for reinitialising of the range value over the test cases.(https://tinyurl.com/y6555cy6)` -func NewAnalyzer() *analysis.Analyzer { - return &analysis.Analyzer{ - Name: "paralleltest", - Doc: Doc, - Run: run, - Requires: []*analysis.Analyzer{inspect.Analyzer}, - } +var Analyzer = &analysis.Analyzer{ + Name: "paralleltest", + Doc: Doc, + Run: run, + Flags: flags(), + Requires: []*analysis.Analyzer{inspect.Analyzer}, +} + +const ignoreMissingFlag = "i" + +func flags() flag.FlagSet { + options := flag.NewFlagSet("", flag.ExitOnError) + options.Bool(ignoreMissingFlag, false, "ignore missing calls to t.Parallel") + return *options } +type boolValue bool + func run(pass *analysis.Pass) (interface{}, error) { + + ignoreMissing := pass.Analyzer.Flags.Lookup(ignoreMissingFlag).Value.(flag.Getter).Get().(bool) + inspector := inspector.New(pass.Files) nodeFilter := []ast.Node{ @@ -34,15 +48,15 @@ func run(pass *analysis.Pass) (interface{}, error) { funcDecl := node.(*ast.FuncDecl) var funcHasParallelMethod, rangeStatementOverTestCasesExists, - rangeStatementHasParallelMethod, - testLoopVariableReinitialised bool - var testRunLoopIdentifier string + rangeStatementHasParallelMethod bool + var loopVariableUsedInRun *string var numberOfTestRun int var positionOfTestRunNode []ast.Node var rangeNode ast.Node // Check runs for test functions only - if !isTestFunction(funcDecl) { + isTest, testVar := isTestFunction(funcDecl) + if !isTest { return } @@ -51,18 +65,21 @@ func run(pass *analysis.Pass) (interface{}, error) { case *ast.ExprStmt: ast.Inspect(v, func(n ast.Node) bool { - // Check if the test method is calling t.parallel + // Check if the test method is calling t.Parallel if !funcHasParallelMethod { - funcHasParallelMethod = methodParallelIsCalledInTestFunction(n) + funcHasParallelMethod = methodParallelIsCalledInTestFunction(n, testVar) } - // Check if the t.Run within the test function is calling t.parallel - if methodRunIsCalledInTestFunction(n) { + // Check if the t.Run within the test function is calling t.Parallel + if methodRunIsCalledInTestFunction(n, testVar) { + // n is a call to t.Run; find out the name of the subtest's *testing.T parameter. + innerTestVar := getRunCallbackParameterName(n) + hasParallel := false numberOfTestRun++ ast.Inspect(v, func(p ast.Node) bool { if !hasParallel { - hasParallel = methodParallelIsCalledInTestFunction(p) + hasParallel = methodParallelIsCalledInTestFunction(p, innerTestVar) } return true }) @@ -73,59 +90,63 @@ func run(pass *analysis.Pass) (interface{}, error) { return true }) - // Check if the range over testcases is calling t.parallel + // Check if the range over testcases is calling t.Parallel case *ast.RangeStmt: rangeNode = v + var loopVars []types.Object + for _, expr := range []ast.Expr{v.Key, v.Value} { + if id, ok := expr.(*ast.Ident); ok { + loopVars = append(loopVars, pass.TypesInfo.ObjectOf(id)) + } + } + ast.Inspect(v, func(n ast.Node) bool { // nolint: gocritic switch r := n.(type) { case *ast.ExprStmt: - if methodRunIsCalledInRangeStatement(r.X) { + if methodRunIsCalledInRangeStatement(r.X, testVar) { + // r.X is a call to t.Run; find out the name of the subtest's *testing.T parameter. + innerTestVar := getRunCallbackParameterName(r.X) + rangeStatementOverTestCasesExists = true - testRunLoopIdentifier = methodRunFirstArgumentObjectName(r.X) if !rangeStatementHasParallelMethod { - rangeStatementHasParallelMethod = methodParallelIsCalledInMethodRun(r.X) + rangeStatementHasParallelMethod = methodParallelIsCalledInMethodRun(r.X, innerTestVar) + } + + if loopVariableUsedInRun == nil { + if run, ok := r.X.(*ast.CallExpr); ok { + loopVariableUsedInRun = loopVarReferencedInRun(run, loopVars, pass.TypesInfo) + } } } } return true }) - - // Check for the range loop value identifier re assignment - // More info here https://gist.github.com/kunwardeep/80c2e9f3d3256c894898bae82d9f75d0 - if rangeStatementOverTestCasesExists { - var rangeValueIdentifier string - if i, ok := v.Value.(*ast.Ident); ok { - rangeValueIdentifier = i.Name - } - - testLoopVariableReinitialised = testCaseLoopVariableReinitialised(v.Body.List, rangeValueIdentifier, testRunLoopIdentifier) - } } } - if !funcHasParallelMethod { + if !ignoreMissing && !funcHasParallelMethod { pass.Reportf(node.Pos(), "Function %s missing the call to method parallel\n", funcDecl.Name.Name) } if rangeStatementOverTestCasesExists && rangeNode != nil { if !rangeStatementHasParallelMethod { - pass.Reportf(rangeNode.Pos(), "Range statement for test %s missing the call to method parallel in test Run\n", funcDecl.Name.Name) - } else { - if testRunLoopIdentifier == "" { - pass.Reportf(rangeNode.Pos(), "Range statement for test %s does not use range value in test Run\n", funcDecl.Name.Name) - } else if !testLoopVariableReinitialised { - pass.Reportf(rangeNode.Pos(), "Range statement for test %s does not reinitialise the variable %s\n", funcDecl.Name.Name, testRunLoopIdentifier) + if !ignoreMissing { + pass.Reportf(rangeNode.Pos(), "Range statement for test %s missing the call to method parallel in test Run\n", funcDecl.Name.Name) } + } else if loopVariableUsedInRun != nil { + pass.Reportf(rangeNode.Pos(), "Range statement for test %s does not reinitialise the variable %s\n", funcDecl.Name.Name, *loopVariableUsedInRun) } } // Check if the t.Run is more than one as there is no point making one test parallel - if numberOfTestRun > 1 && len(positionOfTestRunNode) > 0 { - for _, n := range positionOfTestRunNode { - pass.Reportf(n.Pos(), "Function %s has missing the call to method parallel in the test run\n", funcDecl.Name.Name) + if !ignoreMissing { + if numberOfTestRun > 1 && len(positionOfTestRunNode) > 0 { + for _, n := range positionOfTestRunNode { + pass.Reportf(n.Pos(), "Function %s has missing the call to method parallel in the test run\n", funcDecl.Name.Name) + } } } }) @@ -133,39 +154,7 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } -func testCaseLoopVariableReinitialised(statements []ast.Stmt, rangeValueIdentifier string, testRunLoopIdentifier string) bool { - if len(statements) > 1 { - for _, s := range statements { - leftIdentifier, rightIdentifier := getLeftAndRightIdentifier(s) - if leftIdentifier == testRunLoopIdentifier && rightIdentifier == rangeValueIdentifier { - return true - } - } - } - return false -} - -// Return the left hand side and the right hand side identifiers name -func getLeftAndRightIdentifier(s ast.Stmt) (string, string) { - var leftIdentifier, rightIdentifier string - // nolint: gocritic - switch v := s.(type) { - case *ast.AssignStmt: - if len(v.Rhs) == 1 { - if i, ok := v.Rhs[0].(*ast.Ident); ok { - rightIdentifier = i.Name - } - } - if len(v.Lhs) == 1 { - if i, ok := v.Lhs[0].(*ast.Ident); ok { - leftIdentifier = i.Name - } - } - } - return leftIdentifier, rightIdentifier -} - -func methodParallelIsCalledInMethodRun(node ast.Node) bool { +func methodParallelIsCalledInMethodRun(node ast.Node, testVar string) bool { var methodParallelCalled bool // nolint: gocritic switch callExp := node.(type) { @@ -174,7 +163,7 @@ func methodParallelIsCalledInMethodRun(node ast.Node) bool { if !methodParallelCalled { ast.Inspect(arg, func(n ast.Node) bool { if !methodParallelCalled { - methodParallelCalled = methodParallelIsCalledInRunMethod(n) + methodParallelCalled = methodParallelIsCalledInRunMethod(n, testVar) return true } return false @@ -185,60 +174,74 @@ func methodParallelIsCalledInMethodRun(node ast.Node) bool { return methodParallelCalled } -func methodParallelIsCalledInRunMethod(node ast.Node) bool { - return exprCallHasMethod(node, "Parallel") +func methodParallelIsCalledInRunMethod(node ast.Node, testVar string) bool { + return exprCallHasMethod(node, testVar, "Parallel") } -func methodParallelIsCalledInTestFunction(node ast.Node) bool { - return exprCallHasMethod(node, "Parallel") +func methodParallelIsCalledInTestFunction(node ast.Node, testVar string) bool { + return exprCallHasMethod(node, testVar, "Parallel") } -func methodRunIsCalledInRangeStatement(node ast.Node) bool { - return exprCallHasMethod(node, "Run") +func methodRunIsCalledInRangeStatement(node ast.Node, testVar string) bool { + return exprCallHasMethod(node, testVar, "Run") } -func methodRunIsCalledInTestFunction(node ast.Node) bool { - return exprCallHasMethod(node, "Run") +func methodRunIsCalledInTestFunction(node ast.Node, testVar string) bool { + return exprCallHasMethod(node, testVar, "Run") } -func exprCallHasMethod(node ast.Node, methodName string) bool { +func exprCallHasMethod(node ast.Node, receiverName, methodName string) bool { // nolint: gocritic switch n := node.(type) { case *ast.CallExpr: if fun, ok := n.Fun.(*ast.SelectorExpr); ok { - return fun.Sel.Name == methodName + if receiver, ok := fun.X.(*ast.Ident); ok { + return receiver.Name == receiverName && fun.Sel.Name == methodName + } } } return false } -// Gets the object name `tc` from method t.Run(tc.Foo, func(t *testing.T) -func methodRunFirstArgumentObjectName(node ast.Node) string { - // nolint: gocritic - switch n := node.(type) { - case *ast.CallExpr: - for _, arg := range n.Args { - if s, ok := arg.(*ast.SelectorExpr); ok { - if i, ok := s.X.(*ast.Ident); ok { - return i.Name - } +// In an expression of the form t.Run(x, func(q *testing.T) {...}), return the +// value "q". In _most_ code, the name is probably t, but we shouldn't just +// assume. +func getRunCallbackParameterName(node ast.Node) string { + if n, ok := node.(*ast.CallExpr); ok { + if len(n.Args) < 2 { + // We want argument #2, but this call doesn't have two + // arguments. Maybe it's not really t.Run. + return "" + } + funcArg := n.Args[1] + if fun, ok := funcArg.(*ast.FuncLit); ok { + if len(fun.Type.Params.List) < 1 { + // Subtest function doesn't have any parameters. + return "" + } + firstArg := fun.Type.Params.List[0] + // We'll assume firstArg.Type is *testing.T. + if len(firstArg.Names) < 1 { + return "" } + return firstArg.Names[0].Name } } return "" } -// Checks if the function has the param type *testing.T) -func isTestFunction(funcDecl *ast.FuncDecl) bool { +// Checks if the function has the param type *testing.T; if it does, then the +// parameter name is returned, too. +func isTestFunction(funcDecl *ast.FuncDecl) (bool, string) { testMethodPackageType := "testing" testMethodStruct := "T" testPrefix := "Test" if !strings.HasPrefix(funcDecl.Name.Name, testPrefix) { - return false + return false, "" } if funcDecl.Type.Params != nil && len(funcDecl.Type.Params.List) != 1 { - return false + return false, "" } param := funcDecl.Type.Params.List[0] @@ -246,11 +249,32 @@ func isTestFunction(funcDecl *ast.FuncDecl) bool { if selectExpr, ok := starExp.X.(*ast.SelectorExpr); ok { if selectExpr.Sel.Name == testMethodStruct { if s, ok := selectExpr.X.(*ast.Ident); ok { - return s.Name == testMethodPackageType + return s.Name == testMethodPackageType, param.Names[0].Name } } } } - return false + return false, "" +} + +func loopVarReferencedInRun(call *ast.CallExpr, vars []types.Object, typeInfo *types.Info) (found *string) { + if len(call.Args) != 2 { + return + } + + ast.Inspect(call.Args[1], func(n ast.Node) bool { + ident, ok := n.(*ast.Ident) + if !ok { + return true + } + for _, o := range vars { + if typeInfo.ObjectOf(ident) == o { + found = &ident.Name + } + } + return true + }) + + return } -- cgit mrf-deployment