mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 12:07:47 +00:00
test/integration/scheduler: fix data races
The plugins get called by scheduler goroutines. At least the polling seems to be done concurrently and thus needs locking. Locking the PreBindPlugin state is less obvious. It might be that the scheduler is really done with the test pod, but that ordering doesn't seem to be enough for the race detector. It's simpler to add mutex locking.
This commit is contained in:
parent
f70c26d495
commit
9e9a6cde4b
@ -14,13 +14,15 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package plugins contains functional tests for scheduler plugin support.
|
||||||
|
// Beware that the plugins in this directory are not meant to be used in
|
||||||
|
// performance tests because they don't behave like real plugins.
|
||||||
package plugins
|
package plugins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -65,7 +67,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PreEnqueuePlugin struct {
|
type PreEnqueuePlugin struct {
|
||||||
called int32
|
called int
|
||||||
admit bool
|
admit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,23 +78,62 @@ type PreFilterPlugin struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ScorePlugin struct {
|
type ScorePlugin struct {
|
||||||
|
mutex sync.Mutex
|
||||||
failScore bool
|
failScore bool
|
||||||
numScoreCalled int32
|
numScoreCalled int
|
||||||
highScoreNode string
|
highScoreNode string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sp *ScorePlugin) deepCopy() *ScorePlugin {
|
||||||
|
sp.mutex.Lock()
|
||||||
|
defer sp.mutex.Unlock()
|
||||||
|
|
||||||
|
return &ScorePlugin{
|
||||||
|
failScore: sp.failScore,
|
||||||
|
numScoreCalled: sp.numScoreCalled,
|
||||||
|
highScoreNode: sp.highScoreNode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ScoreWithNormalizePlugin struct {
|
type ScoreWithNormalizePlugin struct {
|
||||||
|
mutex sync.Mutex
|
||||||
numScoreCalled int
|
numScoreCalled int
|
||||||
numNormalizeScoreCalled int
|
numNormalizeScoreCalled int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sp *ScoreWithNormalizePlugin) deepCopy() *ScoreWithNormalizePlugin {
|
||||||
|
sp.mutex.Lock()
|
||||||
|
defer sp.mutex.Unlock()
|
||||||
|
|
||||||
|
return &ScoreWithNormalizePlugin{
|
||||||
|
numScoreCalled: sp.numScoreCalled,
|
||||||
|
numNormalizeScoreCalled: sp.numNormalizeScoreCalled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type FilterPlugin struct {
|
type FilterPlugin struct {
|
||||||
numFilterCalled int32
|
mutex sync.Mutex
|
||||||
|
numFilterCalled int
|
||||||
failFilter bool
|
failFilter bool
|
||||||
rejectFilter bool
|
rejectFilter bool
|
||||||
|
|
||||||
numCalledPerPod map[string]int
|
numCalledPerPod map[string]int
|
||||||
sync.RWMutex
|
}
|
||||||
|
|
||||||
|
func (fp *FilterPlugin) deepCopy() *FilterPlugin {
|
||||||
|
fp.mutex.Lock()
|
||||||
|
defer fp.mutex.Unlock()
|
||||||
|
|
||||||
|
clone := &FilterPlugin{
|
||||||
|
numFilterCalled: fp.numFilterCalled,
|
||||||
|
failFilter: fp.failFilter,
|
||||||
|
rejectFilter: fp.rejectFilter,
|
||||||
|
numCalledPerPod: make(map[string]int),
|
||||||
|
}
|
||||||
|
for pod, counter := range fp.numCalledPerPod {
|
||||||
|
clone.numCalledPerPod[pod] = counter
|
||||||
|
}
|
||||||
|
return clone
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostFilterPlugin struct {
|
type PostFilterPlugin struct {
|
||||||
@ -118,6 +159,7 @@ type PreScorePlugin struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PreBindPlugin struct {
|
type PreBindPlugin struct {
|
||||||
|
mutex sync.Mutex
|
||||||
numPreBindCalled int
|
numPreBindCalled int
|
||||||
failPreBind bool
|
failPreBind bool
|
||||||
rejectPreBind bool
|
rejectPreBind bool
|
||||||
@ -127,7 +169,34 @@ type PreBindPlugin struct {
|
|||||||
podUIDs map[types.UID]struct{}
|
podUIDs map[types.UID]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pp *PreBindPlugin) set(fail, reject, succeed bool) {
|
||||||
|
pp.mutex.Lock()
|
||||||
|
defer pp.mutex.Unlock()
|
||||||
|
|
||||||
|
pp.failPreBind = fail
|
||||||
|
pp.rejectPreBind = reject
|
||||||
|
pp.succeedOnRetry = succeed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pp *PreBindPlugin) deepCopy() *PreBindPlugin {
|
||||||
|
pp.mutex.Lock()
|
||||||
|
defer pp.mutex.Unlock()
|
||||||
|
|
||||||
|
clone := &PreBindPlugin{
|
||||||
|
numPreBindCalled: pp.numPreBindCalled,
|
||||||
|
failPreBind: pp.failPreBind,
|
||||||
|
rejectPreBind: pp.rejectPreBind,
|
||||||
|
succeedOnRetry: pp.succeedOnRetry,
|
||||||
|
podUIDs: make(map[types.UID]struct{}),
|
||||||
|
}
|
||||||
|
for uid := range pp.podUIDs {
|
||||||
|
clone.podUIDs[uid] = struct{}{}
|
||||||
|
}
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
type BindPlugin struct {
|
type BindPlugin struct {
|
||||||
|
mutex sync.Mutex
|
||||||
name string
|
name string
|
||||||
numBindCalled int
|
numBindCalled int
|
||||||
bindStatus *framework.Status
|
bindStatus *framework.Status
|
||||||
@ -135,13 +204,39 @@ type BindPlugin struct {
|
|||||||
pluginInvokeEventChan chan pluginInvokeEvent
|
pluginInvokeEventChan chan pluginInvokeEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bp *BindPlugin) deepCopy() *BindPlugin {
|
||||||
|
bp.mutex.Lock()
|
||||||
|
defer bp.mutex.Unlock()
|
||||||
|
|
||||||
|
return &BindPlugin{
|
||||||
|
name: bp.name,
|
||||||
|
numBindCalled: bp.numBindCalled,
|
||||||
|
bindStatus: bp.bindStatus,
|
||||||
|
client: bp.client,
|
||||||
|
pluginInvokeEventChan: bp.pluginInvokeEventChan,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type PostBindPlugin struct {
|
type PostBindPlugin struct {
|
||||||
|
mutex sync.Mutex
|
||||||
name string
|
name string
|
||||||
numPostBindCalled int
|
numPostBindCalled int
|
||||||
pluginInvokeEventChan chan pluginInvokeEvent
|
pluginInvokeEventChan chan pluginInvokeEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pp *PostBindPlugin) deepCopy() *PostBindPlugin {
|
||||||
|
pp.mutex.Lock()
|
||||||
|
defer pp.mutex.Unlock()
|
||||||
|
|
||||||
|
return &PostBindPlugin{
|
||||||
|
name: pp.name,
|
||||||
|
numPostBindCalled: pp.numPostBindCalled,
|
||||||
|
pluginInvokeEventChan: pp.pluginInvokeEventChan,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type PermitPlugin struct {
|
type PermitPlugin struct {
|
||||||
|
mutex sync.Mutex
|
||||||
name string
|
name string
|
||||||
numPermitCalled int
|
numPermitCalled int
|
||||||
failPermit bool
|
failPermit bool
|
||||||
@ -156,6 +251,26 @@ type PermitPlugin struct {
|
|||||||
fh framework.Handle
|
fh framework.Handle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pp *PermitPlugin) deepCopy() *PermitPlugin {
|
||||||
|
pp.mutex.Lock()
|
||||||
|
defer pp.mutex.Unlock()
|
||||||
|
|
||||||
|
return &PermitPlugin{
|
||||||
|
name: pp.name,
|
||||||
|
numPermitCalled: pp.numPermitCalled,
|
||||||
|
failPermit: pp.failPermit,
|
||||||
|
rejectPermit: pp.rejectPermit,
|
||||||
|
timeoutPermit: pp.timeoutPermit,
|
||||||
|
waitAndRejectPermit: pp.waitAndRejectPermit,
|
||||||
|
waitAndAllowPermit: pp.waitAndAllowPermit,
|
||||||
|
cancelled: pp.cancelled,
|
||||||
|
waitingPod: pp.waitingPod,
|
||||||
|
rejectingPod: pp.rejectingPod,
|
||||||
|
allowingPod: pp.allowingPod,
|
||||||
|
fh: pp.fh,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
enqueuePluginName = "enqueue-plugin"
|
enqueuePluginName = "enqueue-plugin"
|
||||||
prefilterPluginName = "prefilter-plugin"
|
prefilterPluginName = "prefilter-plugin"
|
||||||
@ -216,13 +331,16 @@ func (sp *ScorePlugin) Name() string {
|
|||||||
|
|
||||||
// Score returns the score of scheduling a pod on a specific node.
|
// Score returns the score of scheduling a pod on a specific node.
|
||||||
func (sp *ScorePlugin) Score(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) (int64, *framework.Status) {
|
func (sp *ScorePlugin) Score(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) (int64, *framework.Status) {
|
||||||
curCalled := atomic.AddInt32(&sp.numScoreCalled, 1)
|
sp.mutex.Lock()
|
||||||
|
defer sp.mutex.Unlock()
|
||||||
|
|
||||||
|
sp.numScoreCalled++
|
||||||
if sp.failScore {
|
if sp.failScore {
|
||||||
return 0, framework.NewStatus(framework.Error, fmt.Sprintf("injecting failure for pod %v", p.Name))
|
return 0, framework.NewStatus(framework.Error, fmt.Sprintf("injecting failure for pod %v", p.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
score := int64(1)
|
score := int64(1)
|
||||||
if curCalled == 1 {
|
if sp.numScoreCalled == 1 {
|
||||||
// The first node is scored the highest, the rest is scored lower.
|
// The first node is scored the highest, the rest is scored lower.
|
||||||
sp.highScoreNode = nodeName
|
sp.highScoreNode = nodeName
|
||||||
score = framework.MaxNodeScore
|
score = framework.MaxNodeScore
|
||||||
@ -241,6 +359,9 @@ func (sp *ScoreWithNormalizePlugin) Name() string {
|
|||||||
|
|
||||||
// Score returns the score of scheduling a pod on a specific node.
|
// Score returns the score of scheduling a pod on a specific node.
|
||||||
func (sp *ScoreWithNormalizePlugin) Score(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) (int64, *framework.Status) {
|
func (sp *ScoreWithNormalizePlugin) Score(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) (int64, *framework.Status) {
|
||||||
|
sp.mutex.Lock()
|
||||||
|
defer sp.mutex.Unlock()
|
||||||
|
|
||||||
sp.numScoreCalled++
|
sp.numScoreCalled++
|
||||||
score := int64(10)
|
score := int64(10)
|
||||||
return score, nil
|
return score, nil
|
||||||
@ -263,12 +384,12 @@ func (fp *FilterPlugin) Name() string {
|
|||||||
// Filter is a test function that returns an error or nil, depending on the
|
// Filter is a test function that returns an error or nil, depending on the
|
||||||
// value of "failFilter".
|
// value of "failFilter".
|
||||||
func (fp *FilterPlugin) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
func (fp *FilterPlugin) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
|
||||||
atomic.AddInt32(&fp.numFilterCalled, 1)
|
fp.mutex.Lock()
|
||||||
|
defer fp.mutex.Unlock()
|
||||||
|
|
||||||
|
fp.numFilterCalled++
|
||||||
if fp.numCalledPerPod != nil {
|
if fp.numCalledPerPod != nil {
|
||||||
fp.Lock()
|
|
||||||
fp.numCalledPerPod[fmt.Sprintf("%v/%v", pod.Namespace, pod.Name)]++
|
fp.numCalledPerPod[fmt.Sprintf("%v/%v", pod.Namespace, pod.Name)]++
|
||||||
fp.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if fp.failFilter {
|
if fp.failFilter {
|
||||||
@ -328,6 +449,9 @@ func (pp *PreBindPlugin) Name() string {
|
|||||||
|
|
||||||
// PreBind is a test function that returns (true, nil) or errors for testing.
|
// PreBind is a test function that returns (true, nil) or errors for testing.
|
||||||
func (pp *PreBindPlugin) PreBind(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
|
func (pp *PreBindPlugin) PreBind(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
|
||||||
|
pp.mutex.Lock()
|
||||||
|
defer pp.mutex.Unlock()
|
||||||
|
|
||||||
pp.numPreBindCalled++
|
pp.numPreBindCalled++
|
||||||
if _, tried := pp.podUIDs[pod.UID]; tried && pp.succeedOnRetry {
|
if _, tried := pp.podUIDs[pod.UID]; tried && pp.succeedOnRetry {
|
||||||
return nil
|
return nil
|
||||||
@ -349,6 +473,9 @@ func (bp *BindPlugin) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bp *BindPlugin) Bind(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) *framework.Status {
|
func (bp *BindPlugin) Bind(ctx context.Context, state *framework.CycleState, p *v1.Pod, nodeName string) *framework.Status {
|
||||||
|
bp.mutex.Lock()
|
||||||
|
defer bp.mutex.Unlock()
|
||||||
|
|
||||||
bp.numBindCalled++
|
bp.numBindCalled++
|
||||||
if bp.pluginInvokeEventChan != nil {
|
if bp.pluginInvokeEventChan != nil {
|
||||||
bp.pluginInvokeEventChan <- pluginInvokeEvent{pluginName: bp.Name(), val: bp.numBindCalled}
|
bp.pluginInvokeEventChan <- pluginInvokeEvent{pluginName: bp.Name(), val: bp.numBindCalled}
|
||||||
@ -374,6 +501,9 @@ func (pp *PostBindPlugin) Name() string {
|
|||||||
|
|
||||||
// PostBind is a test function, which counts the number of times called.
|
// PostBind is a test function, which counts the number of times called.
|
||||||
func (pp *PostBindPlugin) PostBind(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) {
|
func (pp *PostBindPlugin) PostBind(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) {
|
||||||
|
pp.mutex.Lock()
|
||||||
|
defer pp.mutex.Unlock()
|
||||||
|
|
||||||
pp.numPostBindCalled++
|
pp.numPostBindCalled++
|
||||||
if pp.pluginInvokeEventChan != nil {
|
if pp.pluginInvokeEventChan != nil {
|
||||||
pp.pluginInvokeEventChan <- pluginInvokeEvent{pluginName: pp.Name(), val: pp.numPostBindCalled}
|
pp.pluginInvokeEventChan <- pluginInvokeEvent{pluginName: pp.Name(), val: pp.numPostBindCalled}
|
||||||
@ -443,6 +573,9 @@ func (pp *PermitPlugin) Name() string {
|
|||||||
|
|
||||||
// Permit implements the permit test plugin.
|
// Permit implements the permit test plugin.
|
||||||
func (pp *PermitPlugin) Permit(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (*framework.Status, time.Duration) {
|
func (pp *PermitPlugin) Permit(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (*framework.Status, time.Duration) {
|
||||||
|
pp.mutex.Lock()
|
||||||
|
defer pp.mutex.Unlock()
|
||||||
|
|
||||||
pp.numPermitCalled++
|
pp.numPermitCalled++
|
||||||
if pp.failPermit {
|
if pp.failPermit {
|
||||||
return framework.NewStatus(framework.Error, fmt.Sprintf("injecting failure for pod %v", pod.Name)), 0
|
return framework.NewStatus(framework.Error, fmt.Sprintf("injecting failure for pod %v", pod.Name)), 0
|
||||||
@ -454,6 +587,8 @@ func (pp *PermitPlugin) Permit(ctx context.Context, state *framework.CycleState,
|
|||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
pp.mutex.Lock()
|
||||||
|
defer pp.mutex.Unlock()
|
||||||
pp.cancelled = true
|
pp.cancelled = true
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -487,6 +622,8 @@ func (pp *PermitPlugin) allowAllPods() {
|
|||||||
|
|
||||||
// rejectAllPods rejects all waiting pods.
|
// rejectAllPods rejects all waiting pods.
|
||||||
func (pp *PermitPlugin) rejectAllPods() {
|
func (pp *PermitPlugin) rejectAllPods() {
|
||||||
|
pp.mutex.Lock()
|
||||||
|
defer pp.mutex.Unlock()
|
||||||
pp.fh.IterateOverWaitingPods(func(wp framework.WaitingPod) { wp.Reject(pp.name, "rejectAllPods") })
|
pp.fh.IterateOverWaitingPods(func(wp framework.WaitingPod) { wp.Reject(pp.name, "rejectAllPods") })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,18 +696,18 @@ func TestPreFilterPlugin(t *testing.T) {
|
|||||||
|
|
||||||
// TestPostFilterPlugin tests invocation of postFilter plugins.
|
// TestPostFilterPlugin tests invocation of postFilter plugins.
|
||||||
func TestPostFilterPlugin(t *testing.T) {
|
func TestPostFilterPlugin(t *testing.T) {
|
||||||
var numNodes int32 = 1
|
numNodes := 1
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
numNodes int32
|
numNodes int
|
||||||
rejectFilter bool
|
rejectFilter bool
|
||||||
failScore bool
|
failScore bool
|
||||||
rejectPostFilter bool
|
rejectPostFilter bool
|
||||||
rejectPostFilter2 bool
|
rejectPostFilter2 bool
|
||||||
breakPostFilter bool
|
breakPostFilter bool
|
||||||
breakPostFilter2 bool
|
breakPostFilter2 bool
|
||||||
expectFilterNumCalled int32
|
expectFilterNumCalled int
|
||||||
expectScoreNumCalled int32
|
expectScoreNumCalled int
|
||||||
expectPostFilterNumCalled int
|
expectPostFilterNumCalled int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -712,20 +849,20 @@ func TestPostFilterPlugin(t *testing.T) {
|
|||||||
t.Errorf("Didn't expect the pod to be scheduled.")
|
t.Errorf("Didn't expect the pod to be scheduled.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if numFilterCalled := atomic.LoadInt32(&filterPlugin.numFilterCalled); numFilterCalled < tt.expectFilterNumCalled {
|
if numFilterCalled := filterPlugin.deepCopy().numFilterCalled; numFilterCalled < tt.expectFilterNumCalled {
|
||||||
t.Errorf("Expected the filter plugin to be called at least %v times, but got %v.", tt.expectFilterNumCalled, numFilterCalled)
|
t.Errorf("Expected the filter plugin to be called at least %v times, but got %v.", tt.expectFilterNumCalled, numFilterCalled)
|
||||||
}
|
}
|
||||||
if numScoreCalled := atomic.LoadInt32(&scorePlugin.numScoreCalled); numScoreCalled < tt.expectScoreNumCalled {
|
if numScoreCalled := scorePlugin.deepCopy().numScoreCalled; numScoreCalled < tt.expectScoreNumCalled {
|
||||||
t.Errorf("Expected the score plugin to be called at least %v times, but got %v.", tt.expectScoreNumCalled, numScoreCalled)
|
t.Errorf("Expected the score plugin to be called at least %v times, but got %v.", tt.expectScoreNumCalled, numScoreCalled)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = testutils.WaitForPodToSchedule(testCtx.ClientSet, pod); err != nil {
|
if err = testutils.WaitForPodToSchedule(testCtx.ClientSet, pod); err != nil {
|
||||||
t.Errorf("Expected the pod to be scheduled. error: %v", err)
|
t.Errorf("Expected the pod to be scheduled. error: %v", err)
|
||||||
}
|
}
|
||||||
if numFilterCalled := atomic.LoadInt32(&filterPlugin.numFilterCalled); numFilterCalled != tt.expectFilterNumCalled {
|
if numFilterCalled := filterPlugin.deepCopy().numFilterCalled; numFilterCalled != tt.expectFilterNumCalled {
|
||||||
t.Errorf("Expected the filter plugin to be called %v times, but got %v.", tt.expectFilterNumCalled, numFilterCalled)
|
t.Errorf("Expected the filter plugin to be called %v times, but got %v.", tt.expectFilterNumCalled, numFilterCalled)
|
||||||
}
|
}
|
||||||
if numScoreCalled := atomic.LoadInt32(&scorePlugin.numScoreCalled); numScoreCalled != tt.expectScoreNumCalled {
|
if numScoreCalled := scorePlugin.deepCopy().numScoreCalled; numScoreCalled != tt.expectScoreNumCalled {
|
||||||
t.Errorf("Expected the score plugin to be called %v times, but got %v.", tt.expectScoreNumCalled, numScoreCalled)
|
t.Errorf("Expected the score plugin to be called %v times, but got %v.", tt.expectScoreNumCalled, numScoreCalled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -792,7 +929,7 @@ func TestScorePlugin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if numScoreCalled := atomic.LoadInt32(&scorePlugin.numScoreCalled); numScoreCalled == 0 {
|
if numScoreCalled := scorePlugin.deepCopy().numScoreCalled; numScoreCalled == 0 {
|
||||||
t.Errorf("Expected the score plugin to be called.")
|
t.Errorf("Expected the score plugin to be called.")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -820,10 +957,11 @@ func TestNormalizeScorePlugin(t *testing.T) {
|
|||||||
t.Errorf("Expected the pod to be scheduled. error: %v", err)
|
t.Errorf("Expected the pod to be scheduled. error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if scoreWithNormalizePlugin.numScoreCalled == 0 {
|
p := scoreWithNormalizePlugin.deepCopy()
|
||||||
|
if p.numScoreCalled == 0 {
|
||||||
t.Errorf("Expected the score plugin to be called.")
|
t.Errorf("Expected the score plugin to be called.")
|
||||||
}
|
}
|
||||||
if scoreWithNormalizePlugin.numNormalizeScoreCalled == 0 {
|
if p.numNormalizeScoreCalled == 0 {
|
||||||
t.Error("Expected the normalize score plugin to be called")
|
t.Error("Expected the normalize score plugin to be called")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -980,9 +1118,8 @@ func TestPrebindPlugin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preBindPlugin.failPreBind = test.fail
|
preBindPlugin.set(test.fail, test.reject, test.succeedOnRetry)
|
||||||
preBindPlugin.rejectPreBind = test.reject
|
|
||||||
preBindPlugin.succeedOnRetry = test.succeedOnRetry
|
|
||||||
// Create a best effort pod.
|
// Create a best effort pod.
|
||||||
pod, err := createPausePod(testCtx.ClientSet,
|
pod, err := createPausePod(testCtx.ClientSet,
|
||||||
initPausePod(&testutils.PausePodConfig{Name: "test-pod", Namespace: testCtx.NS.Name}))
|
initPausePod(&testutils.PausePodConfig{Name: "test-pod", Namespace: testCtx.NS.Name}))
|
||||||
@ -1006,7 +1143,8 @@ func TestPrebindPlugin(t *testing.T) {
|
|||||||
t.Errorf("Expected the pod to be scheduled. error: %v", err)
|
t.Errorf("Expected the pod to be scheduled. error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if preBindPlugin.numPreBindCalled == 0 {
|
p := preBindPlugin.deepCopy()
|
||||||
|
if p.numPreBindCalled == 0 {
|
||||||
t.Errorf("Expected the prebind plugin to be called.")
|
t.Errorf("Expected the prebind plugin to be called.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1014,7 +1152,7 @@ func TestPrebindPlugin(t *testing.T) {
|
|||||||
if err := wait.Poll(10*time.Millisecond, 15*time.Second, func() (bool, error) {
|
if err := wait.Poll(10*time.Millisecond, 15*time.Second, func() (bool, error) {
|
||||||
// 2 means the unschedulable pod is expected to be retried at least twice.
|
// 2 means the unschedulable pod is expected to be retried at least twice.
|
||||||
// (one initial attempt plus the one moved by the preBind pod)
|
// (one initial attempt plus the one moved by the preBind pod)
|
||||||
return int(filterPlugin.numFilterCalled) >= 2*nodesNum, nil
|
return filterPlugin.deepCopy().numFilterCalled >= 2*nodesNum, nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Errorf("Timed out waiting for the unschedulable Pod to be retried at least twice.")
|
t.Errorf("Timed out waiting for the unschedulable Pod to be retried at least twice.")
|
||||||
}
|
}
|
||||||
@ -1523,27 +1661,30 @@ func TestBindPlugin(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("can't get pod: %v", err)
|
t.Errorf("can't get pod: %v", err)
|
||||||
}
|
}
|
||||||
|
p1 := bindPlugin1.deepCopy()
|
||||||
|
p2 := bindPlugin2.deepCopy()
|
||||||
if test.expectBoundByScheduler {
|
if test.expectBoundByScheduler {
|
||||||
if pod.Annotations[bindPluginAnnotation] != "" {
|
if pod.Annotations[bindPluginAnnotation] != "" {
|
||||||
t.Errorf("Expected the pod to be bound by scheduler instead of by bindplugin %s", pod.Annotations[bindPluginAnnotation])
|
t.Errorf("Expected the pod to be bound by scheduler instead of by bindplugin %s", pod.Annotations[bindPluginAnnotation])
|
||||||
}
|
}
|
||||||
if bindPlugin1.numBindCalled != 1 || bindPlugin2.numBindCalled != 1 {
|
if p1.numBindCalled != 1 || p2.numBindCalled != 1 {
|
||||||
t.Errorf("Expected each bind plugin to be called once, was called %d and %d times.", bindPlugin1.numBindCalled, bindPlugin2.numBindCalled)
|
t.Errorf("Expected each bind plugin to be called once, was called %d and %d times.", p1.numBindCalled, p2.numBindCalled)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if pod.Annotations[bindPluginAnnotation] != test.expectBindPluginName {
|
if pod.Annotations[bindPluginAnnotation] != test.expectBindPluginName {
|
||||||
t.Errorf("Expected the pod to be bound by bindplugin %s instead of by bindplugin %s", test.expectBindPluginName, pod.Annotations[bindPluginAnnotation])
|
t.Errorf("Expected the pod to be bound by bindplugin %s instead of by bindplugin %s", test.expectBindPluginName, pod.Annotations[bindPluginAnnotation])
|
||||||
}
|
}
|
||||||
if bindPlugin1.numBindCalled != 1 {
|
if p1.numBindCalled != 1 {
|
||||||
t.Errorf("Expected %s to be called once, was called %d times.", bindPlugin1.Name(), bindPlugin1.numBindCalled)
|
t.Errorf("Expected %s to be called once, was called %d times.", p1.Name(), p1.numBindCalled)
|
||||||
}
|
}
|
||||||
if test.expectBindPluginName == bindPlugin1.Name() && bindPlugin2.numBindCalled > 0 {
|
if test.expectBindPluginName == p1.Name() && p2.numBindCalled > 0 {
|
||||||
// expect bindplugin1 succeeded to bind the pod and bindplugin2 should not be called.
|
// expect bindplugin1 succeeded to bind the pod and bindplugin2 should not be called.
|
||||||
t.Errorf("Expected %s not to be called, was called %d times.", bindPlugin2.Name(), bindPlugin1.numBindCalled)
|
t.Errorf("Expected %s not to be called, was called %d times.", p2.Name(), p2.numBindCalled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = wait.Poll(10*time.Millisecond, 30*time.Second, func() (done bool, err error) {
|
if err = wait.Poll(10*time.Millisecond, 30*time.Second, func() (done bool, err error) {
|
||||||
return postBindPlugin.numPostBindCalled == 1, nil
|
p := postBindPlugin.deepCopy()
|
||||||
|
return p.numPostBindCalled == 1, nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Errorf("Expected the postbind plugin to be called once, was called %d times.", postBindPlugin.numPostBindCalled)
|
t.Errorf("Expected the postbind plugin to be called once, was called %d times.", postBindPlugin.numPostBindCalled)
|
||||||
}
|
}
|
||||||
@ -1555,8 +1696,9 @@ func TestBindPlugin(t *testing.T) {
|
|||||||
if err = wait.Poll(10*time.Millisecond, 30*time.Second, podSchedulingError(testCtx.ClientSet, pod.Namespace, pod.Name)); err != nil {
|
if err = wait.Poll(10*time.Millisecond, 30*time.Second, podSchedulingError(testCtx.ClientSet, pod.Namespace, pod.Name)); err != nil {
|
||||||
t.Errorf("Expected a scheduling error, but didn't get it. error: %v", err)
|
t.Errorf("Expected a scheduling error, but didn't get it. error: %v", err)
|
||||||
}
|
}
|
||||||
if postBindPlugin.numPostBindCalled > 0 {
|
p := postBindPlugin.deepCopy()
|
||||||
t.Errorf("Didn't expect the postbind plugin to be called %d times.", postBindPlugin.numPostBindCalled)
|
if p.numPostBindCalled > 0 {
|
||||||
|
t.Errorf("Didn't expect the postbind plugin to be called %d times.", p.numPostBindCalled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for j := range test.expectInvokeEvents {
|
for j := range test.expectInvokeEvents {
|
||||||
@ -1732,7 +1874,8 @@ func TestPermitPlugin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if perPlugin.numPermitCalled == 0 {
|
p := perPlugin.deepCopy()
|
||||||
|
if p.numPermitCalled == 0 {
|
||||||
t.Errorf("Expected the permit plugin to be called.")
|
t.Errorf("Expected the permit plugin to be called.")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1825,7 +1968,9 @@ func TestPermitPluginsCancelled(t *testing.T) {
|
|||||||
perPlugin1.rejectAllPods()
|
perPlugin1.rejectAllPods()
|
||||||
// Wait some time for the permit plugins to be cancelled
|
// Wait some time for the permit plugins to be cancelled
|
||||||
err = wait.Poll(10*time.Millisecond, 30*time.Second, func() (bool, error) {
|
err = wait.Poll(10*time.Millisecond, 30*time.Second, func() (bool, error) {
|
||||||
return perPlugin1.cancelled && perPlugin2.cancelled, nil
|
p1 := perPlugin1.deepCopy()
|
||||||
|
p2 := perPlugin2.deepCopy()
|
||||||
|
return p1.cancelled && p2.cancelled, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Expected all permit plugins to be cancelled")
|
t.Errorf("Expected all permit plugins to be cancelled")
|
||||||
@ -1910,7 +2055,8 @@ func TestCoSchedulingWithPermitPlugin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if permitPlugin.numPermitCalled == 0 {
|
p := permitPlugin.deepCopy()
|
||||||
|
if p.numPermitCalled == 0 {
|
||||||
t.Errorf("Expected the permit plugin to be called.")
|
t.Errorf("Expected the permit plugin to be called.")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -2249,9 +2395,8 @@ func TestPreemptWithPermitPlugin(t *testing.T) {
|
|||||||
t.Fatalf("Expected the waiting pod to get preempted.")
|
t.Fatalf("Expected the waiting pod to get preempted.")
|
||||||
}
|
}
|
||||||
|
|
||||||
filterPlugin.RLock()
|
p := filterPlugin.deepCopy()
|
||||||
waitingPodCalled := filterPlugin.numCalledPerPod[fmt.Sprintf("%v/%v", w.Namespace, w.Name)]
|
waitingPodCalled := p.numCalledPerPod[fmt.Sprintf("%v/%v", w.Namespace, w.Name)]
|
||||||
filterPlugin.RUnlock()
|
|
||||||
if waitingPodCalled > tt.maxNumWaitingPodCalled {
|
if waitingPodCalled > tt.maxNumWaitingPodCalled {
|
||||||
t.Fatalf("Expected the waiting pod to be called %v times at most, but got %v", tt.maxNumWaitingPodCalled, waitingPodCalled)
|
t.Fatalf("Expected the waiting pod to be called %v times at most, but got %v", tt.maxNumWaitingPodCalled, waitingPodCalled)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user