mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-24 23:59:08 +02:00
* Use POSIX-like file read/write of json for windows + tests: allow renaming an open file.
77 lines
2.0 KiB
Go
77 lines
2.0 KiB
Go
package profilemanager
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// Regression test: a concurrent Get and Set of the ActiveProfileState will
|
|
// fail on Windows since the write is a temp file renamed over an open file.
|
|
// Windows will refuse to replace a file another handle holds open by default.
|
|
func TestActiveProfileState_ReadsDoNotBreakAConcurrentWrite(t *testing.T) {
|
|
withTempConfigDir(t, func(configDir string) {
|
|
withPatchedGlobals(t, configDir, func() {
|
|
sm := &ServiceManager{}
|
|
require.NoError(t, sm.CreateDefaultProfile())
|
|
require.NoError(t, sm.SetActiveProfileStateToDefault())
|
|
|
|
const switched = ID("0123456789abcdef0123456789abcdef")
|
|
const rounds = 50
|
|
|
|
var wg sync.WaitGroup
|
|
errs := make(chan error, 128)
|
|
|
|
for i := 0; i < 8; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for r := 0; r < rounds; r++ {
|
|
state, err := sm.GetActiveProfileState()
|
|
if err != nil {
|
|
errs <- fmt.Errorf("read: %w", err)
|
|
return
|
|
}
|
|
if state.ID != defaultProfileName && state.ID != switched {
|
|
errs <- fmt.Errorf("read: active profile is %q, which no writer wrote", state.ID)
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
for i := 0; i < 2; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for r := 0; r < rounds; r++ {
|
|
id := switched
|
|
if r%2 == 0 {
|
|
id = defaultProfileName
|
|
}
|
|
if err := sm.SetActiveProfileState(&ActiveProfileState{ID: id, Username: "testuser"}); err != nil {
|
|
errs <- fmt.Errorf("switch: %w", err)
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
close(errs)
|
|
|
|
for err := range errs {
|
|
assert.NoError(t, err, "a switch and a read of the active profile state must not collide")
|
|
}
|
|
|
|
state, err := sm.GetActiveProfileState()
|
|
require.NoError(t, err)
|
|
assert.Contains(t, []ID{defaultProfileName, switched}, state.ID,
|
|
"the file holds whichever switch landed last, not a mix of the two")
|
|
})
|
|
})
|
|
}
|