mount-utils: fix flaky test 'TestFormat'

Signed-off-by: TommyStarK <thomasmilox@gmail.com>
This commit is contained in:
TommyStarK 2023-04-23 19:33:23 +02:00
parent b1f901acf4
commit 1c45bacfb0

View File

@ -649,41 +649,28 @@ func TestCheckUmountError(t *testing.T) {
}
}
func TestFormat(t *testing.T) {
// TODO https://github.com/kubernetes/kubernetes/pull/117539#discussion_r1181873355
func TestFormatConcurrency(t *testing.T) {
const (
formatCount = 5
fstype = "ext4"
output = "complete"
cmdDuration = 1 * time.Millisecond
defaultTimeout = 1 * time.Minute
)
tests := []struct {
desc string
max int
timeout time.Duration
wantConcurrent int
desc string
max int
timeout time.Duration
}{
{
max: 0,
wantConcurrent: formatCount,
max: 2,
},
{
max: -1,
wantConcurrent: formatCount,
max: 3,
},
{
max: 1,
wantConcurrent: 1,
},
{
max: 3,
wantConcurrent: 3,
},
{
max: 3,
timeout: 1 * time.Nanosecond,
wantConcurrent: formatCount,
max: 4,
},
}
@ -693,20 +680,18 @@ func TestFormat(t *testing.T) {
tc.timeout = defaultTimeout
}
var concurrent, maxConcurrent int
var concurrent int
var mu sync.Mutex
witness := make(chan struct{})
exec := &testexec.FakeExec{}
for i := 0; i < formatCount; i++ {
exec.CommandScript = append(exec.CommandScript, makeFakeCommandAction(output, nil, func() {
mu.Lock()
concurrent++
if concurrent > maxConcurrent {
maxConcurrent = concurrent
}
mu.Unlock()
time.Sleep(cmdDuration)
<-witness
mu.Lock()
concurrent--
@ -715,23 +700,111 @@ func TestFormat(t *testing.T) {
}
mounter := NewSafeFormatAndMount(nil, exec, WithMaxConcurrentFormat(tc.max, tc.timeout))
var wg sync.WaitGroup
for i := 0; i < formatCount; i++ {
wg.Add(1)
// we run max+1 goroutines and block the command execution
// only max goroutine should be running and the additional one should wait
// for one to be released
for i := 0; i < tc.max+1; i++ {
go func() {
defer wg.Done()
mounter.format(fstype, nil)
}()
}
wg.Wait()
if maxConcurrent != tc.wantConcurrent {
t.Errorf("SafeFormatAndMount.format() got concurrency: %d, want: %d", maxConcurrent, tc.wantConcurrent)
// wait for all goorutines to be scheduled
time.Sleep(100 * time.Millisecond)
mu.Lock()
if concurrent != tc.max {
t.Errorf("SafeFormatAndMount.format() got concurrency: %d, want: %d", concurrent, tc.max)
}
mu.Unlock()
// signal the commands to finish the goroutines, this will allow the command
// that is pending to be executed
for i := 0; i < tc.max; i++ {
witness <- struct{}{}
}
// wait for all goroutines to acquire the lock and decrement the counter
time.Sleep(100 * time.Millisecond)
mu.Lock()
if concurrent != 1 {
t.Errorf("SafeFormatAndMount.format() got concurrency: %d, want: 1", concurrent)
}
mu.Unlock()
// signal the pending command to finish, no more command should be running
close(witness)
// wait a few for the last goroutine to acquire the lock and decrements the counter down to zero
time.Sleep(10 * time.Millisecond)
mu.Lock()
if concurrent != 0 {
t.Errorf("SafeFormatAndMount.format() got concurrency: %d, want: 0", concurrent)
}
mu.Unlock()
})
}
}
// TODO https://github.com/kubernetes/kubernetes/pull/117539#discussion_r1181873355
func TestFormatTimeout(t *testing.T) {
const (
formatCount = 5
fstype = "ext4"
output = "complete"
maxConcurrency = 4
timeout = 200 * time.Millisecond
)
var concurrent int
var mu sync.Mutex
witness := make(chan struct{})
exec := &testexec.FakeExec{}
for i := 0; i < formatCount; i++ {
exec.CommandScript = append(exec.CommandScript, makeFakeCommandAction(output, nil, func() {
mu.Lock()
concurrent++
mu.Unlock()
<-witness
mu.Lock()
concurrent--
mu.Unlock()
}))
}
mounter := NewSafeFormatAndMount(nil, exec, WithMaxConcurrentFormat(maxConcurrency, timeout))
for i := 0; i < maxConcurrency+1; i++ {
go func() {
mounter.format(fstype, nil)
}()
}
// wait a bit more than the configured timeout
time.Sleep(timeout + 100*time.Millisecond)
mu.Lock()
if concurrent != maxConcurrency+1 {
t.Errorf("SafeFormatAndMount.format() got concurrency: %d, want: %d", concurrent, maxConcurrency+1)
}
mu.Unlock()
// signal the pending commands to finish
close(witness)
// wait for all goroutines to acquire the lock and decrement the counter
time.Sleep(100 * time.Millisecond)
mu.Lock()
if concurrent != 0 {
t.Errorf("SafeFormatAndMount.format() got concurrency: %d, want: 0", concurrent)
}
mu.Unlock()
}
func makeFakeCommandAction(stdout string, err error, cmdFn func()) testexec.FakeCommandAction {
c := testexec.FakeCmd{
CombinedOutputScript: []testexec.FakeAction{