Skip to content

Conversation

@vikin91
Copy link
Contributor

@vikin91 vikin91 commented Jan 12, 2026

Description

Apply Go 1.25's testing/synctest package (https://pkg.go.dev/testing/synctest) to sensor/common/detector/queue/queue_test.go to make concurrent tests deterministic and significantly faster.

What changed

  • Wrap test cases in synctest.Test() which provides a fake clock and goroutine tracking
  • Replace time.Sleep with synctest.Wait() for goroutine synchronization
  • time.After and time.AfterFunc now advance instantly when goroutines block
  • Fix a pre-existing goroutine leak that synctest detected (orphaned goroutines after timeout)

Why

  • Speed: Test execution reduced from ~3.5s to ~0s (instant) - the fake clock eliminates real delays
  • Determinism: Tests no longer depend on timing, eliminating potential flakiness
  • Correctness: synctest's strict goroutine tracking exposed and helped fix a goroutine leak

Performance comparison

Metric Before After Improvement
Test time 3.51s 0.00s Instant
Package total ~4.2s ~0.6s ~7x faster

AI disclosure

This change was developed with AI assistance. The user reviewed the code, identified issues with test coverage preservation and improper use of buffered channels, and directed corrections. The final implementation was validated by the user.

User-facing documentation

Testing and quality

  • the change is production ready: the change is GA, or otherwise the functionality is gated by a feature flag
  • CI results are inspected

Automated testing

  • added unit tests
  • added e2e tests
  • added regression tests
  • added compatibility tests
  • modified existing tests

How I validated my change

  1. Ran baseline measurements (5 runs) before changes:

    go test -v ./sensor/common/detector/queue/...
    # Result: TestPauseAndResume ~3.51s per run
    
  2. Applied synctest changes and verified all 6 test scenarios pass:

    go test -v ./sensor/common/detector/queue/...
    # Result: All subtests pass with 0.00s execution time
    
  3. Ran post-change measurements (5 runs) to confirm speedup:

    go test -count=1 ./sensor/common/detector/queue/...
    # Result: Package completes in ~0.6s (down from ~4.2s)
    
  4. Verified test structure preserved: TestPauseAndResume with 6 subtests matching original names

Apply testing/synctest package to make queue tests deterministic
and faster. Changes:
- Replace time.Sleep with synctest.Wait() for goroutine synchronization
- Use fake clock for time.After/time.AfterFunc (runs instantly)
- Fix pre-existing goroutine leak detected by synctest's strict tracking
- Preserve original table-driven test structure

Test execution time reduced from ~3.5s to ~0s (instant).
@openshift-ci
Copy link

openshift-ci bot commented Jan 12, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • Consider using t.Cleanup in each subtest to stop the testStopper/queueStopper and call synctest.Wait(), so that goroutines are reliably cleaned up even if the test fails or bails out early.
  • There is a fair bit of repeated setup/teardown logic across the cases in TestPauseAndResume (creating stoppers, queue, final Stop/Wait), which could be factored into a small helper to reduce duplication and make the intended lifecycle easier to see.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider using t.Cleanup in each subtest to stop the testStopper/queueStopper and call synctest.Wait(), so that goroutines are reliably cleaned up even if the test fails or bails out early.
- There is a fair bit of repeated setup/teardown logic across the cases in TestPauseAndResume (creating stoppers, queue, final Stop/Wait), which could be factored into a small helper to reduce duplication and make the intended lifecycle easier to see.

## Individual Comments

### Comment 1
<location> `sensor/common/detector/queue/queue_test.go:37-46` </location>
<code_context>
+func noPull(t *testing.T, q *Queue[*string], stopper concurrency.Stopper) {
</code_context>

<issue_to_address>
**issue (testing):** noPull helper does not distinguish between a blocked Pull and an early-unblocked Pull that returns nil

The helper’s comment says it verifies that Pull() blocks when the queue is paused, but it only fails when a non-nil item is received. If Pull() returns nil early (e.g., due to the queue stopping), the goroutine exits without sending on ch and the test times out, treating this as success. To avoid this mismatch, either explicitly assert that Pull() is still blocked (e.g., by checking the goroutine is still running) or rename/reword the helper and add a separate test for the nil-while-paused case.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +37 to +46
func noPull(t *testing.T, q *Queue[*string], stopper concurrency.Stopper) {
t.Helper()
ch := make(chan *string)
go func() {
defer close(ch)
select {
case item := <-q.Pull():
ch <- item
// Pull returned - either got an item or queue was stopped (nil).
// Use nested select to avoid blocking if nobody reads from ch.
if item != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (testing): noPull helper does not distinguish between a blocked Pull and an early-unblocked Pull that returns nil

The helper’s comment says it verifies that Pull() blocks when the queue is paused, but it only fails when a non-nil item is received. If Pull() returns nil early (e.g., due to the queue stopping), the goroutine exits without sending on ch and the test times out, treating this as success. To avoid this mismatch, either explicitly assert that Pull() is still blocked (e.g., by checking the goroutine is still running) or rename/reword the helper and add a separate test for the nil-while-paused case.

@rhacs-bot
Copy link
Contributor

Images are ready for the commit at 12f4a20.

To use with deploy scripts, first export MAIN_IMAGE_TAG=4.10.x-747-g12f4a20476.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants