From 5705bcc3f4167eca1bdff9975aef7db554cb033a Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Thu, 17 Apr 2025 08:38:19 +0200 Subject: [PATCH] chore: bump golangci-lint to v2 (#8839) Signed-off-by: Matthieu MOREL --- .github/workflows/pr-linter-check.yml | 4 +- .golangci.yaml | 606 +++++++++++------------ hack/build-image/Dockerfile | 2 +- pkg/controller/backup_controller_test.go | 31 +- 4 files changed, 308 insertions(+), 335 deletions(-) diff --git a/.github/workflows/pr-linter-check.yml b/.github/workflows/pr-linter-check.yml index 46113c6d3..298346542 100644 --- a/.github/workflows/pr-linter-check.yml +++ b/.github/workflows/pr-linter-check.yml @@ -18,7 +18,7 @@ jobs: with: go-version-file: 'go.mod' - name: Linter check - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v7 with: - version: v1.64.5 + version: v2.1.1 args: --verbose diff --git a/.golangci.yaml b/.golangci.yaml index 331cf6679..bf2bffc9a 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -6,7 +6,7 @@ run: # default concurrency is a available CPU number concurrency: 4 - # timeout for analysis, e.g. 30s, 5m, default is 1m + # timeout for analysis, e.g. 30s, 5m, default is 0 timeout: 20m # exit code when at least one issue was found, default is 1 @@ -29,293 +29,263 @@ run: # output configuration options output: - # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" formats: - - format: colored-line-number + text: path: stdout - # print lines of code with issue, default is true - print-issued-lines: true + # print lines of code with issue, default is true + print-issued-lines: true - # print linter name in the end of issue text, default is true - print-linter-name: true + # print linter name in the end of issue text, default is true + print-linter-name: true -# all available settings of specific linters -linters-settings: + # Show statistics per linter. + show-stats: false - depguard: - rules: - main: - deny: - # specify an error message to output when a denylisted package is used - - pkg: github.com/sirupsen/logrus - desc: "logging is allowed only by logutils.Log" +linters: + # all available settings of specific linters + settings: + depguard: + rules: + main: + deny: + # specify an error message to output when a denylisted package is used + - pkg: github.com/sirupsen/logrus + desc: "logging is allowed only by logutils.Log" - dogsled: - # checks assignments with too many blank identifiers; default is 2 - max-blank-identifiers: 2 + dogsled: + # checks assignments with too many blank identifiers; default is 2 + max-blank-identifiers: 2 - dupl: - # tokens count to trigger issue, 150 by default - threshold: 100 + dupl: + # tokens count to trigger issue, 150 by default + threshold: 100 - errcheck: - # report about not checking of errors in type assertions: `a := b.(MyStruct)`; - # default is false: such cases aren't reported by default. - check-type-assertions: false + errcheck: + # report about not checking of errors in type assertions: `a := b.(MyStruct)`; + # default is false: such cases aren't reported by default. + check-type-assertions: false - # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; - # default is false: such cases aren't reported by default. - check-blank: false + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: false - # [deprecated] comma-separated list of pairs of the form pkg:regex - # the regex is used to ignore names within pkg. (default "fmt:.*"). - # see https://github.com/kisielk/errcheck#the-deprecated-method for details - # ignore: fmt:.*,io/ioutil:^Read.* - # path to a file containing a list of functions to exclude from checking - # see https://github.com/kisielk/errcheck#excluding-functions for details - # exclude: /path/to/file.txt + exhaustive: + # indicates that switch statements are to be considered exhaustive if a + # 'default' case is present, even if all enum members aren't listed in the + # switch + default-signifies-exhaustive: false - exhaustive: - # indicates that switch statements are to be considered exhaustive if a - # 'default' case is present, even if all enum members aren't listed in the - # switch - default-signifies-exhaustive: false + funlen: + lines: 60 + statements: 40 - funlen: - lines: 60 - statements: 40 + gocognit: + # minimal code complexity to report, 30 by default (but we recommend 10-20) + min-complexity: 10 - gocognit: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 + nestif: + # minimal complexity of if statements to report, 5 by default + min-complexity: 4 - nestif: - # minimal complexity of if statements to report, 5 by default - min-complexity: 4 + goconst: + # minimal length of string constant, 3 by default + min-len: 3 + # minimal occurrences count to trigger, 3 by default + min-occurrences: 5 - goconst: - # minimal length of string constant, 3 by default - min-len: 3 - # minimal occurrences count to trigger, 3 by default - min-occurrences: 5 + gocritic: + # Which checks should be enabled; can't be combined with 'disabled-checks'; + # See https://go-critic.github.io/overview#checks-overview + # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` + # By default list of stable checks is used. + settings: # settings passed to gocritic + captLocal: # must be valid enabled check name + paramsOnly: true - gocritic: - # Which checks should be enabled; can't be combined with 'disabled-checks'; - # See https://go-critic.github.io/overview#checks-overview - # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` - # By default list of stable checks is used. - # enabled-checks: - # - rangeValCopy + gocyclo: + # minimal code complexity to report, 30 by default (but we recommend 10-20) + min-complexity: 10 - # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty - # disabled-checks: - # - regexpMust + godot: + # check all top-level comments, not only declarations + check-all: false - # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. - # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". - # enabled-tags: - # - performance - # disabled-tags: - # - experimental + godox: + # report any comments starting with keywords, this is useful for TODO or FIXME comments that + # might be left in the code accidentally and should be resolved before merging + keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting + - NOTE + - OPTIMIZE # marks code that should be optimized before merging + - HACK # marks hack-arounds that should be removed before merging - settings: # settings passed to gocritic - captLocal: # must be valid enabled check name - paramsOnly: true - # rangeValCopy: - # sizeThreshold: 32 + gosec: + excludes: + - G115 - gocyclo: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 + govet: + # enable or disable analyzers by name + enable: + - atomicalign + enable-all: false + disable: + - shadow + disable-all: false - godot: - # check all top-level comments, not only declarations - check-all: false - - godox: - # report any comments starting with keywords, this is useful for TODO or FIXME comments that - # might be left in the code accidentally and should be resolved before merging - keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting - - NOTE - - OPTIMIZE # marks code that should be optimized before merging - - HACK # marks hack-arounds that should be removed before merging - - gofmt: - # simplify code: gofmt with `-s` option, true by default - simplify: true - - goimports: - # put imports beginning with prefix after 3rd-party packages; - # it's a comma-separated list of prefixes - local-prefixes: github.com/org/project - - gosec: - excludes: - - G115 - - govet: - # report about shadowed variables - # check-shadowing: true - - # settings per analyzer - settings: - printf: # analyzer name, run `go tool vet help` to see all analyzers - funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf - - # enable or disable analyzers by name - enable: - - atomicalign - enable-all: false - disable: - - shadow - disable-all: false - - lll: + lll: # max line length, lines longer will be reported. Default is 120. # '\t' is counted as 1 character by default, and can be changed with the tab-width option - line-length: 120 - # tab width in spaces. Default to 1. - tab-width: 1 + line-length: 120 + # tab width in spaces. Default to 1. + tab-width: 1 - misspell: - # Correct spellings using locale preferences for US or UK. - # Default is to use a neutral variety of English. - # Setting locale to US will correct the British spelling of 'colour' to 'color'. - locale: US - ignore-words: - - someword + misspell: + # Correct spellings using locale preferences for US or UK. + # Default is to use a neutral variety of English. + # Setting locale to US will correct the British spelling of 'colour' to 'color'. + locale: US + ignore-rules: + - someword - nakedret: - # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 - max-func-lines: 30 + nakedret: + # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 + max-func-lines: 30 - prealloc: - # XXX: we don't recommend using this linter before doing performance profiling. - # For most programs usage of prealloc will be a premature optimization. + prealloc: + # XXX: we don't recommend using this linter before doing performance profiling. + # For most programs usage of prealloc will be a premature optimization. - # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. - # True by default. - simple: true - range-loops: true # Report preallocation suggestions on range loops, true by default - for-loops: false # Report preallocation suggestions on for loops, false by default + # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. + # True by default. + simple: true + range-loops: true # Report preallocation suggestions on range loops, true by default + for-loops: false # Report preallocation suggestions on for loops, false by default - nolintlint: - # Enable to ensure that nolint directives are all used. Default is true. - allow-unused: false - # Exclude following linters from requiring an explanation. Default is []. - allow-no-explanation: [] - # Enable to require an explanation of nonzero length after each nolint directive. Default is false. - require-explanation: true - # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. - require-specific: true + nolintlint: + # Enable to ensure that nolint directives are all used. Default is true. + allow-unused: false + # Exclude following linters from requiring an explanation. Default is []. + allow-no-explanation: [] + # Enable to require an explanation of nonzero length after each nolint directive. Default is false. + require-explanation: true + # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. + require-specific: true - perfsprint: - strconcat: false - sprintf1: false - errorf: false - int-conversion: true + perfsprint: + strconcat: false + sprintf1: false + errorf: false + int-conversion: true - revive: - rules: - - name: blank-imports - disabled: true - - name: context-as-argument - disabled: true - - name: context-keys-type - - name: dot-imports - disabled: true - - name: early-return - disabled: true - arguments: - - "preserveScope" - - name: empty-block - disabled: true - - name: error-naming - disabled: true - - name: error-return - disabled: true - - name: error-strings - disabled: true - - name: errorf - disabled: true - - name: increment-decrement - - name: indent-error-flow - disabled: true - - name: range - - name: receiver-naming - disabled: true - - name: redefines-builtin-id - disabled: true - - name: superfluous-else - disabled: true - arguments: - - "preserveScope" - - name: time-naming - - name: unexported-return - disabled: true - - name: unnecessary-stmt - - name: unreachable-code - - name: unused-parameter - disabled: true - - name: use-any - - name: var-declaration - - name: var-naming - disabled: true + revive: + rules: + - name: blank-imports + disabled: true + - name: context-as-argument + disabled: true + - name: context-keys-type + - name: dot-imports + disabled: true + - name: early-return + disabled: true + arguments: + - "preserveScope" + - name: empty-block + disabled: true + - name: error-naming + disabled: true + - name: error-return + disabled: true + - name: error-strings + disabled: true + - name: errorf + disabled: true + - name: increment-decrement + - name: indent-error-flow + disabled: true + - name: range + - name: receiver-naming + disabled: true + - name: redefines-builtin-id + disabled: true + - name: superfluous-else + disabled: true + arguments: + - "preserveScope" + - name: time-naming + - name: unexported-return + disabled: true + - name: unnecessary-stmt + - name: unreachable-code + - name: unused-parameter + disabled: true + - name: use-any + - name: var-declaration + - name: var-naming + disabled: true - rowserrcheck: - packages: - - github.com/jmoiron/sqlx + rowserrcheck: + packages: + - github.com/jmoiron/sqlx - testifylint: + staticcheck: + checks: + - all + - -QF1001 # FIXME + - -QF1003 # FIXME + - -QF1004 # FIXME + - -QF1007 # FIXME + - -QF1008 # FIXME + - -QF1009 # FIXME + - -QF1012 # FIXME + + testifylint: # TODO: enable them all disable: - - go-require + - empty # FIXME + - equal-values # FIXME - float-compare + - go-require + - len # FIXME - require-error enable-all: true - testpackage: - # regexp pattern to skip files - skip-regexp: (export|internal)_test\.go - unparam: - # Inspect exported functions, default is false. Set to true if no external program/library imports your code. - # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find external interfaces. All text editor integrations - # with golangci-lint call it on a directory with the changed file. - check-exported: false + testpackage: + # regexp pattern to skip files + skip-regexp: (export|internal)_test\.go + unparam: + # Inspect exported functions, default is false. Set to true if no external program/library imports your code. + # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find external interfaces. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false - whitespace: - multi-if: false # Enforces newlines (or comments) after every multi-line if statement - multi-func: false # Enforces newlines (or comments) after every multi-line function signature + whitespace: + multi-if: false # Enforces newlines (or comments) after every multi-line if statement + multi-func: false # Enforces newlines (or comments) after every multi-line function signature - wsl: - # If true append is only allowed to be cuddled if appending value is - # matching variables, fields or types on line above. Default is true. - strict-append: true - # Allow calls and assignments to be cuddled as long as the lines have any - # matching variables, fields or types. Default is true. - allow-assign-and-call: true - # Allow multiline assignments to be cuddled. Default is true. - allow-multiline-assign: true - # Allow declarations (var) to be cuddled. - allow-cuddle-declarations: false - # Allow trailing comments in ending of blocks - allow-trailing-comment: false - # Force newlines in end of case at this limit (0 = never). - force-case-trailing-whitespace: 0 - # Force cuddling of err checks with err var assignment - force-err-cuddling: false - # Allow leading comments to be separated with empty lines - allow-separated-leading-comment: false + wsl: + # If true append is only allowed to be cuddled if appending value is + # matching variables, fields or types on line above. Default is true. + strict-append: true + # Allow calls and assignments to be cuddled as long as the lines have any + # matching variables, fields or types. Default is true. + allow-assign-and-call: true + # Allow multiline assignments to be cuddled. Default is true. + allow-multiline-assign: true + # Allow declarations (var) to be cuddled. + allow-cuddle-declarations: false + # Allow trailing comments in ending of blocks + allow-trailing-comment: false + # Force newlines in end of case at this limit (0 = never). + force-case-trailing-whitespace: 0 + # Force cuddling of err checks with err var assignment + force-err-cuddling: false + # Allow leading comments to be separated with empty lines + allow-separated-leading-comment: false -linters: - disable-all: true + default: none enable: - asasalint - asciicheck @@ -323,88 +293,85 @@ linters: - bodyclose - copyloopvar - dogsled - - durationcheck - dupword + - durationcheck - errcheck - errchkjson + - ginkgolinter - goconst - - gofmt - goheader - - goimports - goprintffuncname - gosec - - gosimple - govet - - ginkgolinter - importas - ineffassign - misspell - nakedret - - nosprintfhostport - nilerr - noctx - nolintlint + - nosprintfhostport - perfsprint - revive - staticcheck - - stylecheck - testifylint - thelper - - typecheck - unconvert - unparam - unused - usestdlibvars - whitespace - fast: false + + exclusions: + # which dirs to skip: issues from them won't be reported; + # can use regexp here: generated.*, regexp is applied on full path; + # default value is empty list, but default dirs are skipped independently + # from this option's value (see skip-dirs-use-default). + # "/" will be replaced by current OS file path separator to properly work + # on Windows. + paths: + - pkg/plugin/generated/* + - third_party + + rules: + - linters: + - staticcheck + text: "DefaultVolumesToRestic" # No need to report deprecate for DefaultVolumesToRestic. + - path: ".*_test.go$" + linters: + - errcheck + - goconst + - gosec + - govet + - staticcheck + - unparam + - unused + - path: test/ + linters: + - errcheck + - goconst + - gosec + - nilerr + - staticcheck + - unparam + - unused + - path: ".*data_upload_controller_test.go$" + linters: + - dupword + text: "type" + - path: ".*config_test.go$" + linters: + - dupword + text: "bucket" + + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling issues: - # which dirs to skip: issues from them won't be reported; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but default dirs are skipped independently - # from this option's value (see skip-dirs-use-default). - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - exclude-dirs: - - pkg/plugin/generated/* - - exclude-rules: - - linters: - - staticcheck - text: "DefaultVolumesToRestic" # No need to report deprecate for DefaultVolumesToRestic. - - path: ".*_test.go$" - linters: - - errcheck - - goconst - - gosec - - govet - - staticcheck - - stylecheck - - unparam - - unused - - path: test/ - linters: - - errcheck - - goconst - - gosec - - nilerr - - staticcheck - - stylecheck - - unparam - - unused - - path: ".*data_upload_controller_test.go$" - linters: - - dupword - text: "type" - - path: ".*config_test.go$" - linters: - - dupword - text: "bucket" - - # The list of ids of default excludes to include or disable. By default it's empty. - include: - - EXC0002 # disable excluding of issues about comments from golint - # Maximum issues count per one linter. Set to 0 to disable. Default is 50. max-issues-per-linter: 0 @@ -414,20 +381,29 @@ issues: # make issues output unique by line, default is true uniq-by-line: true -severity: - # Default value is empty string. - # Set the default severity for issues. If severity rules are defined and the issues - # do not match or no severity is provided to the rule this will be the default - # severity applied. Severities should match the supported severity names of the - # selected out format. - # - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity - # - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity - # - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message - default-severity: error +# This file contains all available configuration options +# with their default values. +formatters: + enable: + - gofmt + - goimports - # The default value is false. - # If set to true severity-rules regular expressions become case sensitive. - case-sensitive: false + exclusions: + generated: lax + paths: + - pkg/plugin/generated/* + - third_party + + settings: + gofmt: + # simplify code: gofmt with `-s` option, true by default + simplify: true + goimports: + local-prefixes: + - github.com/vmware-tanzu/velero + +severity: + default: error # Default value is empty list. # When a list of severity rules are provided, severity information will be added to lint @@ -436,5 +412,7 @@ severity: # Only affects out formats that support setting severity information. rules: - linters: - - dupl + - dupl severity: info + +version: "2" diff --git a/hack/build-image/Dockerfile b/hack/build-image/Dockerfile index 94876a264..f4767d705 100644 --- a/hack/build-image/Dockerfile +++ b/hack/build-image/Dockerfile @@ -94,7 +94,7 @@ RUN ARCH=$(go env GOARCH) && \ chmod +x /usr/bin/goreleaser # get golangci-lint -RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.64.5 +RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.1.1 # install kubectl RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/$(go env GOARCH)/kubectl diff --git a/pkg/controller/backup_controller_test.go b/pkg/controller/backup_controller_test.go index ddf2d1329..548cb9b88 100644 --- a/pkg/controller/backup_controller_test.go +++ b/pkg/controller/backup_controller_test.go @@ -76,7 +76,8 @@ func (b *fakeBackupper) Backup(logger logrus.FieldLogger, backup *pkgbackup.Requ func (b *fakeBackupper) BackupWithResolvers(logger logrus.FieldLogger, backup *pkgbackup.Request, backupFile io.Writer, backupItemActionResolver framework.BackupItemActionResolverV2, itemBlockActionResolver framework.ItemBlockActionResolver, - volumeSnapshotterGetter pkgbackup.VolumeSnapshotterGetter) error { + volumeSnapshotterGetter pkgbackup.VolumeSnapshotterGetter, +) error { args := b.Called(logger, backup, backupFile, backupItemActionResolver, volumeSnapshotterGetter) return args.Error(0) } @@ -129,9 +130,7 @@ func TestProcessBackupNonProcessedItems(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { formatFlag := logging.FormatText - var ( - logger = logging.DefaultLogger(logrus.DebugLevel, formatFlag) - ) + logger := logging.DefaultLogger(logrus.DebugLevel, formatFlag) c := &backupReconciler{ kbClient: velerotest.NewFakeControllerRuntimeClient(t), @@ -189,8 +188,12 @@ func TestProcessBackupValidationFailures(t *testing.T) { }, { name: "labelSelector as well as orLabelSelectors both are specified in backup request fails validation", - backup: defaultBackup().LabelSelector(&metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}}).OrLabelSelector([]*metav1.LabelSelector{{MatchLabels: map[string]string{"a1": "b1"}}, {MatchLabels: map[string]string{"a2": "b2"}}, - {MatchLabels: map[string]string{"a3": "b3"}}, {MatchLabels: map[string]string{"a4": "b4"}}}).Result(), + backup: defaultBackup().LabelSelector(&metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}}).OrLabelSelector([]*metav1.LabelSelector{ + {MatchLabels: map[string]string{"a1": "b1"}}, + {MatchLabels: map[string]string{"a2": "b2"}}, + {MatchLabels: map[string]string{"a3": "b3"}}, + {MatchLabels: map[string]string{"a4": "b4"}}, + }).Result(), backupLocation: defaultBackupLocation, expectedErrs: []string{"encountered labelSelector as well as orLabelSelectors in backup spec, only one can be specified"}, }, @@ -205,9 +208,7 @@ func TestProcessBackupValidationFailures(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { formatFlag := logging.FormatText - var ( - logger = logging.DefaultLogger(logrus.DebugLevel, formatFlag) - ) + logger := logging.DefaultLogger(logrus.DebugLevel, formatFlag) apiServer := velerotest.NewAPIServer(t) discoveryHelper, err := discovery.NewHelper(apiServer.DiscoveryClient, logger) @@ -415,9 +416,7 @@ func Test_prepareBackupRequest_BackupStorageLocation(t *testing.T) { } func TestDefaultBackupTTL(t *testing.T) { - var ( - defaultBackupTTL = metav1.Duration{Duration: 24 * 30 * time.Hour} - ) + defaultBackupTTL := metav1.Duration{Duration: 24 * 30 * time.Hour} now, err := time.Parse(time.RFC1123Z, time.RFC1123Z) require.NoError(t, err) @@ -1545,9 +1544,7 @@ func TestValidateAndGetSnapshotLocations(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { formatFlag := logging.FormatText - var ( - logger = logging.DefaultLogger(logrus.DebugLevel, formatFlag) - ) + logger := logging.DefaultLogger(logrus.DebugLevel, formatFlag) c := &backupReconciler{ logger: logger, @@ -1579,9 +1576,7 @@ func TestValidateAndGetSnapshotLocations(t *testing.T) { sort.Strings(locations) require.Equal(t, test.expectedVolumeSnapshotLocationNames, locations) } else { - if len(errs) == 0 { - require.Error(t, nil, "validateAndGetSnapshotLocations expected error") - } + require.NotEmpty(t, errs, "validateAndGetSnapshotLocations expected error") require.Contains(t, errs, test.expectedErrors) } })