Files
nomad/helper/broker/notify_test.go
Marvin Chin be8575a8a2 Fix server shutdown not waiting for worker run completion (#19560)
* Move group into a separate helper module for reuse

* Add shutdownCh to worker

The shutdown channel is used to signal that worker has stopped.

* Make server shutdown block on workers' shutdownCh

* Fix waiting for eval broker state change blocking indefinitely

There was a race condition in the GenericNotifier between the
Run and WaitForChange functions, where WaitForChange blocks
trying to write to a full unsubscribeCh, but the Run function never
reads from the unsubscribeCh as it has already stopped.

This commit fixes it by unblocking if the notifier has been stopped.

* Bound the amount of time server shutdown waits on worker completion

* Fix lostcancel linter error

* Fix worker test using unexpected worker constructor

* Add changelog

---------

Co-authored-by: Marvin Chin <marvinchin@users.noreply.github.com>
2024-01-05 08:45:07 -06:00

64 lines
1.4 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package broker
import (
"context"
"sync"
"testing"
"time"
"github.com/hashicorp/nomad/ci"
"github.com/stretchr/testify/require"
)
func TestGenericNotifier(t *testing.T) {
ci.Parallel(t)
// Create the new notifier.
ctx, cancelFn := context.WithCancel(context.Background())
defer cancelFn()
notifier := NewGenericNotifier(ctx)
go notifier.Run()
// Ensure we have buffered channels.
require.Equal(t, 1, cap(notifier.publishCh))
require.Equal(t, 1, cap(notifier.subscribeCh))
require.Equal(t, 1, cap(notifier.unsubscribeCh))
// Test that the timeout works.
var timeoutWG sync.WaitGroup
for i := 0; i < 6; i++ {
go func(wg *sync.WaitGroup) {
wg.Add(1)
msg := notifier.WaitForChange(100 * time.Millisecond)
require.Equal(t, "wait timed out after 100ms", msg)
wg.Done()
}(&timeoutWG)
}
timeoutWG.Wait()
// Test that all subscribers receive an update when a single notification
// is sent.
var notifiedWG sync.WaitGroup
for i := 0; i < 6; i++ {
go func(wg *sync.WaitGroup) {
wg.Add(1)
msg := notifier.WaitForChange(3 * time.Second)
require.Equal(t, "we got an update and not a timeout", msg)
wg.Done()
}(&notifiedWG)
}
// Ensure the routines have had time to start before sending the notify
// signal, otherwise the test is a flake.
time.Sleep(500 * time.Millisecond)
notifier.Notify("we got an update and not a timeout")
notifiedWG.Wait()
}