taint_manager_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. /*
  2. Copyright 2017 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. "fmt"
  16. "sort"
  17. "sync"
  18. "testing"
  19. "time"
  20. "k8s.io/api/core/v1"
  21. "k8s.io/client-go/kubernetes/fake"
  22. "k8s.io/kubernetes/pkg/controller/testutil"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. clienttesting "k8s.io/client-go/testing"
  25. )
  26. var timeForControllerToProgress = 500 * time.Millisecond
  27. func getPodFromClientset(clientset *fake.Clientset) GetPodFunc {
  28. return func(name, namespace string) (*v1.Pod, error) {
  29. return clientset.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
  30. }
  31. }
  32. func getNodeFromClientset(clientset *fake.Clientset) GetNodeFunc {
  33. return func(name string) (*v1.Node, error) {
  34. return clientset.CoreV1().Nodes().Get(name, metav1.GetOptions{})
  35. }
  36. }
  37. type podHolder struct {
  38. pod *v1.Pod
  39. sync.Mutex
  40. }
  41. func (p *podHolder) getPod(name, namespace string) (*v1.Pod, error) {
  42. p.Lock()
  43. defer p.Unlock()
  44. return p.pod, nil
  45. }
  46. func (p *podHolder) setPod(pod *v1.Pod) {
  47. p.Lock()
  48. defer p.Unlock()
  49. p.pod = pod
  50. }
  51. type nodeHolder struct {
  52. node *v1.Node
  53. }
  54. func (n *nodeHolder) getNode(name string) (*v1.Node, error) {
  55. return n.node, nil
  56. }
  57. func createNoExecuteTaint(index int) v1.Taint {
  58. now := metav1.Now()
  59. return v1.Taint{
  60. Key: "testTaint" + fmt.Sprintf("%v", index),
  61. Value: "test" + fmt.Sprintf("%v", index),
  62. Effect: v1.TaintEffectNoExecute,
  63. TimeAdded: &now,
  64. }
  65. }
  66. func addToleration(pod *v1.Pod, index int, duration int64) *v1.Pod {
  67. if pod.Annotations == nil {
  68. pod.Annotations = map[string]string{}
  69. }
  70. if duration < 0 {
  71. pod.Spec.Tolerations = []v1.Toleration{{Key: "testTaint" + fmt.Sprintf("%v", index), Value: "test" + fmt.Sprintf("%v", index), Effect: v1.TaintEffectNoExecute}}
  72. } else {
  73. pod.Spec.Tolerations = []v1.Toleration{{Key: "testTaint" + fmt.Sprintf("%v", index), Value: "test" + fmt.Sprintf("%v", index), Effect: v1.TaintEffectNoExecute, TolerationSeconds: &duration}}
  74. }
  75. return pod
  76. }
  77. func addTaintsToNode(node *v1.Node, key, value string, indices []int) *v1.Node {
  78. taints := []v1.Taint{}
  79. for _, index := range indices {
  80. taints = append(taints, createNoExecuteTaint(index))
  81. }
  82. node.Spec.Taints = taints
  83. return node
  84. }
  85. type timestampedPod struct {
  86. names []string
  87. timestamp time.Duration
  88. }
  89. type durationSlice []timestampedPod
  90. func (a durationSlice) Len() int { return len(a) }
  91. func (a durationSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  92. func (a durationSlice) Less(i, j int) bool { return a[i].timestamp < a[j].timestamp }
  93. func TestFilterNoExecuteTaints(t *testing.T) {
  94. taints := []v1.Taint{
  95. {
  96. Key: "one",
  97. Value: "one",
  98. Effect: v1.TaintEffectNoExecute,
  99. },
  100. {
  101. Key: "two",
  102. Value: "two",
  103. Effect: v1.TaintEffectNoSchedule,
  104. },
  105. }
  106. taints = getNoExecuteTaints(taints)
  107. if len(taints) != 1 || taints[0].Key != "one" {
  108. t.Errorf("Filtering doesn't work. Got %v", taints)
  109. }
  110. }
  111. func TestCreatePod(t *testing.T) {
  112. testCases := []struct {
  113. description string
  114. pod *v1.Pod
  115. taintedNodes map[string][]v1.Taint
  116. expectDelete bool
  117. }{
  118. {
  119. description: "not scheduled - ignore",
  120. pod: testutil.NewPod("pod1", ""),
  121. taintedNodes: map[string][]v1.Taint{},
  122. expectDelete: false,
  123. },
  124. {
  125. description: "scheduled on untainted Node",
  126. pod: testutil.NewPod("pod1", "node1"),
  127. taintedNodes: map[string][]v1.Taint{},
  128. expectDelete: false,
  129. },
  130. {
  131. description: "schedule on tainted Node",
  132. pod: testutil.NewPod("pod1", "node1"),
  133. taintedNodes: map[string][]v1.Taint{
  134. "node1": {createNoExecuteTaint(1)},
  135. },
  136. expectDelete: true,
  137. },
  138. {
  139. description: "schedule on tainted Node with finite toleration",
  140. pod: addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  141. taintedNodes: map[string][]v1.Taint{
  142. "node1": {createNoExecuteTaint(1)},
  143. },
  144. expectDelete: false,
  145. },
  146. {
  147. description: "schedule on tainted Node with infinite toleration",
  148. pod: addToleration(testutil.NewPod("pod1", "node1"), 1, -1),
  149. taintedNodes: map[string][]v1.Taint{
  150. "node1": {createNoExecuteTaint(1)},
  151. },
  152. expectDelete: false,
  153. },
  154. {
  155. description: "schedule on tainted Node with infinite ivalid toleration",
  156. pod: addToleration(testutil.NewPod("pod1", "node1"), 2, -1),
  157. taintedNodes: map[string][]v1.Taint{
  158. "node1": {createNoExecuteTaint(1)},
  159. },
  160. expectDelete: true,
  161. },
  162. }
  163. for _, item := range testCases {
  164. stopCh := make(chan struct{})
  165. fakeClientset := fake.NewSimpleClientset()
  166. controller := NewNoExecuteTaintManager(fakeClientset, (&podHolder{pod: item.pod}).getPod, getNodeFromClientset(fakeClientset))
  167. controller.recorder = testutil.NewFakeRecorder()
  168. go controller.Run(stopCh)
  169. controller.taintedNodes = item.taintedNodes
  170. controller.PodUpdated(nil, item.pod)
  171. // wait a bit
  172. time.Sleep(timeForControllerToProgress)
  173. podDeleted := false
  174. for _, action := range fakeClientset.Actions() {
  175. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  176. podDeleted = true
  177. }
  178. }
  179. if podDeleted != item.expectDelete {
  180. t.Errorf("%v: Unexepected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
  181. }
  182. close(stopCh)
  183. }
  184. }
  185. func TestDeletePod(t *testing.T) {
  186. stopCh := make(chan struct{})
  187. fakeClientset := fake.NewSimpleClientset()
  188. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), getNodeFromClientset(fakeClientset))
  189. controller.recorder = testutil.NewFakeRecorder()
  190. go controller.Run(stopCh)
  191. controller.taintedNodes = map[string][]v1.Taint{
  192. "node1": {createNoExecuteTaint(1)},
  193. }
  194. controller.PodUpdated(testutil.NewPod("pod1", "node1"), nil)
  195. // wait a bit to see if nothing will panic
  196. time.Sleep(timeForControllerToProgress)
  197. close(stopCh)
  198. }
  199. func TestUpdatePod(t *testing.T) {
  200. testCases := []struct {
  201. description string
  202. prevPod *v1.Pod
  203. newPod *v1.Pod
  204. taintedNodes map[string][]v1.Taint
  205. expectDelete bool
  206. additionalSleep time.Duration
  207. }{
  208. {
  209. description: "scheduling onto tainted Node",
  210. prevPod: testutil.NewPod("pod1", ""),
  211. newPod: testutil.NewPod("pod1", "node1"),
  212. taintedNodes: map[string][]v1.Taint{
  213. "node1": {createNoExecuteTaint(1)},
  214. },
  215. expectDelete: true,
  216. },
  217. {
  218. description: "scheduling onto tainted Node with toleration",
  219. prevPod: addToleration(testutil.NewPod("pod1", ""), 1, -1),
  220. newPod: addToleration(testutil.NewPod("pod1", "node1"), 1, -1),
  221. taintedNodes: map[string][]v1.Taint{
  222. "node1": {createNoExecuteTaint(1)},
  223. },
  224. expectDelete: false,
  225. },
  226. {
  227. description: "removing toleration",
  228. prevPod: addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  229. newPod: testutil.NewPod("pod1", "node1"),
  230. taintedNodes: map[string][]v1.Taint{
  231. "node1": {createNoExecuteTaint(1)},
  232. },
  233. expectDelete: true,
  234. },
  235. {
  236. description: "lengthening toleration shouldn't work",
  237. prevPod: addToleration(testutil.NewPod("pod1", "node1"), 1, 1),
  238. newPod: addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  239. taintedNodes: map[string][]v1.Taint{
  240. "node1": {createNoExecuteTaint(1)},
  241. },
  242. expectDelete: true,
  243. additionalSleep: 1500 * time.Millisecond,
  244. },
  245. }
  246. for _, item := range testCases {
  247. stopCh := make(chan struct{})
  248. fakeClientset := fake.NewSimpleClientset()
  249. holder := &podHolder{}
  250. controller := NewNoExecuteTaintManager(fakeClientset, holder.getPod, getNodeFromClientset(fakeClientset))
  251. controller.recorder = testutil.NewFakeRecorder()
  252. go controller.Run(stopCh)
  253. controller.taintedNodes = item.taintedNodes
  254. holder.setPod(item.prevPod)
  255. controller.PodUpdated(nil, item.prevPod)
  256. fakeClientset.ClearActions()
  257. time.Sleep(timeForControllerToProgress)
  258. holder.setPod(item.newPod)
  259. controller.PodUpdated(item.prevPod, item.newPod)
  260. // wait a bit
  261. time.Sleep(timeForControllerToProgress)
  262. if item.additionalSleep > 0 {
  263. time.Sleep(item.additionalSleep)
  264. }
  265. podDeleted := false
  266. for _, action := range fakeClientset.Actions() {
  267. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  268. podDeleted = true
  269. }
  270. }
  271. if podDeleted != item.expectDelete {
  272. t.Errorf("%v: Unexepected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
  273. }
  274. close(stopCh)
  275. }
  276. }
  277. func TestCreateNode(t *testing.T) {
  278. testCases := []struct {
  279. description string
  280. pods []v1.Pod
  281. node *v1.Node
  282. expectDelete bool
  283. }{
  284. {
  285. description: "Creating Node matching already assigned Pod",
  286. pods: []v1.Pod{
  287. *testutil.NewPod("pod1", "node1"),
  288. },
  289. node: testutil.NewNode("node1"),
  290. expectDelete: false,
  291. },
  292. {
  293. description: "Creating tainted Node matching already assigned Pod",
  294. pods: []v1.Pod{
  295. *testutil.NewPod("pod1", "node1"),
  296. },
  297. node: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  298. expectDelete: true,
  299. },
  300. {
  301. description: "Creating tainted Node matching already assigned tolerating Pod",
  302. pods: []v1.Pod{
  303. *addToleration(testutil.NewPod("pod1", "node1"), 1, -1),
  304. },
  305. node: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  306. expectDelete: false,
  307. },
  308. }
  309. for _, item := range testCases {
  310. stopCh := make(chan struct{})
  311. fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
  312. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{item.node}).getNode)
  313. controller.recorder = testutil.NewFakeRecorder()
  314. go controller.Run(stopCh)
  315. controller.NodeUpdated(nil, item.node)
  316. // wait a bit
  317. time.Sleep(timeForControllerToProgress)
  318. podDeleted := false
  319. for _, action := range fakeClientset.Actions() {
  320. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  321. podDeleted = true
  322. }
  323. }
  324. if podDeleted != item.expectDelete {
  325. t.Errorf("%v: Unexepected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
  326. }
  327. close(stopCh)
  328. }
  329. }
  330. func TestDeleteNode(t *testing.T) {
  331. stopCh := make(chan struct{})
  332. fakeClientset := fake.NewSimpleClientset()
  333. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), getNodeFromClientset(fakeClientset))
  334. controller.recorder = testutil.NewFakeRecorder()
  335. controller.taintedNodes = map[string][]v1.Taint{
  336. "node1": {createNoExecuteTaint(1)},
  337. }
  338. go controller.Run(stopCh)
  339. controller.NodeUpdated(testutil.NewNode("node1"), nil)
  340. // wait a bit to see if nothing will panic
  341. time.Sleep(timeForControllerToProgress)
  342. controller.taintedNodesLock.Lock()
  343. if _, ok := controller.taintedNodes["node1"]; ok {
  344. t.Error("Node should have been deleted from taintedNodes list")
  345. }
  346. controller.taintedNodesLock.Unlock()
  347. close(stopCh)
  348. }
  349. func TestUpdateNode(t *testing.T) {
  350. testCases := []struct {
  351. description string
  352. pods []v1.Pod
  353. oldNode *v1.Node
  354. newNode *v1.Node
  355. expectDelete bool
  356. additionalSleep time.Duration
  357. }{
  358. {
  359. description: "Added taint",
  360. pods: []v1.Pod{
  361. *testutil.NewPod("pod1", "node1"),
  362. },
  363. oldNode: testutil.NewNode("node1"),
  364. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  365. expectDelete: true,
  366. },
  367. {
  368. description: "Added tolerated taint",
  369. pods: []v1.Pod{
  370. *addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  371. },
  372. oldNode: testutil.NewNode("node1"),
  373. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  374. expectDelete: false,
  375. },
  376. {
  377. description: "Only one added taint tolerated",
  378. pods: []v1.Pod{
  379. *addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  380. },
  381. oldNode: testutil.NewNode("node1"),
  382. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1, 2}),
  383. expectDelete: true,
  384. },
  385. {
  386. description: "Taint removed",
  387. pods: []v1.Pod{
  388. *addToleration(testutil.NewPod("pod1", "node1"), 1, 1),
  389. },
  390. oldNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  391. newNode: testutil.NewNode("node1"),
  392. expectDelete: false,
  393. additionalSleep: 1500 * time.Millisecond,
  394. },
  395. {
  396. description: "Pod with multiple tolerations are evicted when first one runs out",
  397. pods: []v1.Pod{
  398. {
  399. ObjectMeta: metav1.ObjectMeta{
  400. Namespace: "default",
  401. Name: "pod1",
  402. },
  403. Spec: v1.PodSpec{
  404. NodeName: "node1",
  405. Tolerations: []v1.Toleration{
  406. {Key: "testTaint1", Value: "test1", Effect: v1.TaintEffectNoExecute, TolerationSeconds: &[]int64{1}[0]},
  407. {Key: "testTaint2", Value: "test2", Effect: v1.TaintEffectNoExecute, TolerationSeconds: &[]int64{100}[0]},
  408. },
  409. },
  410. Status: v1.PodStatus{
  411. Conditions: []v1.PodCondition{
  412. {
  413. Type: v1.PodReady,
  414. Status: v1.ConditionTrue,
  415. },
  416. },
  417. },
  418. },
  419. },
  420. oldNode: testutil.NewNode("node1"),
  421. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1, 2}),
  422. expectDelete: true,
  423. additionalSleep: 1500 * time.Millisecond,
  424. },
  425. }
  426. for _, item := range testCases {
  427. stopCh := make(chan struct{})
  428. fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
  429. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{item.newNode}).getNode)
  430. controller.recorder = testutil.NewFakeRecorder()
  431. go controller.Run(stopCh)
  432. controller.NodeUpdated(item.oldNode, item.newNode)
  433. // wait a bit
  434. time.Sleep(timeForControllerToProgress)
  435. if item.additionalSleep > 0 {
  436. time.Sleep(item.additionalSleep)
  437. }
  438. podDeleted := false
  439. for _, action := range fakeClientset.Actions() {
  440. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  441. podDeleted = true
  442. }
  443. }
  444. if podDeleted != item.expectDelete {
  445. t.Errorf("%v: Unexepected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
  446. }
  447. close(stopCh)
  448. }
  449. }
  450. func TestUpdateNodeWithMultiplePods(t *testing.T) {
  451. testCases := []struct {
  452. description string
  453. pods []v1.Pod
  454. oldNode *v1.Node
  455. newNode *v1.Node
  456. expectedDeleteTimes durationSlice
  457. }{
  458. {
  459. description: "Pods with different toleration times are evicted appropriately",
  460. pods: []v1.Pod{
  461. *testutil.NewPod("pod1", "node1"),
  462. *addToleration(testutil.NewPod("pod2", "node1"), 1, 1),
  463. *addToleration(testutil.NewPod("pod3", "node1"), 1, -1),
  464. },
  465. oldNode: testutil.NewNode("node1"),
  466. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  467. expectedDeleteTimes: durationSlice{
  468. {[]string{"pod1"}, 0},
  469. {[]string{"pod2"}, time.Second},
  470. },
  471. },
  472. {
  473. description: "Evict all pods not matching all taints instantly",
  474. pods: []v1.Pod{
  475. *testutil.NewPod("pod1", "node1"),
  476. *addToleration(testutil.NewPod("pod2", "node1"), 1, 1),
  477. *addToleration(testutil.NewPod("pod3", "node1"), 1, -1),
  478. },
  479. oldNode: testutil.NewNode("node1"),
  480. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1, 2}),
  481. expectedDeleteTimes: durationSlice{
  482. {[]string{"pod1", "pod2", "pod3"}, 0},
  483. },
  484. },
  485. }
  486. for _, item := range testCases {
  487. t.Logf("Starting testcase %q", item.description)
  488. stopCh := make(chan struct{})
  489. fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
  490. sort.Sort(item.expectedDeleteTimes)
  491. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{item.newNode}).getNode)
  492. controller.recorder = testutil.NewFakeRecorder()
  493. go controller.Run(stopCh)
  494. controller.NodeUpdated(item.oldNode, item.newNode)
  495. startedAt := time.Now()
  496. for i := range item.expectedDeleteTimes {
  497. if i == 0 || item.expectedDeleteTimes[i-1].timestamp != item.expectedDeleteTimes[i].timestamp {
  498. // compute a grace duration to give controller time to process updates. Choose big
  499. // enough intervals in the test cases above to avoid flakes.
  500. var increment time.Duration
  501. if i == len(item.expectedDeleteTimes)-1 || item.expectedDeleteTimes[i+1].timestamp == item.expectedDeleteTimes[i].timestamp {
  502. increment = 500 * time.Millisecond
  503. } else {
  504. increment = ((item.expectedDeleteTimes[i+1].timestamp - item.expectedDeleteTimes[i].timestamp) / time.Duration(2))
  505. }
  506. sleepTime := item.expectedDeleteTimes[i].timestamp - time.Since(startedAt) + increment
  507. if sleepTime < 0 {
  508. sleepTime = 0
  509. }
  510. t.Logf("Sleeping for %v", sleepTime)
  511. time.Sleep(sleepTime)
  512. }
  513. for delay, podName := range item.expectedDeleteTimes[i].names {
  514. deleted := false
  515. for _, action := range fakeClientset.Actions() {
  516. deleteAction, ok := action.(clienttesting.DeleteActionImpl)
  517. if !ok {
  518. t.Logf("Found not-delete action with verb %v. Ignoring.", action.GetVerb())
  519. continue
  520. }
  521. if deleteAction.GetResource().Resource != "pods" {
  522. continue
  523. }
  524. if podName == deleteAction.GetName() {
  525. deleted = true
  526. }
  527. }
  528. if !deleted {
  529. t.Errorf("Failed to deleted pod %v after %v", podName, delay)
  530. }
  531. }
  532. for _, action := range fakeClientset.Actions() {
  533. deleteAction, ok := action.(clienttesting.DeleteActionImpl)
  534. if !ok {
  535. t.Logf("Found not-delete action with verb %v. Ignoring.", action.GetVerb())
  536. continue
  537. }
  538. if deleteAction.GetResource().Resource != "pods" {
  539. continue
  540. }
  541. deletedPodName := deleteAction.GetName()
  542. expected := false
  543. for _, podName := range item.expectedDeleteTimes[i].names {
  544. if podName == deletedPodName {
  545. expected = true
  546. }
  547. }
  548. if !expected {
  549. t.Errorf("Pod %v was deleted even though it shouldn't have", deletedPodName)
  550. }
  551. }
  552. fakeClientset.ClearActions()
  553. }
  554. close(stopCh)
  555. }
  556. }
  557. func TestGetMinTolerationTime(t *testing.T) {
  558. one := int64(1)
  559. oneSec := 1 * time.Second
  560. tests := []struct {
  561. tolerations []v1.Toleration
  562. expected time.Duration
  563. }{
  564. {
  565. tolerations: []v1.Toleration{},
  566. expected: 0,
  567. },
  568. {
  569. tolerations: []v1.Toleration{
  570. {
  571. TolerationSeconds: &one,
  572. },
  573. {
  574. TolerationSeconds: nil,
  575. },
  576. },
  577. expected: oneSec,
  578. },
  579. {
  580. tolerations: []v1.Toleration{
  581. {
  582. TolerationSeconds: nil,
  583. },
  584. {
  585. TolerationSeconds: &one,
  586. },
  587. },
  588. expected: oneSec,
  589. },
  590. }
  591. for _, test := range tests {
  592. got := getMinTolerationTime(test.tolerations)
  593. if got != test.expected {
  594. t.Errorf("Incorrect min toleration time: got %v, expected %v", got, test.expected)
  595. }
  596. }
  597. }