-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
proposal: cmd/go: add go test -long #34707
Comments
If this were implemented, running simply |
I have mixed feelings about this proposal. I too wish that long/integration tests were more standard across Go projects. On the other hand, I'm not sure that It seems to me like |
@bitfield The problem is that, empirically, tests are already getting skipped. I have an So, the question is whether it's better to keep a dozen different empirical methods, or have a single way to find and run tests that won't run by default. @mvdan It's true that large tests tend to require more infrastructure. In my case, it requires a bunch of extra installed programs (docker, kind, ...) to build the test harness. So it comes back to: is there value in standardizing the discovery of such tests, even though running them may take more than just This proposal was filed out of frustration at setting up yet another janky harness for E2E tests, but I'm not deeply married to solving the problem, so this discussion is very useful! |
The usual way of segregating tests is via build tags. Add a tag to mark long tests and then run them with |
I think so. Perhaps we can simply standardize an existing way to do it, such as @iand's build tag idea, or your environment variable idea. This would still make most projects alike, without having to overcomplicate the If we go with a build tag, my only suggestion would be to make it more specific than |
It seems clearly useful to be able to skip non-hermetic tests (such as those that require unavailable tools), although for those you can generally use With a bit of work (and assuming that we fix #33976 soon), you can even make the skip contingent on your own module not being the main module (so that developers on your project always run all of your tests, and the tests fail a needed tool is missing). See So I think we should be careful not to conflate “long” with “non-hermetic”. |
If you have three granularities, why not more? In the Go standard library, we have at least four:
That's not to say that every project should follow this structure. However, it does suggest that |
That said: the user has an explicit control to tell you how long they expect tests to run: the So one option you could pursue would be to tailor the set of |
I really like @bcmills's last idea. After all, I'd love it if this was high-level, like The reason I bring up orders of magnitude is because I can often tell if tests will take milliseconds, seconds, or minutes to run. But it's hard to say if they will take 1s or 2s, because the CPU/disk/network/etc of different machines could easily vary by 5x. Using a cutoff that directly used |
It shouldn't depend much on the machine: you should only be running the test at all if the timeout is 1–2 orders of magnitude longer than how long you expect the test to run, for precisely that reason. My touchstone for this is user behavior: if a user ran your program, how long would they wait before hitting ⌃C or canceling a page-load? That's how long the test should be willing to wait, too. There is a bit of a question as to how you divvy up |
On that note, see #28135, which I guess is on me to implement. 😅 |
If that's true, then I fear that we might be getting off-track; would like to hear if @danderson's problems would be fixed by your timeout/deadline ideas, or if they go beyond test times. It would solve most of the issue for me at least, since I've many times seen non-hermetic tests that run decently fast. |
You can define the |
@cespare, note that if the pattern passed to |
I don't believe we should add complexity here. And as @cespare says, you can already define -verylong yourself when you need it. |
This seems like a likely decline. Leaving open for a week for final comments. |
This caught my eye since I've implemented something much like this in an My use case is for As for adding package test
import (
"flag"
"testing"
"time"
)
// Custom test command line flags.
var (
long = flag.Bool("long", false, "enable long running tests")
stress = flag.Bool("stress", false, "enable stress tests (implies -long)")
)
// timeallowed returns how long a single test is allowed to take.
func timeallowed() time.Duration {
switch {
case testing.Short():
return time.Second / 10
case *long:
return 30 * time.Second
case *stress:
return 2 * time.Minute
default:
return time.Second
}
}
// Long reports whether long tests are enabled.
func Long() bool {
return *long || *stress
}
// Stress reports whether stress tests are enabled.
func Stress() bool {
return *stress
}
// RequireLong marks this test as a long test. Test will be skipped if long
// tests are not enabled.
func RequireLong(t *testing.T) {
if !Long() {
t.Skipf("long test: use -long or -stress to enable")
}
}
// RequireStress marks this test as a stress test. Test will be skipped if stress
// tests are not enabled.
func RequireStress(t *testing.T) {
if !Stress() {
t.Skipf("stress test: use -stress to enable")
}
}
// Repeat the given trial function. The duration is controlled by custom
// command-line flags. The trial function returns whether it wants to continue
// testing.
//
// -short run for less time than usual
// -long allow more time
// -stress run for an extremely long time
func Repeat(t *testing.T, trial func(t *testing.T) bool) {
start := time.Now()
d := timeallowed()
n := 1
for time.Since(start) < d && trial(t) {
n++
}
t.Logf("%d trials in %s", n, time.Since(start))
}
// Trials returns a function that repeats f.
func Trials(f func(t *testing.T) bool) func(t *testing.T) {
return func(t *testing.T) {
Repeat(t, f)
}
} |
It seems the consensus is that there's no value in standardizing a way to run specific classes of tests, and that should just be left to each project to figure out. I'm not particularly happy with that, but I can certainly live with it. No objection to closing from me. |
No change in consensus, so declining. |
go test -long
Abstract
Add
go test -long
as a gate for (very) long tests.Problem statement
I write MetalLB, a set of Go programs that deploy into Kubernetes and do marginally useful things within. Currently, it's tested entirely by short and fast unit tests, but I would very much like to add integration tests that run the code against Kubernetes.
This involves spinning up a local Kubernetes cluster, which takes several minutes, and building and pushing several Docker images, taking another minute or so. This means these tests take 2-5 minutes to even start running, and probably another minute or two to finish.
With the current Go tool UX, the default behavior is the opposite of desirable for rapid iteration, and I often find myself accidentally spinning up this giant coal plant of a test during iterative development. This is an irritating series of little paper cuts.
Empirically, people are solving this on their own. In my code I check for a "RUN_SLOW_TESTS" env var, and use that to
t.Skip
the long tests. It works well enough, but everyone implementing their own hacks for this means the developer experience is fragmented, and it's easier to miss the fact that long tests exist at all, because the "run absolutely everything" switch is different for everyone.Proposal
In a perfect world, remove
go test -short
and replace it withgo test -long
, flipping the default to be "you must choose to run the very slow things. Given that this breaking change is likely not palatable, I propose addinggo test -long
in addition to the existinggo test -short
.In effect, this creates 3 bands of tests: short, medium, and long, with "short and medium" being the default
go test
runs.-short
and-long
act as lowering or raising a bar of "how much I'm willing to wait":-short
only allows the short band to run, whereas-long
allows short, medium and long to run.Again I'm not in love with the 3 bands and would prefer 2 with a flipped default. Given that there would be three, I'd propose the following rules of thumb for what tests go where:
go test -short
should be as fast as the compiler, fast enough that I can run compile+test interactively as part of an IDE.go test
should be fast enough that the developer's attention doesn't wander off to Twitter. Call it less than 10s total.go test -long
is for persnickety CI pipelines and coffee breaks. Minutes, tens of minute, hours if you really must (though I sincerely hope nobody does that last one).cc @bradfitz
The text was updated successfully, but these errors were encountered: