Merge pull request #63666 from xchapter7x/pkg-scheduler-factory

Automatic merge from submit-queue (batch tested with PRs 58487, 63666). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

use subtest for table units (pkg/scheduler/factory)

**What this PR does / why we need it**: Update scheduler's unit table tests to use subtest

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:

**Special notes for your reviewer**:
breaks up PR: https://github.com/kubernetes/kubernetes/pull/63281
/ref #63267

**Release note**:

```release-note
This PR will leverage subtests on the existing table tests for the scheduler units.
Some refactoring of error/status messages and functions to align with new approach.

```
pull/8/head
Kubernetes Submit Queue 2018-07-19 02:09:06 -07:00 committed by GitHub
commit 357decc9db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 228 additions and 168 deletions

View File

@ -27,27 +27,29 @@ import (
)
func TestCompareNodes(t *testing.T) {
compare := compareStrategy{}
tests := []struct {
name string
actual []string
cached []string
missing []string
redundant []string
}{
{
name: "redundant cached value",
actual: []string{"foo", "bar"},
cached: []string{"bar", "foo", "foobar"},
missing: []string{},
redundant: []string{"foobar"},
},
{
name: "missing cached value",
actual: []string{"foo", "bar", "foobar"},
cached: []string{"bar", "foo"},
missing: []string{"foobar"},
redundant: []string{},
},
{
name: "proper cache set",
actual: []string{"foo", "bar", "foobar"},
cached: []string{"bar", "foobar", "foo"},
missing: []string{},
@ -56,34 +58,40 @@ func TestCompareNodes(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
testCompareNodes(test.actual, test.cached, test.missing, test.redundant, t)
})
}
}
func testCompareNodes(actual, cached, missing, redundant []string, t *testing.T) {
compare := compareStrategy{}
nodes := []*v1.Node{}
for _, nodeName := range test.actual {
for _, nodeName := range actual {
node := &v1.Node{}
node.Name = nodeName
nodes = append(nodes, node)
}
nodeInfo := make(map[string]*schedulercache.NodeInfo)
for _, nodeName := range test.cached {
for _, nodeName := range cached {
nodeInfo[nodeName] = &schedulercache.NodeInfo{}
}
m, r := compare.CompareNodes(nodes, nodeInfo)
if !reflect.DeepEqual(m, test.missing) {
t.Errorf("missing expected to be %s; got %s", test.missing, m)
if !reflect.DeepEqual(m, missing) {
t.Errorf("missing expected to be %s; got %s", missing, m)
}
if !reflect.DeepEqual(r, test.redundant) {
t.Errorf("redundant expected to be %s; got %s", test.redundant, r)
}
if !reflect.DeepEqual(r, redundant) {
t.Errorf("redundant expected to be %s; got %s", redundant, r)
}
}
func TestComparePods(t *testing.T) {
compare := compareStrategy{}
tests := []struct {
name string
actual []string
cached []string
queued []string
@ -91,6 +99,7 @@ func TestComparePods(t *testing.T) {
redundant []string
}{
{
name: "redundant cached value",
actual: []string{"foo", "bar"},
cached: []string{"bar", "foo", "foobar"},
queued: []string{},
@ -98,6 +107,7 @@ func TestComparePods(t *testing.T) {
redundant: []string{"foobar"},
},
{
name: "redundant and queued values",
actual: []string{"foo", "bar"},
cached: []string{"foo", "foobar"},
queued: []string{"bar"},
@ -105,6 +115,7 @@ func TestComparePods(t *testing.T) {
redundant: []string{"foobar"},
},
{
name: "missing cached value",
actual: []string{"foo", "bar", "foobar"},
cached: []string{"bar", "foo"},
queued: []string{},
@ -112,6 +123,7 @@ func TestComparePods(t *testing.T) {
redundant: []string{},
},
{
name: "missing and queued values",
actual: []string{"foo", "bar", "foobar"},
cached: []string{"foo"},
queued: []string{"bar"},
@ -119,6 +131,7 @@ func TestComparePods(t *testing.T) {
redundant: []string{},
},
{
name: "correct cache set",
actual: []string{"foo", "bar", "foobar"},
cached: []string{"bar", "foobar", "foo"},
queued: []string{},
@ -126,6 +139,7 @@ func TestComparePods(t *testing.T) {
redundant: []string{},
},
{
name: "queued cache value",
actual: []string{"foo", "bar", "foobar"},
cached: []string{"foobar", "foo"},
queued: []string{"bar"},
@ -135,22 +149,30 @@ func TestComparePods(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
testComparePods(test.actual, test.cached, test.queued, test.missing, test.redundant, t)
})
}
}
func testComparePods(actual, cached, queued, missing, redundant []string, t *testing.T) {
compare := compareStrategy{}
pods := []*v1.Pod{}
for _, uid := range test.actual {
for _, uid := range actual {
pod := &v1.Pod{}
pod.UID = types.UID(uid)
pods = append(pods, pod)
}
queuedPods := []*v1.Pod{}
for _, uid := range test.queued {
for _, uid := range queued {
pod := &v1.Pod{}
pod.UID = types.UID(uid)
queuedPods = append(queuedPods, pod)
}
nodeInfo := make(map[string]*schedulercache.NodeInfo)
for _, uid := range test.cached {
for _, uid := range cached {
pod := &v1.Pod{}
pod.UID = types.UID(uid)
pod.Namespace = "ns"
@ -161,38 +183,39 @@ func TestComparePods(t *testing.T) {
m, r := compare.ComparePods(pods, queuedPods, nodeInfo)
if !reflect.DeepEqual(m, test.missing) {
t.Errorf("missing expected to be %s; got %s", test.missing, m)
if !reflect.DeepEqual(m, missing) {
t.Errorf("missing expected to be %s; got %s", missing, m)
}
if !reflect.DeepEqual(r, test.redundant) {
t.Errorf("redundant expected to be %s; got %s", test.redundant, r)
}
if !reflect.DeepEqual(r, redundant) {
t.Errorf("redundant expected to be %s; got %s", redundant, r)
}
}
func TestComparePdbs(t *testing.T) {
compare := compareStrategy{}
tests := []struct {
name string
actual []string
cached []string
missing []string
redundant []string
}{
{
name: "redundant cache value",
actual: []string{"foo", "bar"},
cached: []string{"bar", "foo", "foobar"},
missing: []string{},
redundant: []string{"foobar"},
},
{
name: "missing cache value",
actual: []string{"foo", "bar", "foobar"},
cached: []string{"bar", "foo"},
missing: []string{"foobar"},
redundant: []string{},
},
{
name: "correct cache",
actual: []string{"foo", "bar", "foobar"},
cached: []string{"bar", "foobar", "foo"},
missing: []string{},
@ -201,15 +224,23 @@ func TestComparePdbs(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
testComparePdbs(test.actual, test.cached, test.missing, test.redundant, t)
})
}
}
func testComparePdbs(actual, cached, missing, redundant []string, t *testing.T) {
compare := compareStrategy{}
pdbs := []*policy.PodDisruptionBudget{}
for _, uid := range test.actual {
for _, uid := range actual {
pdb := &policy.PodDisruptionBudget{}
pdb.UID = types.UID(uid)
pdbs = append(pdbs, pdb)
}
cache := make(map[string]*policy.PodDisruptionBudget)
for _, uid := range test.cached {
for _, uid := range cached {
pdb := &policy.PodDisruptionBudget{}
pdb.UID = types.UID(uid)
cache[uid] = pdb
@ -217,12 +248,11 @@ func TestComparePdbs(t *testing.T) {
m, r := compare.ComparePdbs(pdbs, cache)
if !reflect.DeepEqual(m, test.missing) {
t.Errorf("missing expected to be %s; got %s", test.missing, m)
if !reflect.DeepEqual(m, missing) {
t.Errorf("missing expected to be %s; got %s", missing, m)
}
if !reflect.DeepEqual(r, test.redundant) {
t.Errorf("redundant expected to be %s; got %s", test.redundant, r)
}
if !reflect.DeepEqual(r, redundant) {
t.Errorf("redundant expected to be %s; got %s", redundant, r)
}
}

View File

@ -331,6 +331,7 @@ func TestNodeEnumerator(t *testing.T) {
t.Fatalf("expected %v, got %v", e, a)
}
for i := range testList.Items {
t.Run(fmt.Sprintf("node enumerator/%v", i), func(t *testing.T) {
gotObj := me.Get(i)
if e, a := testList.Items[i].Name, gotObj.(*v1.Node).Name; e != a {
t.Errorf("Expected %v, got %v", e, a)
@ -338,14 +339,18 @@ func TestNodeEnumerator(t *testing.T) {
if e, a := &testList.Items[i], gotObj; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %#v, got %v#", e, a)
}
})
}
}
func TestBind(t *testing.T) {
table := []struct {
name string
binding *v1.Binding
}{
{binding: &v1.Binding{
{
name: "binding can bind and validate request",
binding: &v1.Binding{
ObjectMeta: metav1.ObjectMeta{
Namespace: metav1.NamespaceDefault,
Name: "foo",
@ -353,10 +358,18 @@ func TestBind(t *testing.T) {
Target: v1.ObjectReference{
Name: "foohost.kubernetes.mydomain.com",
},
}},
},
},
}
for _, item := range table {
for _, test := range table {
t.Run(test.name, func(t *testing.T) {
testBind(test.binding, t)
})
}
}
func testBind(binding *v1.Binding, t *testing.T) {
handler := utiltesting.FakeHandler{
StatusCode: 200,
ResponseBody: "",
@ -367,15 +380,14 @@ func TestBind(t *testing.T) {
client := clientset.NewForConfigOrDie(&restclient.Config{Host: server.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}})
b := binder{client}
if err := b.Bind(item.binding); err != nil {
if err := b.Bind(binding); err != nil {
t.Errorf("Unexpected error: %v", err)
continue
return
}
expectedBody := runtime.EncodeOrDie(schedulertesting.Test.Codec(), item.binding)
expectedBody := runtime.EncodeOrDie(schedulertesting.Test.Codec(), binding)
handler.ValidateRequest(t,
schedulertesting.Test.SubResourcePath(string(v1.ResourcePods), metav1.NamespaceDefault, "foo", "binding"),
"POST", &expectedBody)
}
}
func TestInvalidHardPodAffinitySymmetricWeight(t *testing.T) {
@ -406,38 +418,44 @@ func TestInvalidFactoryArgs(t *testing.T) {
client := clientset.NewForConfigOrDie(&restclient.Config{Host: server.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}})
testCases := []struct {
name string
hardPodAffinitySymmetricWeight int32
expectErr string
}{
{
name: "symmetric weight below range",
hardPodAffinitySymmetricWeight: -1,
expectErr: "invalid hardPodAffinitySymmetricWeight: -1, must be in the range 0-100",
},
{
name: "symmetric weight above range",
hardPodAffinitySymmetricWeight: 101,
expectErr: "invalid hardPodAffinitySymmetricWeight: 101, must be in the range 0-100",
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
factory := newConfigFactory(client, test.hardPodAffinitySymmetricWeight)
_, err := factory.Create()
if err == nil {
t.Errorf("expected err: %s, got nothing", test.expectErr)
}
})
}
}
func TestSkipPodUpdate(t *testing.T) {
for _, test := range []struct {
table := []struct {
pod *v1.Pod
isAssumedPodFunc func(*v1.Pod) bool
getPodFunc func(*v1.Pod) *v1.Pod
expected bool
name string
}{
// Non-assumed pod should not be skipped.
{
name: "Non-assumed pod",
pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod-0",
@ -453,9 +471,8 @@ func TestSkipPodUpdate(t *testing.T) {
},
expected: false,
},
// Pod update (with changes on ResourceVersion, Spec.NodeName and/or
// Annotations) for an already assumed pod should be skipped.
{
name: "with changes on ResourceVersion, Spec.NodeName and/or Annotations",
pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod-0",
@ -483,9 +500,8 @@ func TestSkipPodUpdate(t *testing.T) {
},
expected: true,
},
// Pod update (with changes on Labels) for an already assumed pod
// should not be skipped.
{
name: "with changes on Labels",
pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod-0",
@ -505,7 +521,9 @@ func TestSkipPodUpdate(t *testing.T) {
},
expected: false,
},
} {
}
for _, test := range table {
t.Run(test.name, func(t *testing.T) {
c := &configFactory{
schedulerCache: &schedulertesting.FakeCache{
IsAssumedPodFunc: test.isAssumedPodFunc,
@ -516,6 +534,7 @@ func TestSkipPodUpdate(t *testing.T) {
if got != test.expected {
t.Errorf("skipPodUpdate() = %t, expected = %t", got, test.expected)
}
})
}
}
@ -593,24 +612,22 @@ func (f *fakeExtender) IsInterested(pod *v1.Pod) bool {
}
func TestGetBinderFunc(t *testing.T) {
for _, test := range []struct {
table := []struct {
podName string
extenders []algorithm.SchedulerExtender
expectedBinderType string
name string
}{
// Expect to return the default binder because the extender is not a
// binder, even though it's interested in the pod.
{
name: "the extender is not a binder",
podName: "pod0",
extenders: []algorithm.SchedulerExtender{
&fakeExtender{isBinder: false, interestedPodName: "pod0"},
},
expectedBinderType: "*factory.binder",
},
// Expect to return the fake binder because one of the extenders is a
// binder and it's interested in the pod.
{
name: "one of the extenders is a binder and interested in pod",
podName: "pod0",
extenders: []algorithm.SchedulerExtender{
&fakeExtender{isBinder: false, interestedPodName: "pod0"},
@ -618,9 +635,8 @@ func TestGetBinderFunc(t *testing.T) {
},
expectedBinderType: "*factory.fakeExtender",
},
// Expect to return the default binder because one of the extenders is
// a binder but the binder is not interested in the pod.
{
name: "one of the extenders is a binder, but not interested in pod",
podName: "pod1",
extenders: []algorithm.SchedulerExtender{
&fakeExtender{isBinder: false, interestedPodName: "pod1"},
@ -628,20 +644,28 @@ func TestGetBinderFunc(t *testing.T) {
},
expectedBinderType: "*factory.binder",
},
} {
}
for _, test := range table {
t.Run(test.name, func(t *testing.T) {
testGetBinderFunc(test.expectedBinderType, test.podName, test.extenders, t)
})
}
}
func testGetBinderFunc(expectedBinderType, podName string, extenders []algorithm.SchedulerExtender, t *testing.T) {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: test.podName,
Name: podName,
},
}
f := &configFactory{}
binderFunc := f.getBinderFunc(test.extenders)
binderFunc := f.getBinderFunc(extenders)
binder := binderFunc(pod)
binderType := fmt.Sprintf("%s", reflect.TypeOf(binder))
if binderType != test.expectedBinderType {
t.Errorf("Expected binder %q but got %q", test.expectedBinderType, binderType)
}
if binderType != expectedBinderType {
t.Errorf("Expected binder %q but got %q", expectedBinderType, binderType)
}
}

View File

@ -36,14 +36,18 @@ func TestAlgorithmNameValidation(t *testing.T) {
"Some,Alg:orithm",
}
for _, name := range algorithmNamesShouldValidate {
t.Run(name, func(t *testing.T) {
if !validName.MatchString(name) {
t.Errorf("%v should be a valid algorithm name but is not valid.", name)
t.Errorf("should be a valid algorithm name but is not valid.")
}
})
}
for _, name := range algorithmNamesShouldNotValidate {
t.Run(name, func(t *testing.T) {
if validName.MatchString(name) {
t.Errorf("%v should be an invalid algorithm name but is valid.", name)
t.Errorf("should be an invalid algorithm name but is valid.")
}
})
}
}
@ -70,16 +74,18 @@ func TestValidatePriorityConfigOverFlow(t *testing.T) {
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
err := validateSelectedConfigs(test.configs)
if test.expected {
if err == nil {
t.Errorf("Expected Overflow for %s", test.description)
t.Errorf("Expected Overflow")
}
} else {
if err != nil {
t.Errorf("Did not expect an overflow for %s", test.description)
t.Errorf("Did not expect an overflow")
}
}
})
}
}