open-nomad/client/allocrunner/tasklifecycle/gate_test.go
Luiz Aoqui 25a63195da
test: remove flaky Gate test (#14575)
The concurrent gate access test is flaky since it depends on the order
of operations of two concurrent goroutines. Despite the heavy bias
towards one of the results, it's still possible to end the execution
with a closed gate.

I believe this case was created to test an earlier implementation where
the gate state was stored and mutated internally, so the access had to
be protected by a lock. However, the final implementation changed this
approach to be only channel-based, so there is no need for this flaky
test anymore.
2022-09-19 11:31:03 -04:00

119 lines
2.2 KiB
Go

package tasklifecycle
import (
"testing"
"time"
"github.com/hashicorp/nomad/ci"
"github.com/hashicorp/nomad/helper"
)
func TestGate(t *testing.T) {
ci.Parallel(t)
testCases := []struct {
name string
test func(*testing.T, *Gate)
}{
{
name: "starts blocked",
test: func(t *testing.T, g *Gate) {
requireChannelBlocking(t, g.WaitCh(), "wait")
},
},
{
name: "block",
test: func(t *testing.T, g *Gate) {
g.Close()
requireChannelBlocking(t, g.WaitCh(), "wait")
},
},
{
name: "allow",
test: func(t *testing.T, g *Gate) {
g.Open()
requireChannelPassing(t, g.WaitCh(), "wait")
},
},
{
name: "block twice",
test: func(t *testing.T, g *Gate) {
g.Close()
g.Close()
requireChannelBlocking(t, g.WaitCh(), "wait")
},
},
{
name: "allow twice",
test: func(t *testing.T, g *Gate) {
g.Open()
g.Open()
requireChannelPassing(t, g.WaitCh(), "wait")
},
},
{
name: "allow block allow",
test: func(t *testing.T, g *Gate) {
g.Open()
requireChannelPassing(t, g.WaitCh(), "first allow")
g.Close()
requireChannelBlocking(t, g.WaitCh(), "block")
g.Open()
requireChannelPassing(t, g.WaitCh(), "second allow")
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
shutdownCh := make(chan struct{})
defer close(shutdownCh)
g := NewGate(shutdownCh)
tc.test(t, g)
})
}
}
// TestGate_shutdown tests a gate with a closed shutdown channel.
func TestGate_shutdown(t *testing.T) {
ci.Parallel(t)
// Create a Gate with a closed shutdownCh.
shutdownCh := make(chan struct{})
close(shutdownCh)
g := NewGate(shutdownCh)
// Test that Open() and Close() doesn't block forever.
openCh := make(chan struct{})
closeCh := make(chan struct{})
go func() {
g.Open()
close(openCh)
}()
go func() {
g.Close()
close(closeCh)
}()
timer, stop := helper.NewSafeTimer(time.Second)
defer stop()
select {
case <-openCh:
case <-timer.C:
t.Fatalf("timeout waiting for gate operations")
}
select {
case <-closeCh:
case <-timer.C:
t.Fatalf("timeout waiting for gate operations")
}
// A Gate with a shutdownCh should be closed.
requireChannelBlocking(t, g.WaitCh(), "gate should be closed")
}