mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-26 04:06:38 +00:00
Refactor sync fast path tests and fix CI flakiness
- Introduce `skipOnWindows` helper to properly skip tests relying on Unix specific paths. - Replace fixed sleep with `require.Eventually` in `waitForPeerDisconnect` to address flakiness in CI. - Split `commitFastPath` logic out of `runFastPathSync` to close race conditions and improve clarity. - Update tests to leverage new helpers and more precise assertions (e.g., `waitForPeerDisconnect`). - Add `flakyStore` test helper to exercise fail-closed behavior in flag handling. - Enhance `RunFastPathFlagRoutine` to disable the flag on store read errors.
This commit is contained in:
@@ -2,6 +2,8 @@ package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -127,3 +129,48 @@ func newFastPathTestStore(t *testing.T) store.StoreInterface {
|
||||
t.Helper()
|
||||
return gocache_store.NewGoCache(gocache.New(5*time.Minute, 10*time.Minute))
|
||||
}
|
||||
|
||||
func TestRunFastPathFlagRoutine_FailsClosedOnReadError(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
s := &flakyStore{
|
||||
StoreInterface: newFastPathTestStore(t),
|
||||
}
|
||||
require.NoError(t, s.Set(ctx, "peerSyncFastPath", "1"), "seed flag enabled")
|
||||
|
||||
flag := RunFastPathFlagRoutine(ctx, s, 50*time.Millisecond, "peerSyncFastPath")
|
||||
require.NotNil(t, flag)
|
||||
|
||||
assert.Eventually(t, flag.Enabled, 2*time.Second, 25*time.Millisecond, "flag should flip enabled while store reads succeed")
|
||||
|
||||
s.setGetError(errors.New("simulated transient store failure"))
|
||||
assert.Eventually(t, func() bool {
|
||||
return !flag.Enabled()
|
||||
}, 2*time.Second, 25*time.Millisecond, "flag should flip disabled on store read error (fail-closed)")
|
||||
|
||||
s.setGetError(nil)
|
||||
assert.Eventually(t, flag.Enabled, 2*time.Second, 25*time.Millisecond, "flag should recover once the store read succeeds again")
|
||||
}
|
||||
|
||||
// flakyStore wraps a real store and lets tests inject a transient Get error
|
||||
// without affecting Set/Delete. Used to exercise fail-closed behaviour.
|
||||
type flakyStore struct {
|
||||
store.StoreInterface
|
||||
getErr atomic.Pointer[error]
|
||||
}
|
||||
|
||||
func (f *flakyStore) Get(ctx context.Context, key any) (any, error) {
|
||||
if errPtr := f.getErr.Load(); errPtr != nil && *errPtr != nil {
|
||||
return nil, *errPtr
|
||||
}
|
||||
return f.StoreInterface.Get(ctx, key)
|
||||
}
|
||||
|
||||
func (f *flakyStore) setGetError(err error) {
|
||||
if err == nil {
|
||||
f.getErr.Store(nil)
|
||||
return
|
||||
}
|
||||
f.getErr.Store(&err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user