strategy_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /*
  2. Copyright 2014 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 pod
  14. import (
  15. "context"
  16. "fmt"
  17. "net/http"
  18. "net/url"
  19. "reflect"
  20. "testing"
  21. "k8s.io/apimachinery/pkg/api/errors"
  22. "k8s.io/apimachinery/pkg/api/resource"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. "k8s.io/apimachinery/pkg/fields"
  25. "k8s.io/apimachinery/pkg/labels"
  26. "k8s.io/apimachinery/pkg/runtime"
  27. "k8s.io/apimachinery/pkg/types"
  28. genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
  29. utilfeature "k8s.io/apiserver/pkg/util/feature"
  30. "k8s.io/client-go/tools/cache"
  31. featuregatetesting "k8s.io/component-base/featuregate/testing"
  32. apitesting "k8s.io/kubernetes/pkg/api/testing"
  33. api "k8s.io/kubernetes/pkg/apis/core"
  34. "k8s.io/kubernetes/pkg/features"
  35. "k8s.io/kubernetes/pkg/kubelet/client"
  36. // ensure types are installed
  37. _ "k8s.io/kubernetes/pkg/apis/core/install"
  38. )
  39. func TestMatchPod(t *testing.T) {
  40. testCases := []struct {
  41. in *api.Pod
  42. fieldSelector fields.Selector
  43. expectMatch bool
  44. }{
  45. {
  46. in: &api.Pod{
  47. Spec: api.PodSpec{NodeName: "nodeA"},
  48. },
  49. fieldSelector: fields.ParseSelectorOrDie("spec.nodeName=nodeA"),
  50. expectMatch: true,
  51. },
  52. {
  53. in: &api.Pod{
  54. Spec: api.PodSpec{NodeName: "nodeB"},
  55. },
  56. fieldSelector: fields.ParseSelectorOrDie("spec.nodeName=nodeA"),
  57. expectMatch: false,
  58. },
  59. {
  60. in: &api.Pod{
  61. Spec: api.PodSpec{RestartPolicy: api.RestartPolicyAlways},
  62. },
  63. fieldSelector: fields.ParseSelectorOrDie("spec.restartPolicy=Always"),
  64. expectMatch: true,
  65. },
  66. {
  67. in: &api.Pod{
  68. Spec: api.PodSpec{RestartPolicy: api.RestartPolicyAlways},
  69. },
  70. fieldSelector: fields.ParseSelectorOrDie("spec.restartPolicy=Never"),
  71. expectMatch: false,
  72. },
  73. {
  74. in: &api.Pod{
  75. Spec: api.PodSpec{SchedulerName: "scheduler1"},
  76. },
  77. fieldSelector: fields.ParseSelectorOrDie("spec.schedulerName=scheduler1"),
  78. expectMatch: true,
  79. },
  80. {
  81. in: &api.Pod{
  82. Spec: api.PodSpec{SchedulerName: "scheduler1"},
  83. },
  84. fieldSelector: fields.ParseSelectorOrDie("spec.schedulerName=scheduler2"),
  85. expectMatch: false,
  86. },
  87. {
  88. in: &api.Pod{
  89. Spec: api.PodSpec{ServiceAccountName: "serviceAccount1"},
  90. },
  91. fieldSelector: fields.ParseSelectorOrDie("spec.serviceAccountName=serviceAccount1"),
  92. expectMatch: true,
  93. },
  94. {
  95. in: &api.Pod{
  96. Spec: api.PodSpec{SchedulerName: "serviceAccount1"},
  97. },
  98. fieldSelector: fields.ParseSelectorOrDie("spec.serviceAccountName=serviceAccount2"),
  99. expectMatch: false,
  100. },
  101. {
  102. in: &api.Pod{
  103. Status: api.PodStatus{Phase: api.PodRunning},
  104. },
  105. fieldSelector: fields.ParseSelectorOrDie("status.phase=Running"),
  106. expectMatch: true,
  107. },
  108. {
  109. in: &api.Pod{
  110. Status: api.PodStatus{Phase: api.PodRunning},
  111. },
  112. fieldSelector: fields.ParseSelectorOrDie("status.phase=Pending"),
  113. expectMatch: false,
  114. },
  115. {
  116. in: &api.Pod{
  117. Status: api.PodStatus{
  118. PodIPs: []api.PodIP{
  119. {IP: "1.2.3.4"},
  120. },
  121. },
  122. },
  123. fieldSelector: fields.ParseSelectorOrDie("status.podIP=1.2.3.4"),
  124. expectMatch: true,
  125. },
  126. {
  127. in: &api.Pod{
  128. Status: api.PodStatus{
  129. PodIPs: []api.PodIP{
  130. {IP: "1.2.3.4"},
  131. },
  132. },
  133. },
  134. fieldSelector: fields.ParseSelectorOrDie("status.podIP=4.3.2.1"),
  135. expectMatch: false,
  136. },
  137. {
  138. in: &api.Pod{
  139. Status: api.PodStatus{NominatedNodeName: "node1"},
  140. },
  141. fieldSelector: fields.ParseSelectorOrDie("status.nominatedNodeName=node1"),
  142. expectMatch: true,
  143. },
  144. {
  145. in: &api.Pod{
  146. Status: api.PodStatus{NominatedNodeName: "node1"},
  147. },
  148. fieldSelector: fields.ParseSelectorOrDie("status.nominatedNodeName=node2"),
  149. expectMatch: false,
  150. },
  151. {
  152. in: &api.Pod{
  153. Status: api.PodStatus{
  154. PodIPs: []api.PodIP{
  155. {IP: "2001:db8::"},
  156. },
  157. },
  158. },
  159. fieldSelector: fields.ParseSelectorOrDie("status.podIP=2001:db8::"),
  160. expectMatch: true,
  161. },
  162. {
  163. in: &api.Pod{
  164. Status: api.PodStatus{
  165. PodIPs: []api.PodIP{
  166. {IP: "2001:db8::"},
  167. },
  168. },
  169. },
  170. fieldSelector: fields.ParseSelectorOrDie("status.podIP=2001:db7::"),
  171. expectMatch: false,
  172. },
  173. }
  174. for _, testCase := range testCases {
  175. m := MatchPod(labels.Everything(), testCase.fieldSelector)
  176. result, err := m.Matches(testCase.in)
  177. if err != nil {
  178. t.Errorf("Unexpected error %v", err)
  179. }
  180. if result != testCase.expectMatch {
  181. t.Errorf("Result %v, Expected %v, Selector: %v, Pod: %v", result, testCase.expectMatch, testCase.fieldSelector.String(), testCase.in)
  182. }
  183. }
  184. }
  185. func getResourceList(cpu, memory string) api.ResourceList {
  186. res := api.ResourceList{}
  187. if cpu != "" {
  188. res[api.ResourceCPU] = resource.MustParse(cpu)
  189. }
  190. if memory != "" {
  191. res[api.ResourceMemory] = resource.MustParse(memory)
  192. }
  193. return res
  194. }
  195. func getResourceRequirements(requests, limits api.ResourceList) api.ResourceRequirements {
  196. res := api.ResourceRequirements{}
  197. res.Requests = requests
  198. res.Limits = limits
  199. return res
  200. }
  201. func newContainer(name string, requests api.ResourceList, limits api.ResourceList) api.Container {
  202. return api.Container{
  203. Name: name,
  204. Resources: getResourceRequirements(requests, limits),
  205. }
  206. }
  207. func newPod(name string, containers []api.Container) *api.Pod {
  208. return &api.Pod{
  209. ObjectMeta: metav1.ObjectMeta{
  210. Name: name,
  211. },
  212. Spec: api.PodSpec{
  213. Containers: containers,
  214. },
  215. }
  216. }
  217. func TestGetPodQOS(t *testing.T) {
  218. testCases := []struct {
  219. pod *api.Pod
  220. expected api.PodQOSClass
  221. }{
  222. {
  223. pod: newPod("guaranteed", []api.Container{
  224. newContainer("guaranteed", getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")),
  225. }),
  226. expected: api.PodQOSGuaranteed,
  227. },
  228. {
  229. pod: newPod("best-effort", []api.Container{
  230. newContainer("best-effort", getResourceList("", ""), getResourceList("", "")),
  231. }),
  232. expected: api.PodQOSBestEffort,
  233. },
  234. {
  235. pod: newPod("burstable", []api.Container{
  236. newContainer("burstable", getResourceList("100m", "100Mi"), getResourceList("", "")),
  237. }),
  238. expected: api.PodQOSBurstable,
  239. },
  240. }
  241. for id, testCase := range testCases {
  242. Strategy.PrepareForCreate(genericapirequest.NewContext(), testCase.pod)
  243. actual := testCase.pod.Status.QOSClass
  244. if actual != testCase.expected {
  245. t.Errorf("[%d]: invalid qos pod %s, expected: %s, actual: %s", id, testCase.pod.Name, testCase.expected, actual)
  246. }
  247. }
  248. }
  249. func TestCheckGracefulDelete(t *testing.T) {
  250. defaultGracePeriod := int64(30)
  251. tcs := []struct {
  252. in *api.Pod
  253. gracePeriod int64
  254. }{
  255. {
  256. in: &api.Pod{
  257. Spec: api.PodSpec{NodeName: "something"},
  258. Status: api.PodStatus{Phase: api.PodPending},
  259. },
  260. gracePeriod: defaultGracePeriod,
  261. },
  262. {
  263. in: &api.Pod{
  264. Spec: api.PodSpec{NodeName: "something"},
  265. Status: api.PodStatus{Phase: api.PodFailed},
  266. },
  267. gracePeriod: 0,
  268. },
  269. {
  270. in: &api.Pod{
  271. Spec: api.PodSpec{},
  272. Status: api.PodStatus{Phase: api.PodPending},
  273. },
  274. gracePeriod: 0,
  275. },
  276. {
  277. in: &api.Pod{
  278. Spec: api.PodSpec{},
  279. Status: api.PodStatus{Phase: api.PodSucceeded},
  280. },
  281. gracePeriod: 0,
  282. },
  283. {
  284. in: &api.Pod{
  285. Spec: api.PodSpec{},
  286. Status: api.PodStatus{},
  287. },
  288. gracePeriod: 0,
  289. },
  290. }
  291. for _, tc := range tcs {
  292. out := &metav1.DeleteOptions{GracePeriodSeconds: &defaultGracePeriod}
  293. Strategy.CheckGracefulDelete(genericapirequest.NewContext(), tc.in, out)
  294. if out.GracePeriodSeconds == nil {
  295. t.Errorf("out grace period was nil but supposed to be %v", tc.gracePeriod)
  296. }
  297. if *(out.GracePeriodSeconds) != tc.gracePeriod {
  298. t.Errorf("out grace period was %v but was expected to be %v", *out, tc.gracePeriod)
  299. }
  300. }
  301. }
  302. type mockPodGetter struct {
  303. pod *api.Pod
  304. }
  305. func (g mockPodGetter) Get(context.Context, string, *metav1.GetOptions) (runtime.Object, error) {
  306. return g.pod, nil
  307. }
  308. func TestCheckLogLocation(t *testing.T) {
  309. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
  310. ctx := genericapirequest.NewDefaultContext()
  311. fakePodName := "test"
  312. tcs := []struct {
  313. name string
  314. in *api.Pod
  315. opts *api.PodLogOptions
  316. expectedErr error
  317. expectedTransport http.RoundTripper
  318. }{
  319. {
  320. name: "simple",
  321. in: &api.Pod{
  322. ObjectMeta: metav1.ObjectMeta{Name: fakePodName},
  323. Spec: api.PodSpec{
  324. Containers: []api.Container{
  325. {Name: "mycontainer"},
  326. },
  327. NodeName: "foo",
  328. },
  329. Status: api.PodStatus{},
  330. },
  331. opts: &api.PodLogOptions{},
  332. expectedErr: nil,
  333. expectedTransport: fakeSecureRoundTripper,
  334. },
  335. {
  336. name: "insecure",
  337. in: &api.Pod{
  338. ObjectMeta: metav1.ObjectMeta{Name: fakePodName},
  339. Spec: api.PodSpec{
  340. Containers: []api.Container{
  341. {Name: "mycontainer"},
  342. },
  343. NodeName: "foo",
  344. },
  345. Status: api.PodStatus{},
  346. },
  347. opts: &api.PodLogOptions{
  348. InsecureSkipTLSVerifyBackend: true,
  349. },
  350. expectedErr: nil,
  351. expectedTransport: fakeInsecureRoundTripper,
  352. },
  353. {
  354. name: "missing container",
  355. in: &api.Pod{
  356. ObjectMeta: metav1.ObjectMeta{Name: fakePodName},
  357. Spec: api.PodSpec{},
  358. Status: api.PodStatus{},
  359. },
  360. opts: &api.PodLogOptions{},
  361. expectedErr: errors.NewBadRequest("a container name must be specified for pod test"),
  362. expectedTransport: nil,
  363. },
  364. {
  365. name: "choice of two containers",
  366. in: &api.Pod{
  367. ObjectMeta: metav1.ObjectMeta{Name: fakePodName},
  368. Spec: api.PodSpec{
  369. Containers: []api.Container{
  370. {Name: "container1"},
  371. {Name: "container2"},
  372. },
  373. },
  374. Status: api.PodStatus{},
  375. },
  376. opts: &api.PodLogOptions{},
  377. expectedErr: errors.NewBadRequest("a container name must be specified for pod test, choose one of: [container1 container2]"),
  378. expectedTransport: nil,
  379. },
  380. {
  381. name: "initcontainers",
  382. in: &api.Pod{
  383. ObjectMeta: metav1.ObjectMeta{Name: fakePodName},
  384. Spec: api.PodSpec{
  385. Containers: []api.Container{
  386. {Name: "container1"},
  387. {Name: "container2"},
  388. },
  389. InitContainers: []api.Container{
  390. {Name: "initcontainer1"},
  391. },
  392. },
  393. Status: api.PodStatus{},
  394. },
  395. opts: &api.PodLogOptions{},
  396. expectedErr: errors.NewBadRequest("a container name must be specified for pod test, choose one of: [initcontainer1 container1 container2]"),
  397. expectedTransport: nil,
  398. },
  399. {
  400. in: &api.Pod{
  401. ObjectMeta: metav1.ObjectMeta{Name: fakePodName},
  402. Spec: api.PodSpec{
  403. Containers: []api.Container{
  404. {Name: "container1"},
  405. {Name: "container2"},
  406. },
  407. InitContainers: []api.Container{
  408. {Name: "initcontainer1"},
  409. },
  410. EphemeralContainers: []api.EphemeralContainer{
  411. {EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "debugger"}},
  412. },
  413. },
  414. Status: api.PodStatus{},
  415. },
  416. opts: &api.PodLogOptions{},
  417. expectedErr: errors.NewBadRequest("a container name must be specified for pod test, choose one of: [initcontainer1 container1 container2 debugger]"),
  418. expectedTransport: nil,
  419. },
  420. {
  421. name: "bad container",
  422. in: &api.Pod{
  423. ObjectMeta: metav1.ObjectMeta{Name: fakePodName},
  424. Spec: api.PodSpec{
  425. Containers: []api.Container{
  426. {Name: "container1"},
  427. {Name: "container2"},
  428. },
  429. },
  430. Status: api.PodStatus{},
  431. },
  432. opts: &api.PodLogOptions{
  433. Container: "unknown",
  434. },
  435. expectedErr: errors.NewBadRequest("container unknown is not valid for pod test"),
  436. expectedTransport: nil,
  437. },
  438. {
  439. name: "good with two containers",
  440. in: &api.Pod{
  441. ObjectMeta: metav1.ObjectMeta{Name: fakePodName},
  442. Spec: api.PodSpec{
  443. Containers: []api.Container{
  444. {Name: "container1"},
  445. {Name: "container2"},
  446. },
  447. NodeName: "foo",
  448. },
  449. Status: api.PodStatus{},
  450. },
  451. opts: &api.PodLogOptions{
  452. Container: "container2",
  453. },
  454. expectedErr: nil,
  455. expectedTransport: fakeSecureRoundTripper,
  456. },
  457. }
  458. for _, tc := range tcs {
  459. t.Run(tc.name, func(t *testing.T) {
  460. getter := &mockPodGetter{tc.in}
  461. connectionGetter := &mockConnectionInfoGetter{&client.ConnectionInfo{
  462. Transport: fakeSecureRoundTripper,
  463. InsecureSkipTLSVerifyTransport: fakeInsecureRoundTripper,
  464. }}
  465. _, actualTransport, err := LogLocation(ctx, getter, connectionGetter, fakePodName, tc.opts)
  466. if !reflect.DeepEqual(err, tc.expectedErr) {
  467. t.Errorf("expected %q, got %q", tc.expectedErr, err)
  468. }
  469. if actualTransport != tc.expectedTransport {
  470. t.Errorf("expected %q, got %q", tc.expectedTransport, actualTransport)
  471. }
  472. })
  473. }
  474. }
  475. func TestSelectableFieldLabelConversions(t *testing.T) {
  476. apitesting.TestSelectableFieldLabelConversionsOfKind(t,
  477. "v1",
  478. "Pod",
  479. ToSelectableFields(&api.Pod{}),
  480. nil,
  481. )
  482. }
  483. type mockConnectionInfoGetter struct {
  484. info *client.ConnectionInfo
  485. }
  486. func (g mockConnectionInfoGetter) GetConnectionInfo(ctx context.Context, nodeName types.NodeName) (*client.ConnectionInfo, error) {
  487. return g.info, nil
  488. }
  489. func TestPortForwardLocation(t *testing.T) {
  490. ctx := genericapirequest.NewDefaultContext()
  491. tcs := []struct {
  492. in *api.Pod
  493. info *client.ConnectionInfo
  494. opts *api.PodPortForwardOptions
  495. expectedErr error
  496. expectedURL *url.URL
  497. }{
  498. {
  499. in: &api.Pod{
  500. Spec: api.PodSpec{},
  501. },
  502. opts: &api.PodPortForwardOptions{},
  503. expectedErr: errors.NewBadRequest("pod test does not have a host assigned"),
  504. },
  505. {
  506. in: &api.Pod{
  507. ObjectMeta: metav1.ObjectMeta{
  508. Namespace: "ns",
  509. Name: "pod1",
  510. },
  511. Spec: api.PodSpec{
  512. NodeName: "node1",
  513. },
  514. },
  515. info: &client.ConnectionInfo{},
  516. opts: &api.PodPortForwardOptions{},
  517. expectedURL: &url.URL{Host: ":", Path: "/portForward/ns/pod1"},
  518. },
  519. {
  520. in: &api.Pod{
  521. ObjectMeta: metav1.ObjectMeta{
  522. Namespace: "ns",
  523. Name: "pod1",
  524. },
  525. Spec: api.PodSpec{
  526. NodeName: "node1",
  527. },
  528. },
  529. info: &client.ConnectionInfo{},
  530. opts: &api.PodPortForwardOptions{Ports: []int32{80}},
  531. expectedURL: &url.URL{Host: ":", Path: "/portForward/ns/pod1", RawQuery: "port=80"},
  532. },
  533. }
  534. for _, tc := range tcs {
  535. getter := &mockPodGetter{tc.in}
  536. connectionGetter := &mockConnectionInfoGetter{tc.info}
  537. loc, _, err := PortForwardLocation(ctx, getter, connectionGetter, "test", tc.opts)
  538. if !reflect.DeepEqual(err, tc.expectedErr) {
  539. t.Errorf("expected %v, got %v", tc.expectedErr, err)
  540. }
  541. if !reflect.DeepEqual(loc, tc.expectedURL) {
  542. t.Errorf("expected %v, got %v", tc.expectedURL, loc)
  543. }
  544. }
  545. }
  546. func TestGetPodIP(t *testing.T) {
  547. testCases := []struct {
  548. name string
  549. pod *api.Pod
  550. expectedIP string
  551. }{
  552. {
  553. name: "nil pod",
  554. pod: nil,
  555. expectedIP: "",
  556. },
  557. {
  558. name: "no status object",
  559. pod: &api.Pod{
  560. ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "pod1"},
  561. Spec: api.PodSpec{},
  562. },
  563. expectedIP: "",
  564. },
  565. {
  566. name: "no pod ips",
  567. pod: &api.Pod{
  568. ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "pod1"},
  569. Spec: api.PodSpec{},
  570. Status: api.PodStatus{},
  571. },
  572. expectedIP: "",
  573. },
  574. {
  575. name: "empty list",
  576. pod: &api.Pod{
  577. ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "pod1"},
  578. Spec: api.PodSpec{},
  579. Status: api.PodStatus{
  580. PodIPs: []api.PodIP{},
  581. },
  582. },
  583. expectedIP: "",
  584. },
  585. {
  586. name: "1 ip",
  587. pod: &api.Pod{
  588. ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "pod1"},
  589. Spec: api.PodSpec{},
  590. Status: api.PodStatus{
  591. PodIPs: []api.PodIP{
  592. {IP: "10.0.0.10"},
  593. },
  594. },
  595. },
  596. expectedIP: "10.0.0.10",
  597. },
  598. {
  599. name: "multiple ips",
  600. pod: &api.Pod{
  601. ObjectMeta: metav1.ObjectMeta{Namespace: "ns", Name: "pod1"},
  602. Spec: api.PodSpec{},
  603. Status: api.PodStatus{
  604. PodIPs: []api.PodIP{
  605. {IP: "10.0.0.10"},
  606. {IP: "10.0.0.20"},
  607. },
  608. },
  609. },
  610. expectedIP: "10.0.0.10",
  611. },
  612. }
  613. for _, tc := range testCases {
  614. t.Run(tc.name, func(t *testing.T) {
  615. podIP := getPodIP(tc.pod)
  616. if podIP != tc.expectedIP {
  617. t.Errorf("expected pod ip:%v does not match actual %v", tc.expectedIP, podIP)
  618. }
  619. })
  620. }
  621. }
  622. type fakeTransport struct {
  623. val string
  624. }
  625. func (f fakeTransport) RoundTrip(*http.Request) (*http.Response, error) {
  626. return nil, nil
  627. }
  628. var (
  629. fakeSecureRoundTripper = fakeTransport{val: "secure"}
  630. fakeInsecureRoundTripper = fakeTransport{val: "insecure"}
  631. )
  632. func TestPodIndexFunc(t *testing.T) {
  633. tcs := []struct {
  634. name string
  635. indexFunc cache.IndexFunc
  636. pod interface{}
  637. expectedValue string
  638. expectedErr error
  639. }{
  640. {
  641. name: "node name index",
  642. indexFunc: NodeNameIndexFunc,
  643. pod: &api.Pod{
  644. Spec: api.PodSpec{
  645. NodeName: "test-pod",
  646. },
  647. },
  648. expectedValue: "test-pod",
  649. expectedErr: nil,
  650. },
  651. {
  652. name: "not a pod failed",
  653. indexFunc: NodeNameIndexFunc,
  654. pod: "not a pod object",
  655. expectedValue: "test-pod",
  656. expectedErr: fmt.Errorf("not a pod"),
  657. },
  658. }
  659. for _, tc := range tcs {
  660. indexValues, err := tc.indexFunc(tc.pod)
  661. if !reflect.DeepEqual(err, tc.expectedErr) {
  662. t.Errorf("name %v, expected %v, got %v", tc.name, tc.expectedErr, err)
  663. }
  664. if err == nil && len(indexValues) != 1 && indexValues[0] != tc.expectedValue {
  665. t.Errorf("name %v, expected %v, got %v", tc.name, tc.expectedValue, indexValues)
  666. }
  667. }
  668. }