Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update depguard rules to prevent importing test code outside tests #51001

Merged
merged 1 commit into from
Jan 14, 2025

Conversation

rosstimothy
Copy link
Contributor

@rosstimothy rosstimothy commented Jan 13, 2025

There is a lot of shared test code defined outside of _test.go files scattered through out the code base. Dead code detection in Go is not that great and cannot detect that these test helpers are only consumed in tests. While this doesn't remediate anything, it should hopeful avoid any future code from making it harder to separate test and production code.

strings build/teleport | rg testify
github.com/stretchr/testify/assert.init
github.com/stretchr/testify/assert.uint32Type
go:link.pkghashbytes.github.com/stretchr/testify/assert
github.com/stretchr/testify/assert.int64Type
github.com/stretchr/testify/assert.uintptrType
go:link.pkghashbytes.github.com/stretchr/testify/require
github.com/stretchr/testify/assert.stringType
github.com/stretchr/testify/assert.float32Type
github.com/stretchr/testify/assert.bytesType
github.com/stretchr/testify/assert.intType
go:link.pkghashbytes.github.com/stretchr/testify/assert/yaml
github.com/stretchr/testify/assert.float64Type
github.com/stretchr/testify/assert..inittask
github.com/stretchr/testify/assert.int32Type
github.com/stretchr/testify/assert.uint16Type
github.com/stretchr/testify/assert.int8Type
github.com/stretchr/testify/assert.uint64Type
github.com/stretchr/testify/assert.uintType
github.com/stretchr/testify/assert.uint8Type
go:link.pkghash.github.com/stretchr/testify/assert/yaml
github.com/stretchr/testify/assert.int16Type
go:link.pkghash.github.com/stretchr/testify/require
go:link.pkghash.github.com/stretchr/testify/assert
github.com/stretchr/testify/assert.timeType
dep     github.com/stretchr/testify     v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify/assert.init
github.com/stretchr/[email protected]/assert/assertion_compare.go
dep     github.com/stretchr/testify     v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=



strings build/teleport | rg testing
testing
*testing.T
*[]*testing.T
*testing.common
*testing.matcher
testingOnlyDidHRR
*testing.indenter
*func(*testing.T)
testingOnlyCurveID
*testing.filterMatch
*testing.testContext
*testing.chattyPrinter
*testing.highPrecisionTime
$*func(string, func(*testing.T)) bool
)*struct { F uintptr; X0 *testing.common }
+google.golang.org/protobuf/testing/protocmp
9*struct { F uintptr; X0 *testing.T; X1 func(*testing.T) }
<*func(*testing.T, types.SystemRole) (*state.Identity, error)
B*struct { F uintptr; X0 *testing.common; X1 []uintptr; X2 func() }
testing.init
testing.(*matcher).fullName
testing.(*matcher).fullName.deferwrap2
testing.(*matcher).fullName.deferwrap1
testing.(*matcher).unique
testing.parseSubtestNumber
testing.rewrite
testing.isSpace
testing.(*chattyPrinter).Updatef
testing.(*chattyPrinter).prefix
testing.(*chattyPrinter).Updatef.deferwrap1
testing.(*chattyPrinter).Printf
testing.(*chattyPrinter).Printf.deferwrap1
testing.(*common).frameSkip
testing.(*common).frameSkip.func1
testing.(*common).decorate
testing.(*common).flushToParent
testing.(*common).flushToParent.deferwrap2
testing.(*common).flushToParent.deferwrap1
testing.indenter.Write
testing.fmtDuration
testing.(*common).Name
testing.(*common).setRan
testing.(*common).setRan.deferwrap1
testing.(*common).Fail
testing.(*common).Fail.deferwrap1
testing.(*common).Failed
testing.(*common).Failed.deferwrap1
testing.(*common).FailNow
testing.(*common).checkFuzzFn
testing.(*common).logDepth
testing.(*common).logDepth.deferwrap2
testing.(*common).logDepth.deferwrap1
testing.(*common).Log
testing.(*common).log
testing.(*common).Logf
testing.(*common).Error
testing.(*common).Errorf
testing.(*common).Fatal
testing.(*common).Fatalf
testing.(*common).Skip
testing.(*common).Skipf
testing.(*common).SkipNow
testing.(*common).Skipped
testing.(*common).Skipped.deferwrap1
testing.(*common).Helper
testing.(*common).Helper.deferwrap1
testing.(*common).Cleanup
testing.(*common).Cleanup.deferwrap1
testing.(*common).Cleanup.func1
testing.(*common).Cleanup.func1.1
testing.(*common).Cleanup.func1.1.deferwrap1
testing.(*common).TempDir
testing.(*common).TempDir.func2
testing.removeAll
testing.(*common).Setenv
testing.(*common).Setenv.func2
testing.(*common).Setenv.func1
testing.(*common).runCleanup
testing.(*common).runCleanup.func2
testing.(*common).runCleanup.func1
testing.(*common).runCleanup.deferwrap1
testing.(*common).resetRaces
testing.(*common).checkRaces
testing.callerName
testing.pcToName
testing.(*T).Parallel
testing.highPrecisionTimeSince
testing.highPrecisionTimeNow
testing.(*T).Setenv
testing.tRunner
testing.tRunner.func2
testing.tRunner.func1
testing.tRunner.func1.2
testing.tRunner.func1.1
testing.(*T).Run
testing.shouldFailFast
testing.(*T).Run.gowrap1
testing.(*T).Deadline
testing.(*testContext).waitParallel
testing.(*testContext).release
testing.(*T).report
testing.(*common).TempDir.func1
type:.eq.testing.chattyPrinter
type:.eq.testing.testContext
testing.(*T).Cleanup
testing.(*T).Error
testing.(*T).Errorf
testing.(*T).Fail
testing.(*T).FailNow
testing.(*T).Failed
testing.(*T).Fatal
testing.(*T).Fatalf
testing.(*T).Helper
testing.(*T).Log
testing.(*T).Logf
testing.(*T).Name
testing.(*T).Skip
testing.(*T).SkipNow
testing.(*T).Skipf
testing.(*T).Skipped
testing.(*T).TempDir
testing.(*indenter).Write
testing.Testing
testing/fuzz.go
testing/match.go
testing/testing.go
testing/testing_other.go

