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

gomega.Eventually ignores default timeout #781

Closed
pohly opened this issue Oct 1, 2024 · 7 comments
Closed

gomega.Eventually ignores default timeout #781

pohly opened this issue Oct 1, 2024 · 7 comments

Comments

@pohly
Copy link

pohly commented Oct 1, 2024

In a Kubernetes e2e_node test, we have:

gomega.SetDefaultEventuallyTimeout(5 * time.Minute)
...
gomega.Eventually(ctx, listResources).Should(matchNode, "ResourceSlice from kubelet plugin")

But that call doesn't time out. Eventually the entire suite gets killed by the CI, which doesn't give any information about the reason why it didn't stop.

I think I traced it to:

func (assertion *AsyncAssertion) afterTimeout() <-chan time.Time {
if assertion.timeoutInterval >= 0 {
return time.After(assertion.timeoutInterval)
}
if assertion.asyncType == AsyncAssertionTypeConsistently {
return time.After(assertion.g.DurationBundle.ConsistentlyDuration)
} else {
if assertion.ctx == nil {
return time.After(assertion.g.DurationBundle.EventuallyTimeout)
} else {
return nil
}
}
}

assertion.ctx is from Ginkgo and the specific assertion doesn't have a timeout:

(dlv) p assertion.ctx
Sending output to pager...
context.Context(*github.com/onsi/ginkgo/v2/internal.specContext) *{
	Context: context.Context(*context.valueCtx) *{
		Context: context.Context(*context.cancelCtx) ...,
		key: interface {}(string) *(*interface {})(0xc000aa6700),
		val: interface {}(*github.com/onsi/ginkgo/v2/internal.specContext) ...,},
	ProgressReporterManager: *github.com/onsi/ginkgo/v2/internal.ProgressReporterManager {
		lock: *(*sync.Mutex)(0xc000aa44e0),
		progressReporters: map[int]func() string [...],
		prCounter: 1,},
	cancel: context.WithCancelCause.func1 {
		c *context.cancelCtx = *(*context.cancelCtx)(0xc0008141e0)
	},
...

(dlv) p assertion.timeoutInterval
github.com/cenkalti/backoff/v4.Stop (-1)

Therefore the default timeout gets ignored. This seems wrong. gomega.Eventually should stop when the context gets canceled or the gomega.Eventually timeout occurs, whether that was set per call or is the default.

@toshipp
Copy link
Contributor

toshipp commented Oct 15, 2024

I encountered the same issue. I found the current behavior was introduced as a fix in e5105cf. It is not intuitive, IMO, but there may be some reason to have done.

@onsi
Copy link
Owner

onsi commented Oct 15, 2024

hey all - sorry for the delay This was - indeed - an intentional design choice. The thinking was that users choosing to pass in a context would want only the context to govern the timeout for a whole collection of Eventuallys and so layering on an additional non-explicit timeout (ie the default timeout) would be confusing/frustrating.

I'd propose adding a new configuration to Gomega like EnforceDefaultTimeoutsWhenUsingContext() to allow you to opt in to layering the default timeout on top of the context. This would also allow you to turn it on/off on a per spec basis as needed.

The alternative would be for me to detect when the passed in context is a ginkgo context that has no timeout and enforce the default timeout - but that seems too magical (even for me!)

Thoughts?

@pohly
Copy link
Author

pohly commented Oct 15, 2024

The thinking was that users choosing to pass in a context would want only the context to govern the timeout for a whole collection of Eventually

That's not how we use Gomega in Kubernetes. We have a global default and then the context typically always is the context straight from Ginkgo, with no extra timeouts added to it. If a gomega.Eventually needs a specific timeout, it gets set through WithTimeout, which is more convenient than the context.WithTimeout + cancel approach.

adding a new configuration to Gomega like EnforceDefaultTimeoutsWhenUsingContext()

That works for me.

@onsi
Copy link
Owner

onsi commented Oct 15, 2024

So y'all don't use the SpecTimeout(duration) decorators?

@pohly
Copy link
Author

pohly commented Oct 15, 2024

No, not in Kubernetes.

@toshipp
Copy link
Contributor

toshipp commented Oct 17, 2024

adding a new configuration to Gomega like EnforceDefaultTimeoutsWhenUsingContext()

looks good to me.

So y'all don't use the SpecTimeout(duration) decorators?

No. In my case, It tends to have more than one Eventually. I want to set timeout not to specs but to Eventuallys because I use Eventuallys to wait for something, so the entire spec timeout is the sum of them.

@onsi onsi closed this as completed in e4c4265 Oct 29, 2024
@onsi
Copy link
Owner

onsi commented Oct 29, 2024

Just added EnforceDefaultTimeoutsWhenUsingContexts() - will cut a release soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants