mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-04 11:35:11 -04:00
52 lines
1.4 KiB
Go
52 lines
1.4 KiB
Go
package server
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/netbirdio/netbird/client/proto"
|
|
)
|
|
|
|
// The daemon takes guardedConfigMu before s.mutex. authorizeAndPrepareLogin
|
|
// takes s.mutex while holding guardedConfigMu, so a SetConfig that grabbed
|
|
// s.mutex first and then waited for guardedConfigMu would deadlock the daemon
|
|
// against a concurrent login: two unprivileged IPC calls are enough.
|
|
//
|
|
// The held guardedConfigMu below stands in for that login. While SetConfig waits
|
|
// for it, s.mutex must stay free, otherwise the login waiting for s.mutex could
|
|
// never release guardedConfigMu.
|
|
func TestSetConfig_TakesGuardedConfigMuBeforeServerMutex(t *testing.T) {
|
|
s, ctx, profName, username, _ := setupServerWithProfile(t)
|
|
|
|
s.guardedConfigMu.Lock()
|
|
|
|
done := make(chan error, 1)
|
|
go func() {
|
|
_, err := s.SetConfig(ctx, &proto.SetConfigRequest{
|
|
ProfileName: profName,
|
|
Username: username,
|
|
})
|
|
done <- err
|
|
}()
|
|
|
|
require.Never(t, func() bool {
|
|
if !s.mutex.TryLock() {
|
|
return true
|
|
}
|
|
s.mutex.Unlock()
|
|
return false
|
|
}, 500*time.Millisecond, 10*time.Millisecond,
|
|
"SetConfig held s.mutex while waiting for guardedConfigMu, which deadlocks against a concurrent login")
|
|
|
|
s.guardedConfigMu.Unlock()
|
|
|
|
select {
|
|
case err := <-done:
|
|
require.NoError(t, err)
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("SetConfig did not finish after guardedConfigMu was released")
|
|
}
|
|
}
|