eventhandlers_test.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. Copyright 2019 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package scheduler
  14. import (
  15. "reflect"
  16. "testing"
  17. "k8s.io/api/core/v1"
  18. "k8s.io/apimachinery/pkg/api/resource"
  19. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  20. "k8s.io/kubernetes/pkg/scheduler/factory"
  21. fakecache "k8s.io/kubernetes/pkg/scheduler/internal/cache/fake"
  22. )
  23. func TestSkipPodUpdate(t *testing.T) {
  24. table := []struct {
  25. pod *v1.Pod
  26. isAssumedPodFunc func(*v1.Pod) bool
  27. getPodFunc func(*v1.Pod) *v1.Pod
  28. expected bool
  29. name string
  30. }{
  31. {
  32. name: "Non-assumed pod",
  33. pod: &v1.Pod{
  34. ObjectMeta: metav1.ObjectMeta{
  35. Name: "pod-0",
  36. },
  37. },
  38. isAssumedPodFunc: func(*v1.Pod) bool { return false },
  39. getPodFunc: func(*v1.Pod) *v1.Pod {
  40. return &v1.Pod{
  41. ObjectMeta: metav1.ObjectMeta{
  42. Name: "pod-0",
  43. },
  44. }
  45. },
  46. expected: false,
  47. },
  48. {
  49. name: "with changes on ResourceVersion, Spec.NodeName and/or Annotations",
  50. pod: &v1.Pod{
  51. ObjectMeta: metav1.ObjectMeta{
  52. Name: "pod-0",
  53. Annotations: map[string]string{"a": "b"},
  54. ResourceVersion: "0",
  55. },
  56. Spec: v1.PodSpec{
  57. NodeName: "node-0",
  58. },
  59. },
  60. isAssumedPodFunc: func(*v1.Pod) bool {
  61. return true
  62. },
  63. getPodFunc: func(*v1.Pod) *v1.Pod {
  64. return &v1.Pod{
  65. ObjectMeta: metav1.ObjectMeta{
  66. Name: "pod-0",
  67. Annotations: map[string]string{"c": "d"},
  68. ResourceVersion: "1",
  69. },
  70. Spec: v1.PodSpec{
  71. NodeName: "node-1",
  72. },
  73. }
  74. },
  75. expected: true,
  76. },
  77. {
  78. name: "with changes on Labels",
  79. pod: &v1.Pod{
  80. ObjectMeta: metav1.ObjectMeta{
  81. Name: "pod-0",
  82. Labels: map[string]string{"a": "b"},
  83. },
  84. },
  85. isAssumedPodFunc: func(*v1.Pod) bool {
  86. return true
  87. },
  88. getPodFunc: func(*v1.Pod) *v1.Pod {
  89. return &v1.Pod{
  90. ObjectMeta: metav1.ObjectMeta{
  91. Name: "pod-0",
  92. Labels: map[string]string{"c": "d"},
  93. },
  94. }
  95. },
  96. expected: false,
  97. },
  98. }
  99. for _, test := range table {
  100. t.Run(test.name, func(t *testing.T) {
  101. c := NewFromConfig(&factory.Config{
  102. SchedulerCache: &fakecache.Cache{
  103. IsAssumedPodFunc: test.isAssumedPodFunc,
  104. GetPodFunc: test.getPodFunc,
  105. },
  106. },
  107. )
  108. got := c.skipPodUpdate(test.pod)
  109. if got != test.expected {
  110. t.Errorf("skipPodUpdate() = %t, expected = %t", got, test.expected)
  111. }
  112. })
  113. }
  114. }
  115. func TestNodeAllocatableChanged(t *testing.T) {
  116. newQuantity := func(value int64) resource.Quantity {
  117. return *resource.NewQuantity(value, resource.BinarySI)
  118. }
  119. for _, c := range []struct {
  120. Name string
  121. Changed bool
  122. OldAllocatable v1.ResourceList
  123. NewAllocatable v1.ResourceList
  124. }{
  125. {
  126. Name: "no allocatable resources changed",
  127. Changed: false,
  128. OldAllocatable: v1.ResourceList{v1.ResourceMemory: newQuantity(1024)},
  129. NewAllocatable: v1.ResourceList{v1.ResourceMemory: newQuantity(1024)},
  130. },
  131. {
  132. Name: "new node has more allocatable resources",
  133. Changed: true,
  134. OldAllocatable: v1.ResourceList{v1.ResourceMemory: newQuantity(1024)},
  135. NewAllocatable: v1.ResourceList{v1.ResourceMemory: newQuantity(1024), v1.ResourceStorage: newQuantity(1024)},
  136. },
  137. } {
  138. oldNode := &v1.Node{Status: v1.NodeStatus{Allocatable: c.OldAllocatable}}
  139. newNode := &v1.Node{Status: v1.NodeStatus{Allocatable: c.NewAllocatable}}
  140. changed := nodeAllocatableChanged(newNode, oldNode)
  141. if changed != c.Changed {
  142. t.Errorf("nodeAllocatableChanged should be %t, got %t", c.Changed, changed)
  143. }
  144. }
  145. }
  146. func TestNodeLabelsChanged(t *testing.T) {
  147. for _, c := range []struct {
  148. Name string
  149. Changed bool
  150. OldLabels map[string]string
  151. NewLabels map[string]string
  152. }{
  153. {
  154. Name: "no labels changed",
  155. Changed: false,
  156. OldLabels: map[string]string{"foo": "bar"},
  157. NewLabels: map[string]string{"foo": "bar"},
  158. },
  159. // Labels changed.
  160. {
  161. Name: "new node has more labels",
  162. Changed: true,
  163. OldLabels: map[string]string{"foo": "bar"},
  164. NewLabels: map[string]string{"foo": "bar", "test": "value"},
  165. },
  166. } {
  167. oldNode := &v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: c.OldLabels}}
  168. newNode := &v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: c.NewLabels}}
  169. changed := nodeLabelsChanged(newNode, oldNode)
  170. if changed != c.Changed {
  171. t.Errorf("Test case %q failed: should be %t, got %t", c.Name, c.Changed, changed)
  172. }
  173. }
  174. }
  175. func TestNodeTaintsChanged(t *testing.T) {
  176. for _, c := range []struct {
  177. Name string
  178. Changed bool
  179. OldTaints []v1.Taint
  180. NewTaints []v1.Taint
  181. }{
  182. {
  183. Name: "no taint changed",
  184. Changed: false,
  185. OldTaints: []v1.Taint{{Key: "key", Value: "value"}},
  186. NewTaints: []v1.Taint{{Key: "key", Value: "value"}},
  187. },
  188. {
  189. Name: "taint value changed",
  190. Changed: true,
  191. OldTaints: []v1.Taint{{Key: "key", Value: "value1"}},
  192. NewTaints: []v1.Taint{{Key: "key", Value: "value2"}},
  193. },
  194. } {
  195. oldNode := &v1.Node{Spec: v1.NodeSpec{Taints: c.OldTaints}}
  196. newNode := &v1.Node{Spec: v1.NodeSpec{Taints: c.NewTaints}}
  197. changed := nodeTaintsChanged(newNode, oldNode)
  198. if changed != c.Changed {
  199. t.Errorf("Test case %q failed: should be %t, not %t", c.Name, c.Changed, changed)
  200. }
  201. }
  202. }
  203. func TestNodeConditionsChanged(t *testing.T) {
  204. nodeConditionType := reflect.TypeOf(v1.NodeCondition{})
  205. if nodeConditionType.NumField() != 6 {
  206. t.Errorf("NodeCondition type has changed. The nodeConditionsChanged() function must be reevaluated.")
  207. }
  208. for _, c := range []struct {
  209. Name string
  210. Changed bool
  211. OldConditions []v1.NodeCondition
  212. NewConditions []v1.NodeCondition
  213. }{
  214. {
  215. Name: "no condition changed",
  216. Changed: false,
  217. OldConditions: []v1.NodeCondition{{Type: v1.NodeOutOfDisk, Status: v1.ConditionTrue}},
  218. NewConditions: []v1.NodeCondition{{Type: v1.NodeOutOfDisk, Status: v1.ConditionTrue}},
  219. },
  220. {
  221. Name: "only LastHeartbeatTime changed",
  222. Changed: false,
  223. OldConditions: []v1.NodeCondition{{Type: v1.NodeOutOfDisk, Status: v1.ConditionTrue, LastHeartbeatTime: metav1.Unix(1, 0)}},
  224. NewConditions: []v1.NodeCondition{{Type: v1.NodeOutOfDisk, Status: v1.ConditionTrue, LastHeartbeatTime: metav1.Unix(2, 0)}},
  225. },
  226. {
  227. Name: "new node has more healthy conditions",
  228. Changed: true,
  229. OldConditions: []v1.NodeCondition{},
  230. NewConditions: []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionTrue}},
  231. },
  232. {
  233. Name: "new node has less unhealthy conditions",
  234. Changed: true,
  235. OldConditions: []v1.NodeCondition{{Type: v1.NodeOutOfDisk, Status: v1.ConditionTrue}},
  236. NewConditions: []v1.NodeCondition{},
  237. },
  238. {
  239. Name: "condition status changed",
  240. Changed: true,
  241. OldConditions: []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionFalse}},
  242. NewConditions: []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionTrue}},
  243. },
  244. } {
  245. oldNode := &v1.Node{Status: v1.NodeStatus{Conditions: c.OldConditions}}
  246. newNode := &v1.Node{Status: v1.NodeStatus{Conditions: c.NewConditions}}
  247. changed := nodeConditionsChanged(newNode, oldNode)
  248. if changed != c.Changed {
  249. t.Errorf("Test case %q failed: should be %t, got %t", c.Name, c.Changed, changed)
  250. }
  251. }
  252. }