Updates #51023.

@rosstimothy rosstimothy added the no-changelog Indicates that a PR does not require a changelog entry label Jan 13, 2025
@rosstimothy rosstimothy force-pushed the tross/testify_prod_code branch from e489716 to 4e0910a Compare January 13, 2025 23:18
@rosstimothy rosstimothy marked this pull request as ready for review January 13, 2025 23:51
@rosstimothy rosstimothy force-pushed the tross/testify_prod_code branch 3 times, most recently from d6e0845 to fc98b57 Compare January 14, 2025 14:35
.golangci.yml Outdated Show resolved Hide resolved
.golangci.yml Outdated Show resolved Hide resolved
- '!**/lib/teleterm/gatewaytest/**'
- '!**/lib/utils/testhelpers.go'
- '!**/lib/utils/testutils/**'
- '!**/integration/appaccess/fixtures.go'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments/notes:

  1. Could integration/ and integrations/ get a full pass?
  2. Dedicated packages for test helpers are a more robust solution to standalone files, as these are likely to be fully excluded from the complete binary.
  3. We could use a testonly build tag for some of these, which is a stronger guarantee than depguard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could integration/ and integrations/ get a full pass?

Maybe integration/ but integrations are not tests, they are our plugins, and are imported directly into teleport.e.

these are likely to be fully excluded from the complete binary

I would not rely on Go's dead code removal to guarantee this.

We could use a testonly build tag for some of these

I thought about this but chasing tags in all the various ways we seem to run tests in CI seemed like a more involved task. This for now at least puts a halt to things until we can evaluate other options, including a build tag.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not rely on Go's dead code removal to guarantee this.

I think it does work on a per-package basis. A strings check for testenv does come up empty.

I thought about this but chasing tags in all the various ways we seem to run tests in CI seemed like a more involved task. This for now at least puts a halt to things until we can evaluate other options, including a build tag.

Yep, it's a bigger task for sure. Just throwing some ideas out there.

.golangci.yml Outdated Show resolved Hide resolved
- '!**/lib/utils/cli.go'
- '!**/lib/utils/testhelpers.go'
- '!**/lib/utils/testutils/**'
- '!**/tool/teleport/testenv/**'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a depguard rule that only allows "testenv" imports for tests and other testenv packages? I think these are in the clear now, but might as well add the rule here.

There is a lot of shared test code defined outside of _test.go
files scattered through out the code base. Dead code detection in
Go is not that great and cannot detect that these test helpers are
only consumed in tests. This results in testify code being included
in production binaries:

```bash
strings build/teleport | rg testify
github.com/stretchr/testify/assert.init
github.com/stretchr/testify/assert.uint32Type
go:link.pkghashbytes.github.com/stretchr/testify/assert
github.com/stretchr/testify/assert.int64Type
github.com/stretchr/testify/assert.uintptrType
go:link.pkghashbytes.github.com/stretchr/testify/require
github.com/stretchr/testify/assert.stringType
github.com/stretchr/testify/assert.float32Type
github.com/stretchr/testify/assert.bytesType
github.com/stretchr/testify/assert.intType
go:link.pkghashbytes.github.com/stretchr/testify/assert/yaml
github.com/stretchr/testify/assert.float64Type
github.com/stretchr/testify/assert..inittask
github.com/stretchr/testify/assert.int32Type
github.com/stretchr/testify/assert.uint16Type
github.com/stretchr/testify/assert.int8Type
github.com/stretchr/testify/assert.uint64Type
github.com/stretchr/testify/assert.uintType
github.com/stretchr/testify/assert.uint8Type
go:link.pkghash.github.com/stretchr/testify/assert/yaml
github.com/stretchr/testify/assert.int16Type
go:link.pkghash.github.com/stretchr/testify/require
go:link.pkghash.github.com/stretchr/testify/assert
github.com/stretchr/testify/assert.timeType
dep     github.com/stretchr/testify     v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify/assert.init
github.com/stretchr/[email protected]/assert/assertion_compare.go
dep     github.com/stretchr/testify     v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
```

While this doesn't remediate anything, it should hopeful avoid any
future code from making it harder to separate test and production
code.
@rosstimothy rosstimothy force-pushed the tross/testify_prod_code branch from 4e211ec to 6cb1db1 Compare January 14, 2025 18:36
@rosstimothy rosstimothy enabled auto-merge January 14, 2025 18:37
@rosstimothy rosstimothy added this pull request to the merge queue Jan 14, 2025
Merged via the queue into master with commit b5b8a03 Jan 14, 2025
41 checks passed
@rosstimothy rosstimothy deleted the tross/testify_prod_code branch January 14, 2025 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-changelog Indicates that a PR does not require a changelog entry
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants