eventhandlers_test.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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. fakecache "k8s.io/kubernetes/pkg/scheduler/internal/cache/fake"
  21. )
  22. func TestSkipPodUpdate(t *testing.T) {
  23. for _, test := range []struct {
  24. pod *v1.Pod
  25. isAssumedPodFunc func(*v1.Pod) bool
  26. getPodFunc func(*v1.Pod) *v1.Pod
  27. expected bool
  28. name string
  29. }{
  30. {
  31. name: "Non-assumed pod",
  32. pod: &v1.Pod{
  33. ObjectMeta: metav1.ObjectMeta{
  34. Name: "pod-0",
  35. },
  36. },
  37. isAssumedPodFunc: func(*v1.Pod) bool { return false },
  38. getPodFunc: func(*v1.Pod) *v1.Pod {
  39. return &v1.Pod{
  40. ObjectMeta: metav1.ObjectMeta{
  41. Name: "pod-0",
  42. },
  43. }
  44. },
  45. expected: false,
  46. },
  47. {
  48. name: "with changes on ResourceVersion, Spec.NodeName and/or Annotations",
  49. pod: &v1.Pod{
  50. ObjectMeta: metav1.ObjectMeta{
  51. Name: "pod-0",
  52. Annotations: map[string]string{"a": "b"},
  53. ResourceVersion: "0",
  54. },
  55. Spec: v1.PodSpec{
  56. NodeName: "node-0",
  57. },
  58. },
  59. isAssumedPodFunc: func(*v1.Pod) bool {
  60. return true
  61. },
  62. getPodFunc: func(*v1.Pod) *v1.Pod {
  63. return &v1.Pod{
  64. ObjectMeta: metav1.ObjectMeta{
  65. Name: "pod-0",
  66. Annotations: map[string]string{"c": "d"},
  67. ResourceVersion: "1",
  68. },
  69. Spec: v1.PodSpec{
  70. NodeName: "node-1",
  71. },
  72. }
  73. },
  74. expected: true,
  75. },
  76. {
  77. name: "with changes on Labels",
  78. pod: &v1.Pod{
  79. ObjectMeta: metav1.ObjectMeta{
  80. Name: "pod-0",
  81. Labels: map[string]string{"a": "b"},
  82. },
  83. },
  84. isAssumedPodFunc: func(*v1.Pod) bool {
  85. return true
  86. },
  87. getPodFunc: func(*v1.Pod) *v1.Pod {
  88. return &v1.Pod{
  89. ObjectMeta: metav1.ObjectMeta{
  90. Name: "pod-0",
  91. Labels: map[string]string{"c": "d"},
  92. },
  93. }
  94. },
  95. expected: false,
  96. },
  97. } {
  98. t.Run(test.name, func(t *testing.T) {
  99. c := &Scheduler{
  100. SchedulerCache: &fakecache.Cache{
  101. IsAssumedPodFunc: test.isAssumedPodFunc,
  102. GetPodFunc: test.getPodFunc,
  103. },
  104. }
  105. got := c.skipPodUpdate(test.pod)
  106. if got != test.expected {
  107. t.Errorf("skipPodUpdate() = %t, expected = %t", got, test.expected)
  108. }
  109. })
  110. }
  111. }
  112. func TestNodeAllocatableChanged(t *testing.T) {
  113. newQuantity := func(value int64) resource.Quantity {
  114. return *resource.NewQuantity(value, resource.BinarySI)
  115. }
  116. for _, test := range []struct {
  117. Name string
  118. Changed bool
  119. OldAllocatable v1.ResourceList
  120. NewAllocatable v1.ResourceList
  121. }{
  122. {
  123. Name: "no allocatable resources changed",
  124. Changed: false,
  125. OldAllocatable: v1.ResourceList{v1.ResourceMemory: newQuantity(1024)},
  126. NewAllocatable: v1.ResourceList{v1.ResourceMemory: newQuantity(1024)},
  127. },
  128. {
  129. Name: "new node has more allocatable resources",
  130. Changed: true,
  131. OldAllocatable: v1.ResourceList{v1.ResourceMemory: newQuantity(1024)},
  132. NewAllocatable: v1.ResourceList{v1.ResourceMemory: newQuantity(1024), v1.ResourceStorage: newQuantity(1024)},
  133. },
  134. } {
  135. t.Run(test.Name, func(t *testing.T) {
  136. oldNode := &v1.Node{Status: v1.NodeStatus{Allocatable: test.OldAllocatable}}
  137. newNode := &v1.Node{Status: v1.NodeStatus{Allocatable: test.NewAllocatable}}
  138. changed := nodeAllocatableChanged(newNode, oldNode)
  139. if changed != test.Changed {
  140. t.Errorf("nodeAllocatableChanged should be %t, got %t", test.Changed, changed)
  141. }
  142. })
  143. }
  144. }
  145. func TestNodeLabelsChanged(t *testing.T) {
  146. for _, test := range []struct {
  147. Name string
  148. Changed bool
  149. OldLabels map[string]string
  150. NewLabels map[string]string
  151. }{
  152. {
  153. Name: "no labels changed",
  154. Changed: false,
  155. OldLabels: map[string]string{"foo": "bar"},
  156. NewLabels: map[string]string{"foo": "bar"},
  157. },
  158. // Labels changed.
  159. {
  160. Name: "new node has more labels",
  161. Changed: true,
  162. OldLabels: map[string]string{"foo": "bar"},
  163. NewLabels: map[string]string{"foo": "bar", "test": "value"},
  164. },
  165. } {
  166. t.Run(test.Name, func(t *testing.T) {
  167. oldNode := &v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: test.OldLabels}}
  168. newNode := &v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: test.NewLabels}}
  169. changed := nodeLabelsChanged(newNode, oldNode)
  170. if changed != test.Changed {
  171. t.Errorf("Test case %q failed: should be %t, got %t", test.Name, test.Changed, changed)
  172. }
  173. })
  174. }
  175. }
  176. func TestNodeTaintsChanged(t *testing.T) {
  177. for _, test := range []struct {
  178. Name string
  179. Changed bool
  180. OldTaints []v1.Taint
  181. NewTaints []v1.Taint
  182. }{
  183. {
  184. Name: "no taint changed",
  185. Changed: false,
  186. OldTaints: []v1.Taint{{Key: "key", Value: "value"}},
  187. NewTaints: []v1.Taint{{Key: "key", Value: "value"}},
  188. },
  189. {
  190. Name: "taint value changed",
  191. Changed: true,
  192. OldTaints: []v1.Taint{{Key: "key", Value: "value1"}},
  193. NewTaints: []v1.Taint{{Key: "key", Value: "value2"}},
  194. },
  195. } {
  196. t.Run(test.Name, func(t *testing.T) {
  197. oldNode := &v1.Node{Spec: v1.NodeSpec{Taints: test.OldTaints}}
  198. newNode := &v1.Node{Spec: v1.NodeSpec{Taints: test.NewTaints}}
  199. changed := nodeTaintsChanged(newNode, oldNode)
  200. if changed != test.Changed {
  201. t.Errorf("Test case %q failed: should be %t, not %t", test.Name, test.Changed, changed)
  202. }
  203. })
  204. }
  205. }
  206. func TestNodeConditionsChanged(t *testing.T) {
  207. nodeConditionType := reflect.TypeOf(v1.NodeCondition{})
  208. if nodeConditionType.NumField() != 6 {
  209. t.Errorf("NodeCondition type has changed. The nodeConditionsChanged() function must be reevaluated.")
  210. }
  211. for _, test := range []struct {
  212. Name string
  213. Changed bool
  214. OldConditions []v1.NodeCondition
  215. NewConditions []v1.NodeCondition
  216. }{
  217. {
  218. Name: "no condition changed",
  219. Changed: false,
  220. OldConditions: []v1.NodeCondition{{Type: v1.NodeDiskPressure, Status: v1.ConditionTrue}},
  221. NewConditions: []v1.NodeCondition{{Type: v1.NodeDiskPressure, Status: v1.ConditionTrue}},
  222. },
  223. {
  224. Name: "only LastHeartbeatTime changed",
  225. Changed: false,
  226. OldConditions: []v1.NodeCondition{{Type: v1.NodeDiskPressure, Status: v1.ConditionTrue, LastHeartbeatTime: metav1.Unix(1, 0)}},
  227. NewConditions: []v1.NodeCondition{{Type: v1.NodeDiskPressure, Status: v1.ConditionTrue, LastHeartbeatTime: metav1.Unix(2, 0)}},
  228. },
  229. {
  230. Name: "new node has more healthy conditions",
  231. Changed: true,
  232. OldConditions: []v1.NodeCondition{},
  233. NewConditions: []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionTrue}},
  234. },
  235. {
  236. Name: "new node has less unhealthy conditions",
  237. Changed: true,
  238. OldConditions: []v1.NodeCondition{{Type: v1.NodeDiskPressure, Status: v1.ConditionTrue}},
  239. NewConditions: []v1.NodeCondition{},
  240. },
  241. {
  242. Name: "condition status changed",
  243. Changed: true,
  244. OldConditions: []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionFalse}},
  245. NewConditions: []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionTrue}},
  246. },
  247. } {
  248. t.Run(test.Name, func(t *testing.T) {
  249. oldNode := &v1.Node{Status: v1.NodeStatus{Conditions: test.OldConditions}}
  250. newNode := &v1.Node{Status: v1.NodeStatus{Conditions: test.NewConditions}}
  251. changed := nodeConditionsChanged(newNode, oldNode)
  252. if changed != test.Changed {
  253. t.Errorf("Test case %q failed: should be %t, got %t", test.Name, test.Changed, changed)
  254. }
  255. })
  256. }
  257. }