set_env_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  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 set
  14. import (
  15. "fmt"
  16. "io/ioutil"
  17. "net/http"
  18. "strings"
  19. "testing"
  20. "github.com/stretchr/testify/assert"
  21. appsv1 "k8s.io/api/apps/v1"
  22. appsv1beta1 "k8s.io/api/apps/v1beta1"
  23. appsv1beta2 "k8s.io/api/apps/v1beta2"
  24. batchv1 "k8s.io/api/batch/v1"
  25. corev1 "k8s.io/api/core/v1"
  26. extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
  27. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  28. "k8s.io/apimachinery/pkg/runtime"
  29. "k8s.io/apimachinery/pkg/runtime/schema"
  30. "k8s.io/cli-runtime/pkg/genericclioptions"
  31. "k8s.io/cli-runtime/pkg/resource"
  32. restclient "k8s.io/client-go/rest"
  33. "k8s.io/client-go/rest/fake"
  34. cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
  35. "k8s.io/kubernetes/pkg/kubectl/scheme"
  36. )
  37. func TestSetEnvLocal(t *testing.T) {
  38. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  39. defer tf.Cleanup()
  40. tf.Client = &fake.RESTClient{
  41. GroupVersion: schema.GroupVersion{Version: ""},
  42. NegotiatedSerializer: scheme.Codecs.WithoutConversion(),
  43. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  44. t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
  45. return nil, nil
  46. }),
  47. }
  48. tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
  49. outputFormat := "name"
  50. streams, _, buf, bufErr := genericclioptions.NewTestIOStreams()
  51. opts := NewEnvOptions(streams)
  52. opts.PrintFlags = genericclioptions.NewPrintFlags("").WithDefaultOutput(outputFormat).WithTypeSetter(scheme.Scheme)
  53. opts.FilenameOptions = resource.FilenameOptions{
  54. Filenames: []string{"../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"},
  55. }
  56. opts.Local = true
  57. err := opts.Complete(tf, NewCmdEnv(tf, streams), []string{"env=prod"})
  58. assert.NoError(t, err)
  59. err = opts.Validate()
  60. assert.NoError(t, err)
  61. err = opts.RunEnv()
  62. assert.NoError(t, err)
  63. if bufErr.Len() > 0 {
  64. t.Errorf("unexpected error: %s", string(bufErr.String()))
  65. }
  66. if !strings.Contains(buf.String(), "replicationcontroller/cassandra") {
  67. t.Errorf("did not set env: %s", buf.String())
  68. }
  69. }
  70. func TestSetEnvLocalNamespace(t *testing.T) {
  71. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  72. defer tf.Cleanup()
  73. tf.Client = &fake.RESTClient{
  74. GroupVersion: schema.GroupVersion{Version: ""},
  75. NegotiatedSerializer: scheme.Codecs.WithoutConversion(),
  76. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  77. t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
  78. return nil, nil
  79. }),
  80. }
  81. tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
  82. outputFormat := "yaml"
  83. streams, _, buf, bufErr := genericclioptions.NewTestIOStreams()
  84. opts := NewEnvOptions(streams)
  85. opts.PrintFlags = genericclioptions.NewPrintFlags("").WithDefaultOutput(outputFormat).WithTypeSetter(scheme.Scheme)
  86. opts.FilenameOptions = resource.FilenameOptions{
  87. Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/namespaced-resource.yaml"},
  88. }
  89. opts.Local = true
  90. err := opts.Complete(tf, NewCmdEnv(tf, streams), []string{"env=prod"})
  91. assert.NoError(t, err)
  92. err = opts.Validate()
  93. assert.NoError(t, err)
  94. err = opts.RunEnv()
  95. assert.NoError(t, err)
  96. if bufErr.Len() > 0 {
  97. t.Errorf("unexpected error: %s", string(bufErr.String()))
  98. }
  99. if !strings.Contains(buf.String(), "namespace: existing-ns") {
  100. t.Errorf("did not set env: %s", buf.String())
  101. }
  102. }
  103. func TestSetMultiResourcesEnvLocal(t *testing.T) {
  104. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  105. defer tf.Cleanup()
  106. tf.Client = &fake.RESTClient{
  107. GroupVersion: schema.GroupVersion{Version: ""},
  108. NegotiatedSerializer: scheme.Codecs.WithoutConversion(),
  109. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  110. t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
  111. return nil, nil
  112. }),
  113. }
  114. tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
  115. outputFormat := "name"
  116. streams, _, buf, bufErr := genericclioptions.NewTestIOStreams()
  117. opts := NewEnvOptions(streams)
  118. opts.PrintFlags = genericclioptions.NewPrintFlags("").WithDefaultOutput(outputFormat).WithTypeSetter(scheme.Scheme)
  119. opts.FilenameOptions = resource.FilenameOptions{
  120. Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"},
  121. }
  122. opts.Local = true
  123. err := opts.Complete(tf, NewCmdEnv(tf, streams), []string{"env=prod"})
  124. assert.NoError(t, err)
  125. err = opts.Validate()
  126. assert.NoError(t, err)
  127. err = opts.RunEnv()
  128. assert.NoError(t, err)
  129. if bufErr.Len() > 0 {
  130. t.Errorf("unexpected error: %s", string(bufErr.String()))
  131. }
  132. expectedOut := "replicationcontroller/first-rc\nreplicationcontroller/second-rc\n"
  133. if buf.String() != expectedOut {
  134. t.Errorf("expected out:\n%s\nbut got:\n%s", expectedOut, buf.String())
  135. }
  136. }
  137. func TestSetEnvRemote(t *testing.T) {
  138. inputs := []struct {
  139. name string
  140. object runtime.Object
  141. groupVersion schema.GroupVersion
  142. path string
  143. args []string
  144. }{
  145. {
  146. name: "test extensions.v1beta1 replicaset",
  147. object: &extensionsv1beta1.ReplicaSet{
  148. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  149. Spec: extensionsv1beta1.ReplicaSetSpec{
  150. Template: corev1.PodTemplateSpec{
  151. Spec: corev1.PodSpec{
  152. Containers: []corev1.Container{
  153. {
  154. Name: "nginx",
  155. Image: "nginx",
  156. },
  157. },
  158. },
  159. },
  160. },
  161. },
  162. groupVersion: extensionsv1beta1.SchemeGroupVersion,
  163. path: "/namespaces/test/replicasets/nginx",
  164. args: []string{"replicaset", "nginx", "env=prod"},
  165. },
  166. {
  167. name: "test apps.v1beta2 replicaset",
  168. object: &appsv1beta2.ReplicaSet{
  169. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  170. Spec: appsv1beta2.ReplicaSetSpec{
  171. Template: corev1.PodTemplateSpec{
  172. Spec: corev1.PodSpec{
  173. Containers: []corev1.Container{
  174. {
  175. Name: "nginx",
  176. Image: "nginx",
  177. },
  178. },
  179. },
  180. },
  181. },
  182. },
  183. groupVersion: appsv1beta2.SchemeGroupVersion,
  184. path: "/namespaces/test/replicasets/nginx",
  185. args: []string{"replicaset", "nginx", "env=prod"},
  186. },
  187. {
  188. name: "test appsv1 replicaset",
  189. object: &appsv1.ReplicaSet{
  190. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  191. Spec: appsv1.ReplicaSetSpec{
  192. Template: corev1.PodTemplateSpec{
  193. Spec: corev1.PodSpec{
  194. Containers: []corev1.Container{
  195. {
  196. Name: "nginx",
  197. Image: "nginx",
  198. },
  199. },
  200. },
  201. },
  202. },
  203. },
  204. groupVersion: appsv1.SchemeGroupVersion,
  205. path: "/namespaces/test/replicasets/nginx",
  206. args: []string{"replicaset", "nginx", "env=prod"},
  207. },
  208. {
  209. name: "test extensions.v1beta1 daemonset",
  210. object: &extensionsv1beta1.DaemonSet{
  211. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  212. Spec: extensionsv1beta1.DaemonSetSpec{
  213. Template: corev1.PodTemplateSpec{
  214. Spec: corev1.PodSpec{
  215. Containers: []corev1.Container{
  216. {
  217. Name: "nginx",
  218. Image: "nginx",
  219. },
  220. },
  221. },
  222. },
  223. },
  224. },
  225. groupVersion: extensionsv1beta1.SchemeGroupVersion,
  226. path: "/namespaces/test/daemonsets/nginx",
  227. args: []string{"daemonset", "nginx", "env=prod"},
  228. },
  229. {
  230. name: "test appsv1beta2 daemonset",
  231. object: &appsv1beta2.DaemonSet{
  232. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  233. Spec: appsv1beta2.DaemonSetSpec{
  234. Template: corev1.PodTemplateSpec{
  235. Spec: corev1.PodSpec{
  236. Containers: []corev1.Container{
  237. {
  238. Name: "nginx",
  239. Image: "nginx",
  240. },
  241. },
  242. },
  243. },
  244. },
  245. },
  246. groupVersion: appsv1beta2.SchemeGroupVersion,
  247. path: "/namespaces/test/daemonsets/nginx",
  248. args: []string{"daemonset", "nginx", "env=prod"},
  249. },
  250. {
  251. name: "test appsv1 daemonset",
  252. object: &appsv1.DaemonSet{
  253. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  254. Spec: appsv1.DaemonSetSpec{
  255. Template: corev1.PodTemplateSpec{
  256. Spec: corev1.PodSpec{
  257. Containers: []corev1.Container{
  258. {
  259. Name: "nginx",
  260. Image: "nginx",
  261. },
  262. },
  263. },
  264. },
  265. },
  266. },
  267. groupVersion: appsv1.SchemeGroupVersion,
  268. path: "/namespaces/test/daemonsets/nginx",
  269. args: []string{"daemonset", "nginx", "env=prod"},
  270. },
  271. {
  272. name: "test extensions.v1beta1 deployment",
  273. object: &extensionsv1beta1.Deployment{
  274. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  275. Spec: extensionsv1beta1.DeploymentSpec{
  276. Template: corev1.PodTemplateSpec{
  277. Spec: corev1.PodSpec{
  278. Containers: []corev1.Container{
  279. {
  280. Name: "nginx",
  281. Image: "nginx",
  282. },
  283. },
  284. },
  285. },
  286. },
  287. },
  288. groupVersion: extensionsv1beta1.SchemeGroupVersion,
  289. path: "/namespaces/test/deployments/nginx",
  290. args: []string{"deployment", "nginx", "env=prod"},
  291. },
  292. {
  293. name: "test appsv1beta1 deployment",
  294. object: &appsv1beta1.Deployment{
  295. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  296. Spec: appsv1beta1.DeploymentSpec{
  297. Template: corev1.PodTemplateSpec{
  298. Spec: corev1.PodSpec{
  299. Containers: []corev1.Container{
  300. {
  301. Name: "nginx",
  302. Image: "nginx",
  303. },
  304. },
  305. },
  306. },
  307. },
  308. },
  309. groupVersion: appsv1beta1.SchemeGroupVersion,
  310. path: "/namespaces/test/deployments/nginx",
  311. args: []string{"deployment", "nginx", "env=prod"},
  312. },
  313. {
  314. name: "test appsv1beta2 deployment",
  315. object: &appsv1beta2.Deployment{
  316. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  317. Spec: appsv1beta2.DeploymentSpec{
  318. Template: corev1.PodTemplateSpec{
  319. Spec: corev1.PodSpec{
  320. Containers: []corev1.Container{
  321. {
  322. Name: "nginx",
  323. Image: "nginx",
  324. },
  325. },
  326. },
  327. },
  328. },
  329. },
  330. groupVersion: appsv1beta2.SchemeGroupVersion,
  331. path: "/namespaces/test/deployments/nginx",
  332. args: []string{"deployment", "nginx", "env=prod"},
  333. },
  334. {
  335. name: "test appsv1 deployment",
  336. object: &appsv1.Deployment{
  337. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  338. Spec: appsv1.DeploymentSpec{
  339. Template: corev1.PodTemplateSpec{
  340. Spec: corev1.PodSpec{
  341. Containers: []corev1.Container{
  342. {
  343. Name: "nginx",
  344. Image: "nginx",
  345. },
  346. },
  347. },
  348. },
  349. },
  350. },
  351. groupVersion: appsv1.SchemeGroupVersion,
  352. path: "/namespaces/test/deployments/nginx",
  353. args: []string{"deployment", "nginx", "env=prod"},
  354. },
  355. {
  356. name: "test appsv1beta1 statefulset",
  357. object: &appsv1beta1.StatefulSet{
  358. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  359. Spec: appsv1beta1.StatefulSetSpec{
  360. Template: corev1.PodTemplateSpec{
  361. Spec: corev1.PodSpec{
  362. Containers: []corev1.Container{
  363. {
  364. Name: "nginx",
  365. Image: "nginx",
  366. },
  367. },
  368. },
  369. },
  370. },
  371. },
  372. groupVersion: appsv1beta1.SchemeGroupVersion,
  373. path: "/namespaces/test/statefulsets/nginx",
  374. args: []string{"statefulset", "nginx", "env=prod"},
  375. },
  376. {
  377. name: "test appsv1beta2 statefulset",
  378. object: &appsv1beta2.StatefulSet{
  379. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  380. Spec: appsv1beta2.StatefulSetSpec{
  381. Template: corev1.PodTemplateSpec{
  382. Spec: corev1.PodSpec{
  383. Containers: []corev1.Container{
  384. {
  385. Name: "nginx",
  386. Image: "nginx",
  387. },
  388. },
  389. },
  390. },
  391. },
  392. },
  393. groupVersion: appsv1beta2.SchemeGroupVersion,
  394. path: "/namespaces/test/statefulsets/nginx",
  395. args: []string{"statefulset", "nginx", "env=prod"},
  396. },
  397. {
  398. name: "test appsv1 statefulset",
  399. object: &appsv1.StatefulSet{
  400. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  401. Spec: appsv1.StatefulSetSpec{
  402. Template: corev1.PodTemplateSpec{
  403. Spec: corev1.PodSpec{
  404. Containers: []corev1.Container{
  405. {
  406. Name: "nginx",
  407. Image: "nginx",
  408. },
  409. },
  410. },
  411. },
  412. },
  413. },
  414. groupVersion: appsv1.SchemeGroupVersion,
  415. path: "/namespaces/test/statefulsets/nginx",
  416. args: []string{"statefulset", "nginx", "env=prod"},
  417. },
  418. {
  419. name: "test batchv1 Job",
  420. object: &batchv1.Job{
  421. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  422. Spec: batchv1.JobSpec{
  423. Template: corev1.PodTemplateSpec{
  424. Spec: corev1.PodSpec{
  425. Containers: []corev1.Container{
  426. {
  427. Name: "nginx",
  428. Image: "nginx",
  429. },
  430. },
  431. },
  432. },
  433. },
  434. },
  435. groupVersion: batchv1.SchemeGroupVersion,
  436. path: "/namespaces/test/jobs/nginx",
  437. args: []string{"job", "nginx", "env=prod"},
  438. },
  439. {
  440. name: "test corev1 replication controller",
  441. object: &corev1.ReplicationController{
  442. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  443. Spec: corev1.ReplicationControllerSpec{
  444. Template: &corev1.PodTemplateSpec{
  445. Spec: corev1.PodSpec{
  446. Containers: []corev1.Container{
  447. {
  448. Name: "nginx",
  449. Image: "nginx",
  450. },
  451. },
  452. },
  453. },
  454. },
  455. },
  456. groupVersion: corev1.SchemeGroupVersion,
  457. path: "/namespaces/test/replicationcontrollers/nginx",
  458. args: []string{"replicationcontroller", "nginx", "env=prod"},
  459. },
  460. }
  461. for _, input := range inputs {
  462. t.Run(input.name, func(t *testing.T) {
  463. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  464. defer tf.Cleanup()
  465. tf.Client = &fake.RESTClient{
  466. GroupVersion: input.groupVersion,
  467. NegotiatedSerializer: scheme.Codecs.WithoutConversion(),
  468. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  469. switch p, m := req.URL.Path, req.Method; {
  470. case p == input.path && m == http.MethodGet:
  471. return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(input.object)}, nil
  472. case p == input.path && m == http.MethodPatch:
  473. stream, err := req.GetBody()
  474. if err != nil {
  475. return nil, err
  476. }
  477. bytes, err := ioutil.ReadAll(stream)
  478. if err != nil {
  479. return nil, err
  480. }
  481. assert.Contains(t, string(bytes), `"value":`+`"`+"prod"+`"`, fmt.Sprintf("env not updated for %#v", input.object))
  482. return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(input.object)}, nil
  483. default:
  484. t.Errorf("%s: unexpected request: %s %#v\n%#v", "image", req.Method, req.URL, req)
  485. return nil, fmt.Errorf("unexpected request")
  486. }
  487. }),
  488. }
  489. outputFormat := "yaml"
  490. streams := genericclioptions.NewTestIOStreamsDiscard()
  491. opts := NewEnvOptions(streams)
  492. opts.PrintFlags = genericclioptions.NewPrintFlags("").WithDefaultOutput(outputFormat).WithTypeSetter(scheme.Scheme)
  493. opts.Local = false
  494. opts.IOStreams = streams
  495. err := opts.Complete(tf, NewCmdEnv(tf, streams), input.args)
  496. assert.NoError(t, err)
  497. err = opts.RunEnv()
  498. assert.NoError(t, err)
  499. })
  500. }
  501. }
  502. func TestSetEnvFromResource(t *testing.T) {
  503. mockConfigMap := &corev1.ConfigMap{
  504. ObjectMeta: metav1.ObjectMeta{Name: "testconfigmap"},
  505. Data: map[string]string{
  506. "env": "prod",
  507. "test-key": "testValue",
  508. "test-key-two": "testValueTwo",
  509. },
  510. }
  511. mockSecret := &corev1.Secret{
  512. ObjectMeta: metav1.ObjectMeta{Name: "testsecret"},
  513. Data: map[string][]byte{
  514. "env": []byte("prod"),
  515. "test-key": []byte("testValue"),
  516. "test-key-two": []byte("testValueTwo"),
  517. },
  518. }
  519. inputs := []struct {
  520. name string
  521. args []string
  522. from string
  523. keys []string
  524. assertIncludes []string
  525. assertExcludes []string
  526. }{
  527. {
  528. name: "test from configmap",
  529. args: []string{"deployment", "nginx"},
  530. from: "configmap/testconfigmap",
  531. keys: []string{},
  532. assertIncludes: []string{
  533. `{"name":"ENV","valueFrom":{"configMapKeyRef":{"key":"env","name":"testconfigmap"}}}`,
  534. `{"name":"TEST_KEY","valueFrom":{"configMapKeyRef":{"key":"test-key","name":"testconfigmap"}}}`,
  535. `{"name":"TEST_KEY_TWO","valueFrom":{"configMapKeyRef":{"key":"test-key-two","name":"testconfigmap"}}}`,
  536. },
  537. assertExcludes: []string{},
  538. },
  539. {
  540. name: "test from secret",
  541. args: []string{"deployment", "nginx"},
  542. from: "secret/testsecret",
  543. keys: []string{},
  544. assertIncludes: []string{
  545. `{"name":"ENV","valueFrom":{"secretKeyRef":{"key":"env","name":"testsecret"}}}`,
  546. `{"name":"TEST_KEY","valueFrom":{"secretKeyRef":{"key":"test-key","name":"testsecret"}}}`,
  547. `{"name":"TEST_KEY_TWO","valueFrom":{"secretKeyRef":{"key":"test-key-two","name":"testsecret"}}}`,
  548. },
  549. assertExcludes: []string{},
  550. },
  551. {
  552. name: "test from configmap with keys",
  553. args: []string{"deployment", "nginx"},
  554. from: "configmap/testconfigmap",
  555. keys: []string{"env", "test-key-two"},
  556. assertIncludes: []string{
  557. `{"name":"ENV","valueFrom":{"configMapKeyRef":{"key":"env","name":"testconfigmap"}}}`,
  558. `{"name":"TEST_KEY_TWO","valueFrom":{"configMapKeyRef":{"key":"test-key-two","name":"testconfigmap"}}}`,
  559. },
  560. assertExcludes: []string{`{"name":"TEST_KEY","valueFrom":{"configMapKeyRef":{"key":"test-key","name":"testconfigmap"}}}`},
  561. },
  562. {
  563. name: "test from secret with keys",
  564. args: []string{"deployment", "nginx"},
  565. from: "secret/testsecret",
  566. keys: []string{"env", "test-key-two"},
  567. assertIncludes: []string{
  568. `{"name":"ENV","valueFrom":{"secretKeyRef":{"key":"env","name":"testsecret"}}}`,
  569. `{"name":"TEST_KEY_TWO","valueFrom":{"secretKeyRef":{"key":"test-key-two","name":"testsecret"}}}`,
  570. },
  571. assertExcludes: []string{`{"name":"TEST_KEY","valueFrom":{"secretKeyRef":{"key":"test-key","name":"testsecret"}}}`},
  572. },
  573. }
  574. for _, input := range inputs {
  575. mockDeployment := &appsv1.Deployment{
  576. ObjectMeta: metav1.ObjectMeta{Name: "nginx"},
  577. Spec: appsv1.DeploymentSpec{
  578. Template: corev1.PodTemplateSpec{
  579. Spec: corev1.PodSpec{
  580. Containers: []corev1.Container{
  581. {
  582. Name: "nginx",
  583. Image: "nginx",
  584. },
  585. },
  586. },
  587. },
  588. },
  589. }
  590. t.Run(input.name, func(t *testing.T) {
  591. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  592. defer tf.Cleanup()
  593. tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
  594. tf.Client = &fake.RESTClient{
  595. GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
  596. NegotiatedSerializer: scheme.Codecs.WithoutConversion(),
  597. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  598. switch p, m := req.URL.Path, req.Method; {
  599. case p == "/namespaces/test/configmaps/testconfigmap" && m == http.MethodGet:
  600. return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(mockConfigMap)}, nil
  601. case p == "/namespaces/test/secrets/testsecret" && m == http.MethodGet:
  602. return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(mockSecret)}, nil
  603. case p == "/namespaces/test/deployments/nginx" && m == http.MethodGet:
  604. return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(mockDeployment)}, nil
  605. case p == "/namespaces/test/deployments/nginx" && m == http.MethodPatch:
  606. stream, err := req.GetBody()
  607. if err != nil {
  608. return nil, err
  609. }
  610. bytes, err := ioutil.ReadAll(stream)
  611. if err != nil {
  612. return nil, err
  613. }
  614. for _, include := range input.assertIncludes {
  615. assert.Contains(t, string(bytes), include)
  616. }
  617. for _, exclude := range input.assertExcludes {
  618. assert.NotContains(t, string(bytes), exclude)
  619. }
  620. return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: objBody(mockDeployment)}, nil
  621. default:
  622. t.Errorf("%s: unexpected request: %#v\n%#v", input.name, req.URL, req)
  623. return nil, nil
  624. }
  625. }),
  626. }
  627. outputFormat := "yaml"
  628. streams := genericclioptions.NewTestIOStreamsDiscard()
  629. opts := NewEnvOptions(streams)
  630. opts.From = input.from
  631. opts.Keys = input.keys
  632. opts.PrintFlags = genericclioptions.NewPrintFlags("").WithDefaultOutput(outputFormat).WithTypeSetter(scheme.Scheme)
  633. opts.Local = false
  634. opts.IOStreams = streams
  635. err := opts.Complete(tf, NewCmdEnv(tf, streams), input.args)
  636. assert.NoError(t, err)
  637. err = opts.RunEnv()
  638. assert.NoError(t, err)
  639. })
  640. }
  641. }