conversion_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. /*
  2. Copyright 2015 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 v1_test
  14. import (
  15. "encoding/json"
  16. "math/rand"
  17. "net/url"
  18. "reflect"
  19. "testing"
  20. "time"
  21. appsv1 "k8s.io/api/apps/v1"
  22. v1 "k8s.io/api/core/v1"
  23. "k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
  24. apiequality "k8s.io/apimachinery/pkg/api/equality"
  25. "k8s.io/apimachinery/pkg/api/resource"
  26. metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer"
  27. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  28. "k8s.io/apimachinery/pkg/runtime"
  29. "k8s.io/apimachinery/pkg/util/diff"
  30. "k8s.io/kubernetes/pkg/api/legacyscheme"
  31. apps "k8s.io/kubernetes/pkg/apis/apps"
  32. "k8s.io/kubernetes/pkg/apis/core"
  33. corefuzzer "k8s.io/kubernetes/pkg/apis/core/fuzzer"
  34. corev1 "k8s.io/kubernetes/pkg/apis/core/v1"
  35. utilpointer "k8s.io/utils/pointer"
  36. // ensure types are installed
  37. _ "k8s.io/kubernetes/pkg/apis/core/install"
  38. // ensure types are installed corereplicationcontroller<->replicaset conversions
  39. _ "k8s.io/kubernetes/pkg/apis/apps/install"
  40. )
  41. func TestPodLogOptions(t *testing.T) {
  42. sinceSeconds := int64(1)
  43. sinceTime := metav1.NewTime(time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC).Local())
  44. tailLines := int64(2)
  45. limitBytes := int64(3)
  46. versionedLogOptions := &v1.PodLogOptions{
  47. Container: "mycontainer",
  48. Follow: true,
  49. Previous: true,
  50. SinceSeconds: &sinceSeconds,
  51. SinceTime: &sinceTime,
  52. Timestamps: true,
  53. TailLines: &tailLines,
  54. LimitBytes: &limitBytes,
  55. }
  56. unversionedLogOptions := &core.PodLogOptions{
  57. Container: "mycontainer",
  58. Follow: true,
  59. Previous: true,
  60. SinceSeconds: &sinceSeconds,
  61. SinceTime: &sinceTime,
  62. Timestamps: true,
  63. TailLines: &tailLines,
  64. LimitBytes: &limitBytes,
  65. }
  66. expectedParameters := url.Values{
  67. "container": {"mycontainer"},
  68. "follow": {"true"},
  69. "previous": {"true"},
  70. "sinceSeconds": {"1"},
  71. "sinceTime": {"2000-01-01T12:34:56Z"},
  72. "timestamps": {"true"},
  73. "tailLines": {"2"},
  74. "limitBytes": {"3"},
  75. }
  76. codec := runtime.NewParameterCodec(legacyscheme.Scheme)
  77. // unversioned -> query params
  78. {
  79. actualParameters, err := codec.EncodeParameters(unversionedLogOptions, v1.SchemeGroupVersion)
  80. if err != nil {
  81. t.Fatal(err)
  82. }
  83. if !reflect.DeepEqual(actualParameters, expectedParameters) {
  84. t.Fatalf("Expected\n%#v\ngot\n%#v", expectedParameters, actualParameters)
  85. }
  86. }
  87. // versioned -> query params
  88. {
  89. actualParameters, err := codec.EncodeParameters(versionedLogOptions, v1.SchemeGroupVersion)
  90. if err != nil {
  91. t.Fatal(err)
  92. }
  93. if !reflect.DeepEqual(actualParameters, expectedParameters) {
  94. t.Fatalf("Expected\n%#v\ngot\n%#v", expectedParameters, actualParameters)
  95. }
  96. }
  97. // query params -> versioned
  98. {
  99. convertedLogOptions := &v1.PodLogOptions{}
  100. err := codec.DecodeParameters(expectedParameters, v1.SchemeGroupVersion, convertedLogOptions)
  101. if err != nil {
  102. t.Fatal(err)
  103. }
  104. if !reflect.DeepEqual(convertedLogOptions, versionedLogOptions) {
  105. t.Fatalf("Unexpected deserialization:\n%s", diff.ObjectGoPrintSideBySide(versionedLogOptions, convertedLogOptions))
  106. }
  107. }
  108. // query params -> unversioned
  109. {
  110. convertedLogOptions := &core.PodLogOptions{}
  111. err := codec.DecodeParameters(expectedParameters, v1.SchemeGroupVersion, convertedLogOptions)
  112. if err != nil {
  113. t.Fatal(err)
  114. }
  115. if !reflect.DeepEqual(convertedLogOptions, unversionedLogOptions) {
  116. t.Fatalf("Unexpected deserialization:\n%s", diff.ObjectGoPrintSideBySide(unversionedLogOptions, convertedLogOptions))
  117. }
  118. }
  119. }
  120. // TestPodSpecConversion tests that v1.ServiceAccount is an alias for
  121. // ServiceAccountName.
  122. func TestPodSpecConversion(t *testing.T) {
  123. name, other := "foo", "bar"
  124. // Test internal -> v1. Should have both alias (DeprecatedServiceAccount)
  125. // and new field (ServiceAccountName).
  126. i := &core.PodSpec{
  127. ServiceAccountName: name,
  128. }
  129. v := v1.PodSpec{}
  130. if err := legacyscheme.Scheme.Convert(i, &v, nil); err != nil {
  131. t.Fatalf("unexpected error: %v", err)
  132. }
  133. if v.ServiceAccountName != name {
  134. t.Fatalf("want v1.ServiceAccountName %q, got %q", name, v.ServiceAccountName)
  135. }
  136. if v.DeprecatedServiceAccount != name {
  137. t.Fatalf("want v1.DeprecatedServiceAccount %q, got %q", name, v.DeprecatedServiceAccount)
  138. }
  139. // Test v1 -> internal. Either DeprecatedServiceAccount, ServiceAccountName,
  140. // or both should translate to ServiceAccountName. ServiceAccountName wins
  141. // if both are set.
  142. testCases := []*v1.PodSpec{
  143. // New
  144. {ServiceAccountName: name},
  145. // Alias
  146. {DeprecatedServiceAccount: name},
  147. // Both: same
  148. {ServiceAccountName: name, DeprecatedServiceAccount: name},
  149. // Both: different
  150. {ServiceAccountName: name, DeprecatedServiceAccount: other},
  151. }
  152. for k, v := range testCases {
  153. got := core.PodSpec{}
  154. err := legacyscheme.Scheme.Convert(v, &got, nil)
  155. if err != nil {
  156. t.Fatalf("unexpected error for case %d: %v", k, err)
  157. }
  158. if got.ServiceAccountName != name {
  159. t.Fatalf("want core.ServiceAccountName %q, got %q", name, got.ServiceAccountName)
  160. }
  161. }
  162. }
  163. func TestResourceListConversion(t *testing.T) {
  164. bigMilliQuantity := resource.NewQuantity(resource.MaxMilliValue, resource.DecimalSI)
  165. bigMilliQuantity.Add(resource.MustParse("12345m"))
  166. tests := []struct {
  167. input v1.ResourceList
  168. expected core.ResourceList
  169. }{
  170. { // No changes necessary.
  171. input: v1.ResourceList{
  172. v1.ResourceMemory: resource.MustParse("30M"),
  173. v1.ResourceCPU: resource.MustParse("100m"),
  174. v1.ResourceStorage: resource.MustParse("1G"),
  175. },
  176. expected: core.ResourceList{
  177. core.ResourceMemory: resource.MustParse("30M"),
  178. core.ResourceCPU: resource.MustParse("100m"),
  179. core.ResourceStorage: resource.MustParse("1G"),
  180. },
  181. },
  182. { // Nano-scale values should be rounded up to milli-scale.
  183. input: v1.ResourceList{
  184. v1.ResourceCPU: resource.MustParse("3.000023m"),
  185. v1.ResourceMemory: resource.MustParse("500.000050m"),
  186. },
  187. expected: core.ResourceList{
  188. core.ResourceCPU: resource.MustParse("4m"),
  189. core.ResourceMemory: resource.MustParse("501m"),
  190. },
  191. },
  192. { // Large values should still be accurate.
  193. input: v1.ResourceList{
  194. v1.ResourceCPU: bigMilliQuantity.DeepCopy(),
  195. v1.ResourceStorage: bigMilliQuantity.DeepCopy(),
  196. },
  197. expected: core.ResourceList{
  198. core.ResourceCPU: bigMilliQuantity.DeepCopy(),
  199. core.ResourceStorage: bigMilliQuantity.DeepCopy(),
  200. },
  201. },
  202. }
  203. for i, test := range tests {
  204. output := core.ResourceList{}
  205. // defaulting is a separate step from conversion that is applied when reading from the API or from etcd.
  206. // perform that step explicitly.
  207. corev1.SetDefaults_ResourceList(&test.input)
  208. err := legacyscheme.Scheme.Convert(&test.input, &output, nil)
  209. if err != nil {
  210. t.Fatalf("unexpected error for case %d: %v", i, err)
  211. }
  212. if !apiequality.Semantic.DeepEqual(test.expected, output) {
  213. t.Errorf("unexpected conversion for case %d: Expected\n%+v;\nGot\n%+v", i, test.expected, output)
  214. }
  215. }
  216. }
  217. func TestReplicationControllerConversion(t *testing.T) {
  218. // If we start with a RC, we should always have round-trip fidelity.
  219. inputs := []*v1.ReplicationController{
  220. {
  221. ObjectMeta: metav1.ObjectMeta{
  222. Name: "name",
  223. Namespace: "namespace",
  224. },
  225. Spec: v1.ReplicationControllerSpec{
  226. Replicas: utilpointer.Int32Ptr(1),
  227. MinReadySeconds: 32,
  228. Selector: map[string]string{"foo": "bar", "bar": "foo"},
  229. Template: &v1.PodTemplateSpec{
  230. ObjectMeta: metav1.ObjectMeta{
  231. Labels: map[string]string{"foo": "bar", "bar": "foo"},
  232. },
  233. Spec: v1.PodSpec{
  234. Containers: []v1.Container{
  235. {
  236. Name: "container",
  237. Image: "image",
  238. },
  239. },
  240. },
  241. },
  242. },
  243. Status: v1.ReplicationControllerStatus{
  244. Replicas: 1,
  245. FullyLabeledReplicas: 2,
  246. ReadyReplicas: 3,
  247. AvailableReplicas: 4,
  248. ObservedGeneration: 5,
  249. Conditions: []v1.ReplicationControllerCondition{
  250. {
  251. Type: v1.ReplicationControllerReplicaFailure,
  252. Status: v1.ConditionTrue,
  253. LastTransitionTime: metav1.NewTime(time.Unix(123456789, 0)),
  254. Reason: "Reason",
  255. Message: "Message",
  256. },
  257. },
  258. },
  259. },
  260. }
  261. // Add some fuzzed RCs.
  262. apiObjectFuzzer := fuzzer.FuzzerFor(fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, corefuzzer.Funcs), rand.NewSource(152), legacyscheme.Codecs)
  263. for i := 0; i < 100; i++ {
  264. rc := &v1.ReplicationController{}
  265. apiObjectFuzzer.Fuzz(rc)
  266. // Sometimes the fuzzer decides to leave Spec.Template nil.
  267. // We can't support that because Spec.Template is not a pointer in RS,
  268. // so it will round-trip as non-nil but empty.
  269. if rc.Spec.Template == nil {
  270. rc.Spec.Template = &v1.PodTemplateSpec{}
  271. }
  272. // Sometimes the fuzzer decides to insert an empty label key.
  273. // This doesn't round-trip properly because it's invalid.
  274. if rc.Spec.Selector != nil {
  275. delete(rc.Spec.Selector, "")
  276. }
  277. inputs = append(inputs, rc)
  278. }
  279. // Round-trip the input RCs before converting to RS.
  280. for i := range inputs {
  281. inputs[i] = roundTrip(t, inputs[i]).(*v1.ReplicationController)
  282. }
  283. for _, in := range inputs {
  284. rs := &apps.ReplicaSet{}
  285. // Use in.DeepCopy() to avoid sharing pointers with `in`.
  286. if err := corev1.Convert_v1_ReplicationController_To_apps_ReplicaSet(in.DeepCopy(), rs, nil); err != nil {
  287. t.Errorf("can't convert RC to RS: %v", err)
  288. continue
  289. }
  290. // Round-trip RS before converting back to RC.
  291. rs = roundTripRS(t, rs)
  292. out := &v1.ReplicationController{}
  293. if err := corev1.Convert_apps_ReplicaSet_To_v1_ReplicationController(rs, out, nil); err != nil {
  294. t.Errorf("can't convert RS to RC: %v", err)
  295. continue
  296. }
  297. if !apiequality.Semantic.DeepEqual(in, out) {
  298. instr, _ := json.MarshalIndent(in, "", " ")
  299. outstr, _ := json.MarshalIndent(out, "", " ")
  300. t.Errorf("RC-RS conversion round-trip failed:\nin:\n%s\nout:\n%s", instr, outstr)
  301. }
  302. }
  303. }
  304. func roundTripRS(t *testing.T, rs *apps.ReplicaSet) *apps.ReplicaSet {
  305. codec := legacyscheme.Codecs.LegacyCodec(appsv1.SchemeGroupVersion)
  306. data, err := runtime.Encode(codec, rs)
  307. if err != nil {
  308. t.Errorf("%v\n %#v", err, rs)
  309. return nil
  310. }
  311. obj2, err := runtime.Decode(codec, data)
  312. if err != nil {
  313. t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), rs)
  314. return nil
  315. }
  316. return obj2.(*apps.ReplicaSet)
  317. }
  318. func Test_core_PodStatus_to_v1_PodStatus(t *testing.T) {
  319. // core to v1
  320. testInputs := []core.PodStatus{
  321. {
  322. // one IP
  323. PodIPs: []core.PodIP{
  324. {
  325. IP: "1.1.1.1",
  326. },
  327. },
  328. },
  329. {
  330. // no ips
  331. PodIPs: nil,
  332. },
  333. {
  334. // list of ips
  335. PodIPs: []core.PodIP{
  336. {
  337. IP: "1.1.1.1",
  338. },
  339. {
  340. IP: "2000::",
  341. },
  342. },
  343. },
  344. }
  345. for i, input := range testInputs {
  346. v1PodStatus := v1.PodStatus{}
  347. if err := corev1.Convert_core_PodStatus_To_v1_PodStatus(&input, &v1PodStatus, nil); nil != err {
  348. t.Errorf("%v: Convert core.PodStatus to v1.PodStatus failed with error %v", i, err.Error())
  349. }
  350. if len(input.PodIPs) == 0 {
  351. // no more work needed
  352. continue
  353. }
  354. // Primary IP was not set..
  355. if len(v1PodStatus.PodIP) == 0 {
  356. t.Errorf("%v: Convert core.PodStatus to v1.PodStatus failed out.PodIP is empty, should be %v", i, v1PodStatus.PodIP)
  357. }
  358. // Primary should always == in.PodIPs[0].IP
  359. if len(input.PodIPs) > 0 && v1PodStatus.PodIP != input.PodIPs[0].IP {
  360. t.Errorf("%v: Convert core.PodStatus to v1.PodStatus failed out.PodIP != in.PodIP[0].IP expected %v found %v", i, input.PodIPs[0].IP, v1PodStatus.PodIP)
  361. }
  362. // match v1.PodIPs to core.PodIPs
  363. for idx := range input.PodIPs {
  364. if v1PodStatus.PodIPs[idx].IP != input.PodIPs[idx].IP {
  365. t.Errorf("%v: Convert core.PodStatus to v1.PodStatus failed. Expected v1.PodStatus[%v]=%v but found %v", i, idx, input.PodIPs[idx].IP, v1PodStatus.PodIPs[idx].IP)
  366. }
  367. }
  368. }
  369. }
  370. func Test_v1_PodStatus_to_core_PodStatus(t *testing.T) {
  371. // fail
  372. v1FailTestInputs := []v1.PodStatus{
  373. {
  374. PodIP: "1.1.2.1", // fail becaue PodIP != PodIPs[0]
  375. PodIPs: []v1.PodIP{
  376. {IP: "1.1.1.1"},
  377. {IP: "2.2.2.2"},
  378. },
  379. },
  380. }
  381. // success
  382. v1TestInputs := []v1.PodStatus{
  383. // only Primary IP Provided
  384. {
  385. PodIP: "1.1.1.1",
  386. },
  387. {
  388. // both are not provided
  389. PodIP: "",
  390. PodIPs: nil,
  391. },
  392. // only list of IPs
  393. {
  394. PodIPs: []v1.PodIP{
  395. {IP: "1.1.1.1"},
  396. {IP: "2.2.2.2"},
  397. },
  398. },
  399. // Both
  400. {
  401. PodIP: "1.1.1.1",
  402. PodIPs: []v1.PodIP{
  403. {IP: "1.1.1.1"},
  404. {IP: "2.2.2.2"},
  405. },
  406. },
  407. // v4 and v6
  408. {
  409. PodIP: "1.1.1.1",
  410. PodIPs: []v1.PodIP{
  411. {IP: "1.1.1.1"},
  412. {IP: "::1"},
  413. },
  414. },
  415. // v6 and v4
  416. {
  417. PodIP: "::1",
  418. PodIPs: []v1.PodIP{
  419. {IP: "::1"},
  420. {IP: "1.1.1.1"},
  421. },
  422. },
  423. }
  424. // run failed cases
  425. for i, failedTest := range v1FailTestInputs {
  426. corePodStatus := core.PodStatus{}
  427. // convert..
  428. if err := corev1.Convert_v1_PodStatus_To_core_PodStatus(&failedTest, &corePodStatus, nil); err == nil {
  429. t.Errorf("%v: Convert v1.PodStatus to core.PodStatus should have failed for input %+v", i, failedTest)
  430. }
  431. }
  432. // run ok cases
  433. for i, testInput := range v1TestInputs {
  434. corePodStatus := core.PodStatus{}
  435. // convert..
  436. if err := corev1.Convert_v1_PodStatus_To_core_PodStatus(&testInput, &corePodStatus, nil); err != nil {
  437. t.Errorf("%v: Convert v1.PodStatus to core.PodStatus failed with error:%v for input %+v", i, err.Error(), testInput)
  438. }
  439. if len(testInput.PodIP) == 0 && len(testInput.PodIPs) == 0 {
  440. continue //no more work needed
  441. }
  442. // List should have at least 1 IP == v1.PodIP || v1.PodIPs[0] (whichever provided)
  443. if len(testInput.PodIP) > 0 && corePodStatus.PodIPs[0].IP != testInput.PodIP {
  444. t.Errorf("%v: Convert v1.PodStatus to core.PodStatus failed. expected corePodStatus.PodIPs[0].ip=%v found %v", i, corePodStatus.PodIPs[0].IP, corePodStatus.PodIPs[0].IP)
  445. }
  446. // walk the list
  447. for idx := range testInput.PodIPs {
  448. if corePodStatus.PodIPs[idx].IP != testInput.PodIPs[idx].IP {
  449. t.Errorf("%v: Convert v1.PodStatus to core.PodStatus failed core.PodIPs[%v]=%v expected %v", i, idx, corePodStatus.PodIPs[idx].IP, testInput.PodIPs[idx].IP)
  450. }
  451. }
  452. // if input has a list of IPs
  453. // then out put should have the same length
  454. if len(testInput.PodIPs) > 0 && len(testInput.PodIPs) != len(corePodStatus.PodIPs) {
  455. t.Errorf("%v: Convert v1.PodStatus to core.PodStatus failed len(core.PodIPs) != len(v1.PodStatus.PodIPs) [%v]=[%v]", i, len(corePodStatus.PodIPs), len(testInput.PodIPs))
  456. }
  457. }
  458. }
  459. func Test_core_NodeSpec_to_v1_NodeSpec(t *testing.T) {
  460. // core to v1
  461. testInputs := []core.NodeSpec{
  462. {
  463. PodCIDRs: []string{"10.0.0.0/24", "10.0.1.0/24"},
  464. },
  465. {
  466. PodCIDRs: nil,
  467. },
  468. {
  469. PodCIDRs: []string{"10.0.0.0/24"},
  470. },
  471. {
  472. PodCIDRs: []string{"ace:cab:deca::/8"},
  473. },
  474. {
  475. PodCIDRs: []string{"10.0.0.0/24", "ace:cab:deca::/8"},
  476. },
  477. {
  478. PodCIDRs: []string{"ace:cab:deca::/8", "10.0.0.0/24"},
  479. },
  480. }
  481. for i, testInput := range testInputs {
  482. v1NodeSpec := v1.NodeSpec{}
  483. // convert
  484. if err := corev1.Convert_core_NodeSpec_To_v1_NodeSpec(&testInput, &v1NodeSpec, nil); nil != err {
  485. t.Errorf("%v: Convert core.NodeSpec to v1.NodeSpec failed with error %v", i, err.Error())
  486. }
  487. if len(testInput.PodCIDRs) == 0 {
  488. continue // no more work needed
  489. }
  490. // validate results
  491. if v1NodeSpec.PodCIDR != testInput.PodCIDRs[0] {
  492. t.Errorf("%v: Convert core.NodeSpec to v1.NodeSpec failed. Expected v1.PodCIDR=%v but found %v", i, testInput.PodCIDRs[0], v1NodeSpec.PodCIDR)
  493. }
  494. // match v1.PodIPs to core.PodIPs
  495. for idx := range testInput.PodCIDRs {
  496. if v1NodeSpec.PodCIDRs[idx] != testInput.PodCIDRs[idx] {
  497. t.Errorf("%v: Convert core.NodeSpec to v1.NodeSpec failed. Expected v1.NodeSpec[%v]=%v but found %v", i, idx, testInput.PodCIDRs[idx], v1NodeSpec.PodCIDRs[idx])
  498. }
  499. }
  500. }
  501. }
  502. func Test_v1_NodeSpec_to_core_NodeSpec(t *testing.T) {
  503. failInputs := []v1.NodeSpec{
  504. { // fail PodCIDRs[0] != PodCIDR
  505. PodCIDR: "10.0.0.0/24",
  506. PodCIDRs: []string{"10.0.1.0/24", "ace:cab:deca::/8"},
  507. },
  508. }
  509. testInputs := []v1.NodeSpec{
  510. // cidr only - 4
  511. {
  512. PodCIDR: "10.0.1.0/24",
  513. },
  514. // cidr only - 6
  515. {
  516. PodCIDR: "ace:cab:deca::/8",
  517. },
  518. // Both are provided
  519. {
  520. PodCIDR: "10.0.1.0/24",
  521. PodCIDRs: []string{"10.0.1.0/24", "ace:cab:deca::/8"},
  522. },
  523. // list only
  524. {
  525. PodCIDRs: []string{"10.0.1.0/24", "ace:cab:deca::/8"},
  526. },
  527. // Both are provided 4,6
  528. {
  529. PodCIDR: "10.0.1.0/24",
  530. PodCIDRs: []string{"10.0.1.0/24", "ace:cab:deca::/8"},
  531. },
  532. // Both are provided 6,4
  533. {
  534. PodCIDR: "ace:cab:deca::/8",
  535. PodCIDRs: []string{"ace:cab:deca::/8", "10.0.1.0/24"},
  536. },
  537. // list only 4,6
  538. {
  539. PodCIDRs: []string{"10.0.1.0/24", "ace:cab:deca::/8"},
  540. },
  541. // list only 6,4
  542. {
  543. PodCIDRs: []string{"ace:cab:deca::/8", "10.0.1.0/24"},
  544. },
  545. // no cidr and no cidrs
  546. {
  547. PodCIDR: "",
  548. PodCIDRs: nil,
  549. },
  550. }
  551. // fail cases
  552. for i, failInput := range failInputs {
  553. coreNodeSpec := core.NodeSpec{}
  554. if err := corev1.Convert_v1_NodeSpec_To_core_NodeSpec(&failInput, &coreNodeSpec, nil); err == nil {
  555. t.Errorf("%v: Convert v1.NodeSpec to core.NodeSpec failed. Expected an error when coreNodeSpec.PodCIDR != coreNodeSpec.PodCIDRs[0]", i)
  556. }
  557. }
  558. for i, testInput := range testInputs {
  559. coreNodeSpec := core.NodeSpec{}
  560. if err := corev1.Convert_v1_NodeSpec_To_core_NodeSpec(&testInput, &coreNodeSpec, nil); err != nil {
  561. t.Errorf("%v:Convert v1.NodeSpec to core.NodeSpec failed with error:%v", i, err.Error())
  562. }
  563. if len(testInput.PodCIDRs) == 0 && len(testInput.PodCIDR) == 0 {
  564. continue // no more work needed
  565. }
  566. if len(testInput.PodCIDR) > 0 && coreNodeSpec.PodCIDRs[0] != testInput.PodCIDR {
  567. t.Errorf("%v:Convert v1.NodeSpec to core.NodeSpec failed. expected coreNodeSpec.PodCIDRs[0]=%v found %v", i, testInput.PodCIDR, coreNodeSpec.PodCIDRs[0])
  568. }
  569. // match ip list
  570. for idx := range testInput.PodCIDRs {
  571. if coreNodeSpec.PodCIDRs[idx] != testInput.PodCIDRs[idx] {
  572. t.Errorf("%v:Convert v1.NodeSpec to core.NodeSpec failed core.PodCIDRs[%v]=%v expected %v", i, idx, coreNodeSpec.PodCIDRs[idx], testInput.PodCIDRs[idx])
  573. }
  574. }
  575. }
  576. }