mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-11 04:52:08 +00:00
mount-utils: fix flaky test 'TestFormat'
Signed-off-by: TommyStarK <thomasmilox@gmail.com>
This commit is contained in:
parent
b1f901acf4
commit
1c45bacfb0
@ -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{
|
||||
|
Loading…
Reference in New Issue
Block a user