get_test.go 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654
  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 get
  14. import (
  15. "bytes"
  16. encjson "encoding/json"
  17. "fmt"
  18. "io"
  19. "io/ioutil"
  20. "net/http"
  21. "path/filepath"
  22. "reflect"
  23. "strings"
  24. "testing"
  25. appsv1 "k8s.io/api/apps/v1"
  26. autoscalingv1 "k8s.io/api/autoscaling/v1"
  27. batchv1 "k8s.io/api/batch/v1"
  28. batchv1beta1 "k8s.io/api/batch/v1beta1"
  29. corev1 "k8s.io/api/core/v1"
  30. extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
  31. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  32. metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
  33. "k8s.io/apimachinery/pkg/runtime"
  34. "k8s.io/apimachinery/pkg/runtime/schema"
  35. "k8s.io/apimachinery/pkg/runtime/serializer/json"
  36. "k8s.io/apimachinery/pkg/runtime/serializer/streaming"
  37. "k8s.io/apimachinery/pkg/util/diff"
  38. "k8s.io/apimachinery/pkg/watch"
  39. "k8s.io/cli-runtime/pkg/genericclioptions"
  40. "k8s.io/cli-runtime/pkg/resource"
  41. restclient "k8s.io/client-go/rest"
  42. "k8s.io/client-go/rest/fake"
  43. restclientwatch "k8s.io/client-go/rest/watch"
  44. "k8s.io/kube-openapi/pkg/util/proto"
  45. cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
  46. "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
  47. openapitesting "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/testing"
  48. "k8s.io/kubernetes/pkg/kubectl/scheme"
  49. )
  50. var (
  51. openapiSchemaPath = filepath.Join("..", "..", "..", "..", "api", "openapi-spec", "swagger.json")
  52. grace = int64(30)
  53. enableServiceLinks = corev1.DefaultEnableServiceLinks
  54. )
  55. func testComponentStatusData() *corev1.ComponentStatusList {
  56. good := corev1.ComponentStatus{
  57. Conditions: []corev1.ComponentCondition{
  58. {Type: corev1.ComponentHealthy, Status: corev1.ConditionTrue, Message: "ok"},
  59. },
  60. ObjectMeta: metav1.ObjectMeta{Name: "servergood"},
  61. }
  62. bad := corev1.ComponentStatus{
  63. Conditions: []corev1.ComponentCondition{
  64. {Type: corev1.ComponentHealthy, Status: corev1.ConditionFalse, Message: "", Error: "bad status: 500"},
  65. },
  66. ObjectMeta: metav1.ObjectMeta{Name: "serverbad"},
  67. }
  68. unknown := corev1.ComponentStatus{
  69. Conditions: []corev1.ComponentCondition{
  70. {Type: corev1.ComponentHealthy, Status: corev1.ConditionUnknown, Message: "", Error: "fizzbuzz error"},
  71. },
  72. ObjectMeta: metav1.ObjectMeta{Name: "serverunknown"},
  73. }
  74. return &corev1.ComponentStatusList{
  75. Items: []corev1.ComponentStatus{good, bad, unknown},
  76. }
  77. }
  78. // Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
  79. func TestGetUnknownSchemaObject(t *testing.T) {
  80. t.Skip("This test is completely broken. The first thing it does is add the object to the scheme!")
  81. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  82. defer tf.Cleanup()
  83. _, _, codec := cmdtesting.NewExternalScheme()
  84. tf.OpenAPISchemaFunc = openapitesting.CreateOpenAPISchemaFunc(openapiSchemaPath)
  85. obj := &cmdtesting.ExternalType{
  86. Kind: "Type",
  87. APIVersion: "apitest/unlikelyversion",
  88. Name: "foo",
  89. }
  90. tf.UnstructuredClient = &fake.RESTClient{
  91. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  92. Resp: &http.Response{
  93. StatusCode: 200, Header: cmdtesting.DefaultHeader(),
  94. Body: cmdtesting.ObjBody(codec, obj),
  95. },
  96. }
  97. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  98. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  99. cmd := NewCmdGet("kubectl", tf, streams)
  100. cmd.SetOutput(buf)
  101. cmd.Run(cmd, []string{"type", "foo"})
  102. expected := []runtime.Object{cmdtesting.NewInternalType("", "", "foo")}
  103. actual := []runtime.Object{}
  104. if len(actual) != len(expected) {
  105. t.Fatalf("expected: %#v, but actual: %#v", expected, actual)
  106. }
  107. t.Logf("actual: %#v", actual[0])
  108. for i, obj := range actual {
  109. expectedJSON := runtime.EncodeOrDie(codec, expected[i])
  110. expectedMap := map[string]interface{}{}
  111. if err := encjson.Unmarshal([]byte(expectedJSON), &expectedMap); err != nil {
  112. t.Fatal(err)
  113. }
  114. actualJSON := runtime.EncodeOrDie(codec, obj)
  115. actualMap := map[string]interface{}{}
  116. if err := encjson.Unmarshal([]byte(actualJSON), &actualMap); err != nil {
  117. t.Fatal(err)
  118. }
  119. if !reflect.DeepEqual(expectedMap, actualMap) {
  120. t.Errorf("expectedMap: %#v, but actualMap: %#v", expectedMap, actualMap)
  121. }
  122. }
  123. }
  124. // Verifies that schemas that are not in the master tree of Kubernetes can be retrieved via Get.
  125. func TestGetSchemaObject(t *testing.T) {
  126. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  127. defer tf.Cleanup()
  128. codec := scheme.Codecs.LegacyCodec(corev1.SchemeGroupVersion)
  129. t.Logf("%v", string(runtime.EncodeOrDie(codec, &corev1.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})))
  130. tf.UnstructuredClient = &fake.RESTClient{
  131. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  132. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})},
  133. }
  134. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  135. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  136. cmd := NewCmdGet("kubectl", tf, streams)
  137. cmd.Run(cmd, []string{"replicationcontrollers", "foo"})
  138. if !strings.Contains(buf.String(), "foo") {
  139. t.Errorf("unexpected output: %s", buf.String())
  140. }
  141. }
  142. func TestGetObjectsWithOpenAPIOutputFormatPresent(t *testing.T) {
  143. pods, _, _ := cmdtesting.TestData()
  144. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  145. defer tf.Cleanup()
  146. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  147. // overide the openAPISchema function to return custom output
  148. // for Pod type.
  149. tf.OpenAPISchemaFunc = testOpenAPISchemaData
  150. tf.UnstructuredClient = &fake.RESTClient{
  151. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  152. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
  153. }
  154. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  155. cmd := NewCmdGet("kubectl", tf, streams)
  156. cmd.SetOutput(buf)
  157. cmd.Flags().Set(useOpenAPIPrintColumnFlagLabel, "true")
  158. cmd.Run(cmd, []string{"pods", "foo"})
  159. expected := `NAME RSRC
  160. foo 10
  161. `
  162. if e, a := expected, buf.String(); e != a {
  163. t.Errorf("expected\n%v\ngot\n%v", e, a)
  164. }
  165. }
  166. type FakeResources struct {
  167. resources map[schema.GroupVersionKind]proto.Schema
  168. }
  169. func (f FakeResources) LookupResource(s schema.GroupVersionKind) proto.Schema {
  170. return f.resources[s]
  171. }
  172. var _ openapi.Resources = &FakeResources{}
  173. func testOpenAPISchemaData() (openapi.Resources, error) {
  174. return &FakeResources{
  175. resources: map[schema.GroupVersionKind]proto.Schema{
  176. {
  177. Version: "v1",
  178. Kind: "Pod",
  179. }: &proto.Primitive{
  180. BaseSchema: proto.BaseSchema{
  181. Extensions: map[string]interface{}{
  182. "x-kubernetes-print-columns": "custom-columns=NAME:.metadata.name,RSRC:.metadata.resourceVersion",
  183. },
  184. },
  185. },
  186. },
  187. }, nil
  188. }
  189. func TestGetObjects(t *testing.T) {
  190. pods, _, _ := cmdtesting.TestData()
  191. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  192. defer tf.Cleanup()
  193. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  194. tf.UnstructuredClient = &fake.RESTClient{
  195. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  196. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
  197. }
  198. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  199. cmd := NewCmdGet("kubectl", tf, streams)
  200. cmd.SetOutput(buf)
  201. cmd.Run(cmd, []string{"pods", "foo"})
  202. expected := `NAME READY STATUS RESTARTS AGE
  203. foo 0/0 0 <unknown>
  204. `
  205. if e, a := expected, buf.String(); e != a {
  206. t.Errorf("expected\n%v\ngot\n%v", e, a)
  207. }
  208. }
  209. func TestGetObjectsShowKind(t *testing.T) {
  210. pods, _, _ := cmdtesting.TestData()
  211. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  212. defer tf.Cleanup()
  213. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  214. tf.UnstructuredClient = &fake.RESTClient{
  215. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  216. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
  217. }
  218. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  219. cmd := NewCmdGet("kubectl", tf, streams)
  220. cmd.SetOutput(buf)
  221. cmd.Flags().Set("show-kind", "true")
  222. cmd.Run(cmd, []string{"pods", "foo"})
  223. expected := `NAME READY STATUS RESTARTS AGE
  224. pod/foo 0/0 0 <unknown>
  225. `
  226. if e, a := expected, buf.String(); e != a {
  227. t.Errorf("expected\n%v\ngot\n%v", e, a)
  228. }
  229. }
  230. func TestGetMultipleResourceTypesShowKinds(t *testing.T) {
  231. pods, svcs, _ := cmdtesting.TestData()
  232. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  233. defer tf.Cleanup()
  234. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  235. tf.UnstructuredClient = &fake.RESTClient{
  236. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  237. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  238. switch p, m := req.URL.Path, req.Method; {
  239. case p == "/namespaces/test/pods" && m == "GET":
  240. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
  241. case p == "/namespaces/test/replicationcontrollers" && m == "GET":
  242. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &corev1.ReplicationControllerList{})}, nil
  243. case p == "/namespaces/test/services" && m == "GET":
  244. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svcs)}, nil
  245. case p == "/namespaces/test/statefulsets" && m == "GET":
  246. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &appsv1.StatefulSetList{})}, nil
  247. case p == "/namespaces/test/horizontalpodautoscalers" && m == "GET":
  248. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &autoscalingv1.HorizontalPodAutoscalerList{})}, nil
  249. case p == "/namespaces/test/jobs" && m == "GET":
  250. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &batchv1.JobList{})}, nil
  251. case p == "/namespaces/test/cronjobs" && m == "GET":
  252. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &batchv1beta1.CronJobList{})}, nil
  253. case p == "/namespaces/test/daemonsets" && m == "GET":
  254. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &appsv1.DaemonSetList{})}, nil
  255. case p == "/namespaces/test/deployments" && m == "GET":
  256. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &extensionsv1beta1.DeploymentList{})}, nil
  257. case p == "/namespaces/test/replicasets" && m == "GET":
  258. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &extensionsv1beta1.ReplicaSetList{})}, nil
  259. default:
  260. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  261. return nil, nil
  262. }
  263. }),
  264. }
  265. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  266. cmd := NewCmdGet("kubectl", tf, streams)
  267. cmd.SetOutput(buf)
  268. cmd.Run(cmd, []string{"all"})
  269. expected := `NAME READY STATUS RESTARTS AGE
  270. pod/foo 0/0 0 <unknown>
  271. pod/bar 0/0 0 <unknown>
  272. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  273. service/baz ClusterIP <none> <none> <none> <unknown>
  274. `
  275. if e, a := expected, buf.String(); e != a {
  276. t.Errorf("expected\n%v\ngot\n%v", e, a)
  277. }
  278. }
  279. func TestGetObjectsShowLabels(t *testing.T) {
  280. pods, _, _ := cmdtesting.TestData()
  281. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  282. defer tf.Cleanup()
  283. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  284. tf.UnstructuredClient = &fake.RESTClient{
  285. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  286. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
  287. }
  288. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  289. cmd := NewCmdGet("kubectl", tf, streams)
  290. cmd.SetOutput(buf)
  291. cmd.Flags().Set("show-labels", "true")
  292. cmd.Run(cmd, []string{"pods", "foo"})
  293. expected := `NAME READY STATUS RESTARTS AGE LABELS
  294. foo 0/0 0 <unknown> <none>
  295. `
  296. if e, a := expected, buf.String(); e != a {
  297. t.Errorf("expected\n%v\ngot\n%v", e, a)
  298. }
  299. }
  300. func TestGetEmptyTable(t *testing.T) {
  301. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  302. defer tf.Cleanup()
  303. emptyTable := ioutil.NopCloser(bytes.NewBufferString(`{
  304. "kind":"Table",
  305. "apiVersion":"meta.k8s.io/v1beta1",
  306. "metadata":{
  307. "selfLink":"/api/v1/namespaces/default/pods",
  308. "resourceVersion":"346"
  309. },
  310. "columnDefinitions":[
  311. {"name":"Name","type":"string","format":"name","description":"the name","priority":0}
  312. ],
  313. "rows":[]
  314. }`))
  315. tf.UnstructuredClient = &fake.RESTClient{
  316. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  317. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: emptyTable},
  318. }
  319. streams, _, buf, errbuf := genericclioptions.NewTestIOStreams()
  320. cmd := NewCmdGet("kubectl", tf, streams)
  321. cmd.SetOutput(buf)
  322. cmd.Run(cmd, []string{"pods"})
  323. expected := ``
  324. if e, a := expected, buf.String(); e != a {
  325. t.Errorf("expected\n%v\ngot\n%v", e, a)
  326. }
  327. expectedErr := `No resources found.
  328. `
  329. if e, a := expectedErr, errbuf.String(); e != a {
  330. t.Errorf("expectedErr\n%v\ngot\n%v", e, a)
  331. }
  332. }
  333. func TestGetObjectIgnoreNotFound(t *testing.T) {
  334. cmdtesting.InitTestErrorHandler(t)
  335. ns := &corev1.NamespaceList{
  336. ListMeta: metav1.ListMeta{
  337. ResourceVersion: "1",
  338. },
  339. Items: []corev1.Namespace{
  340. {
  341. ObjectMeta: metav1.ObjectMeta{Name: "testns", Namespace: "test", ResourceVersion: "11"},
  342. Spec: corev1.NamespaceSpec{},
  343. },
  344. },
  345. }
  346. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  347. defer tf.Cleanup()
  348. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  349. tf.UnstructuredClient = &fake.RESTClient{
  350. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  351. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  352. switch p, m := req.URL.Path, req.Method; {
  353. case p == "/namespaces/test/pods/nonexistentpod" && m == "GET":
  354. return &http.Response{StatusCode: 404, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.StringBody("")}, nil
  355. case p == "/api/v1/namespaces/test" && m == "GET":
  356. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &ns.Items[0])}, nil
  357. default:
  358. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  359. return nil, nil
  360. }
  361. }),
  362. }
  363. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  364. cmd := NewCmdGet("kubectl", tf, streams)
  365. cmd.SetOutput(buf)
  366. cmd.Flags().Set("ignore-not-found", "true")
  367. cmd.Flags().Set("output", "yaml")
  368. cmd.Run(cmd, []string{"pods", "nonexistentpod"})
  369. if buf.String() != "" {
  370. t.Errorf("unexpected output: %s", buf.String())
  371. }
  372. }
  373. func TestGetSortedObjects(t *testing.T) {
  374. pods := &corev1.PodList{
  375. ListMeta: metav1.ListMeta{
  376. ResourceVersion: "15",
  377. },
  378. Items: []corev1.Pod{
  379. {
  380. ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: "test", ResourceVersion: "10"},
  381. Spec: corev1.PodSpec{
  382. RestartPolicy: corev1.RestartPolicyAlways,
  383. DNSPolicy: corev1.DNSClusterFirst,
  384. TerminationGracePeriodSeconds: &grace,
  385. SecurityContext: &corev1.PodSecurityContext{},
  386. EnableServiceLinks: &enableServiceLinks,
  387. },
  388. },
  389. {
  390. ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "11"},
  391. Spec: corev1.PodSpec{
  392. RestartPolicy: corev1.RestartPolicyAlways,
  393. DNSPolicy: corev1.DNSClusterFirst,
  394. TerminationGracePeriodSeconds: &grace,
  395. SecurityContext: &corev1.PodSecurityContext{},
  396. EnableServiceLinks: &enableServiceLinks,
  397. },
  398. },
  399. {
  400. ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "9"},
  401. Spec: corev1.PodSpec{
  402. RestartPolicy: corev1.RestartPolicyAlways,
  403. DNSPolicy: corev1.DNSClusterFirst,
  404. TerminationGracePeriodSeconds: &grace,
  405. SecurityContext: &corev1.PodSecurityContext{},
  406. EnableServiceLinks: &enableServiceLinks,
  407. },
  408. },
  409. },
  410. }
  411. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  412. defer tf.Cleanup()
  413. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  414. tf.UnstructuredClient = &fake.RESTClient{
  415. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  416. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
  417. }
  418. tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &corev1.SchemeGroupVersion}}
  419. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  420. cmd := NewCmdGet("kubectl", tf, streams)
  421. cmd.SetOutput(buf)
  422. // sorting with metedata.name
  423. cmd.Flags().Set("sort-by", ".metadata.name")
  424. cmd.Run(cmd, []string{"pods"})
  425. expected := `NAME READY STATUS RESTARTS AGE
  426. a 0/0 0 <unknown>
  427. b 0/0 0 <unknown>
  428. c 0/0 0 <unknown>
  429. `
  430. if e, a := expected, buf.String(); e != a {
  431. t.Errorf("expected\n%v\ngot\n%v", e, a)
  432. }
  433. }
  434. func TestGetSortedObjectsUnstructuredTable(t *testing.T) {
  435. unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(sortTestTableData()[0])
  436. if err != nil {
  437. t.Fatal(err)
  438. }
  439. unstructuredBytes, err := encjson.MarshalIndent(unstructuredMap, "", " ")
  440. if err != nil {
  441. t.Fatal(err)
  442. }
  443. // t.Log(string(unstructuredBytes))
  444. body := ioutil.NopCloser(bytes.NewReader(unstructuredBytes))
  445. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  446. defer tf.Cleanup()
  447. tf.UnstructuredClient = &fake.RESTClient{
  448. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  449. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body},
  450. }
  451. tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &corev1.SchemeGroupVersion}}
  452. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  453. cmd := NewCmdGet("kubectl", tf, streams)
  454. cmd.SetOutput(buf)
  455. // sorting with metedata.name
  456. cmd.Flags().Set("sort-by", ".metadata.name")
  457. cmd.Run(cmd, []string{"pods"})
  458. expected := `NAME CUSTOM
  459. a custom-a
  460. b custom-b
  461. c custom-c
  462. `
  463. if e, a := expected, buf.String(); e != a {
  464. t.Errorf("expected\n%v\ngot\n%v", e, a)
  465. }
  466. }
  467. func sortTestData() []runtime.Object {
  468. return []runtime.Object{
  469. &corev1.Pod{
  470. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  471. ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: "test", ResourceVersion: "10"},
  472. Spec: corev1.PodSpec{
  473. RestartPolicy: corev1.RestartPolicyAlways,
  474. DNSPolicy: corev1.DNSClusterFirst,
  475. TerminationGracePeriodSeconds: &grace,
  476. SecurityContext: &corev1.PodSecurityContext{},
  477. EnableServiceLinks: &enableServiceLinks,
  478. },
  479. },
  480. &corev1.Pod{
  481. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  482. ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "11"},
  483. Spec: corev1.PodSpec{
  484. RestartPolicy: corev1.RestartPolicyAlways,
  485. DNSPolicy: corev1.DNSClusterFirst,
  486. TerminationGracePeriodSeconds: &grace,
  487. SecurityContext: &corev1.PodSecurityContext{},
  488. EnableServiceLinks: &enableServiceLinks,
  489. },
  490. },
  491. &corev1.Pod{
  492. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  493. ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "9"},
  494. Spec: corev1.PodSpec{
  495. RestartPolicy: corev1.RestartPolicyAlways,
  496. DNSPolicy: corev1.DNSClusterFirst,
  497. TerminationGracePeriodSeconds: &grace,
  498. SecurityContext: &corev1.PodSecurityContext{},
  499. EnableServiceLinks: &enableServiceLinks,
  500. },
  501. },
  502. }
  503. }
  504. func sortTestTableData() []runtime.Object {
  505. return []runtime.Object{
  506. &metav1beta1.Table{
  507. TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1beta1", Kind: "Table"},
  508. ColumnDefinitions: []metav1beta1.TableColumnDefinition{
  509. {Name: "NAME", Type: "string", Format: "name"},
  510. {Name: "CUSTOM", Type: "string", Format: ""},
  511. },
  512. Rows: []metav1beta1.TableRow{
  513. {
  514. Cells: []interface{}{"c", "custom-c"},
  515. Object: runtime.RawExtension{
  516. Object: &corev1.Pod{
  517. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  518. ObjectMeta: metav1.ObjectMeta{Name: "c", Namespace: "test", ResourceVersion: "10"},
  519. Spec: corev1.PodSpec{
  520. RestartPolicy: corev1.RestartPolicyAlways,
  521. DNSPolicy: corev1.DNSClusterFirst,
  522. TerminationGracePeriodSeconds: &grace,
  523. SecurityContext: &corev1.PodSecurityContext{},
  524. EnableServiceLinks: &enableServiceLinks,
  525. },
  526. },
  527. },
  528. },
  529. {
  530. Cells: []interface{}{"b", "custom-b"},
  531. Object: runtime.RawExtension{
  532. Object: &corev1.Pod{
  533. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  534. ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "11"},
  535. Spec: corev1.PodSpec{
  536. RestartPolicy: corev1.RestartPolicyAlways,
  537. DNSPolicy: corev1.DNSClusterFirst,
  538. TerminationGracePeriodSeconds: &grace,
  539. SecurityContext: &corev1.PodSecurityContext{},
  540. EnableServiceLinks: &enableServiceLinks,
  541. },
  542. },
  543. },
  544. },
  545. {
  546. Cells: []interface{}{"a", "custom-a"},
  547. Object: runtime.RawExtension{
  548. Object: &corev1.Pod{
  549. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  550. ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "9"},
  551. Spec: corev1.PodSpec{
  552. RestartPolicy: corev1.RestartPolicyAlways,
  553. DNSPolicy: corev1.DNSClusterFirst,
  554. TerminationGracePeriodSeconds: &grace,
  555. SecurityContext: &corev1.PodSecurityContext{},
  556. EnableServiceLinks: &enableServiceLinks,
  557. },
  558. },
  559. },
  560. },
  561. },
  562. },
  563. }
  564. }
  565. func TestRuntimeSorter(t *testing.T) {
  566. tests := []struct {
  567. name string
  568. field string
  569. objs []runtime.Object
  570. op func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error
  571. expect string
  572. expectError string
  573. }{
  574. {
  575. name: "ensure sorter works with an empty object list",
  576. field: "metadata.name",
  577. objs: []runtime.Object{},
  578. op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error {
  579. return nil
  580. },
  581. expect: "",
  582. },
  583. {
  584. name: "ensure sorter returns original position",
  585. field: "metadata.name",
  586. objs: sortTestData(),
  587. op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error {
  588. for idx := range objs {
  589. p := sorter.OriginalPosition(idx)
  590. fmt.Fprintf(out, "%v,", p)
  591. }
  592. return nil
  593. },
  594. expect: "2,1,0,",
  595. },
  596. {
  597. name: "ensure sorter handles table object position",
  598. field: "metadata.name",
  599. objs: sortTestTableData(),
  600. op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error {
  601. for idx := range objs {
  602. p := sorter.OriginalPosition(idx)
  603. fmt.Fprintf(out, "%v,", p)
  604. }
  605. return nil
  606. },
  607. expect: "0,",
  608. },
  609. {
  610. name: "ensure sorter sorts table objects",
  611. field: "metadata.name",
  612. objs: sortTestData(),
  613. op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error {
  614. for _, o := range objs {
  615. fmt.Fprintf(out, "%s,", o.(*corev1.Pod).Name)
  616. }
  617. return nil
  618. },
  619. expect: "a,b,c,",
  620. },
  621. {
  622. name: "ensure sorter rejects mixed Table + non-Table object lists",
  623. field: "metadata.name",
  624. objs: append(sortTestData(), sortTestTableData()...),
  625. op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error { return nil },
  626. expectError: "sorting is not supported on mixed Table",
  627. },
  628. {
  629. name: "ensure sorter errors out on invalid jsonpath",
  630. field: "metadata.unknown",
  631. objs: sortTestData(),
  632. op: func(sorter *RuntimeSorter, objs []runtime.Object, out io.Writer) error { return nil },
  633. expectError: "couldn't find any field with path",
  634. },
  635. }
  636. for _, tc := range tests {
  637. t.Run(tc.name, func(t *testing.T) {
  638. sorter := NewRuntimeSorter(tc.objs, tc.field)
  639. if err := sorter.Sort(); err != nil {
  640. if len(tc.expectError) > 0 && strings.Contains(err.Error(), tc.expectError) {
  641. return
  642. }
  643. if len(tc.expectError) > 0 {
  644. t.Fatalf("unexpected error: expecting %s, but got %s", tc.expectError, err)
  645. }
  646. t.Fatalf("unexpected error: %v", err)
  647. }
  648. out := bytes.NewBuffer([]byte{})
  649. err := tc.op(sorter, tc.objs, out)
  650. if err != nil {
  651. t.Fatalf("unexpected error: %v", err)
  652. }
  653. if tc.expect != out.String() {
  654. t.Fatalf("unexpected output: expecting %s, but got %s", tc.expect, out.String())
  655. }
  656. })
  657. }
  658. }
  659. func TestGetObjectsIdentifiedByFile(t *testing.T) {
  660. pods, _, _ := cmdtesting.TestData()
  661. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  662. defer tf.Cleanup()
  663. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  664. tf.UnstructuredClient = &fake.RESTClient{
  665. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  666. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods.Items[0])},
  667. }
  668. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  669. cmd := NewCmdGet("kubectl", tf, streams)
  670. cmd.SetOutput(buf)
  671. cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml")
  672. cmd.Run(cmd, []string{})
  673. expected := `NAME READY STATUS RESTARTS AGE
  674. foo 0/0 0 <unknown>
  675. `
  676. if e, a := expected, buf.String(); e != a {
  677. t.Errorf("expected\n%v\ngot\n%v", e, a)
  678. }
  679. }
  680. func TestGetListObjects(t *testing.T) {
  681. pods, _, _ := cmdtesting.TestData()
  682. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  683. defer tf.Cleanup()
  684. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  685. tf.UnstructuredClient = &fake.RESTClient{
  686. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  687. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)},
  688. }
  689. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  690. cmd := NewCmdGet("kubectl", tf, streams)
  691. cmd.SetOutput(buf)
  692. cmd.Run(cmd, []string{"pods"})
  693. expected := `NAME READY STATUS RESTARTS AGE
  694. foo 0/0 0 <unknown>
  695. bar 0/0 0 <unknown>
  696. `
  697. if e, a := expected, buf.String(); e != a {
  698. t.Errorf("expected\n%v\ngot\n%v", e, a)
  699. }
  700. }
  701. func TestGetListComponentStatus(t *testing.T) {
  702. statuses := testComponentStatusData()
  703. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  704. defer tf.Cleanup()
  705. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  706. tf.UnstructuredClient = &fake.RESTClient{
  707. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  708. Resp: &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, statuses)},
  709. }
  710. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  711. cmd := NewCmdGet("kubectl", tf, streams)
  712. cmd.SetOutput(buf)
  713. cmd.Run(cmd, []string{"componentstatuses"})
  714. expected := `NAME STATUS MESSAGE ERROR
  715. servergood Healthy ok
  716. serverbad Unhealthy bad status: 500
  717. serverunknown Unhealthy fizzbuzz error
  718. `
  719. if e, a := expected, buf.String(); e != a {
  720. t.Errorf("expected\n%v\ngot\n%v", e, a)
  721. }
  722. }
  723. func TestGetMixedGenericObjects(t *testing.T) {
  724. cmdtesting.InitTestErrorHandler(t)
  725. // ensure that a runtime.Object without
  726. // an ObjectMeta field is handled properly
  727. structuredObj := &metav1.Status{
  728. TypeMeta: metav1.TypeMeta{
  729. Kind: "Status",
  730. APIVersion: "v1",
  731. },
  732. Status: "Success",
  733. Message: "",
  734. Reason: "",
  735. Code: 0,
  736. }
  737. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  738. defer tf.Cleanup()
  739. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  740. tf.UnstructuredClient = &fake.RESTClient{
  741. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  742. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  743. switch req.URL.Path {
  744. case "/namespaces/test/pods":
  745. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, structuredObj)}, nil
  746. default:
  747. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  748. return nil, nil
  749. }
  750. }),
  751. }
  752. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  753. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  754. cmd := NewCmdGet("kubectl", tf, streams)
  755. cmd.SetOutput(buf)
  756. cmd.Flags().Set("output", "json")
  757. cmd.Run(cmd, []string{"pods"})
  758. expected := `{
  759. "apiVersion": "v1",
  760. "items": [
  761. {
  762. "apiVersion": "v1",
  763. "kind": "Status",
  764. "metadata": {},
  765. "status": "Success"
  766. }
  767. ],
  768. "kind": "List",
  769. "metadata": {
  770. "resourceVersion": "",
  771. "selfLink": ""
  772. }
  773. }
  774. `
  775. if e, a := expected, buf.String(); e != a {
  776. t.Errorf("expected\n%v\ngot\n%v", e, a)
  777. }
  778. }
  779. func TestGetMultipleTypeObjects(t *testing.T) {
  780. pods, svc, _ := cmdtesting.TestData()
  781. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  782. defer tf.Cleanup()
  783. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  784. tf.UnstructuredClient = &fake.RESTClient{
  785. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  786. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  787. switch req.URL.Path {
  788. case "/namespaces/test/pods":
  789. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
  790. case "/namespaces/test/services":
  791. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svc)}, nil
  792. default:
  793. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  794. return nil, nil
  795. }
  796. }),
  797. }
  798. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  799. cmd := NewCmdGet("kubectl", tf, streams)
  800. cmd.SetOutput(buf)
  801. cmd.Run(cmd, []string{"pods,services"})
  802. expected := `NAME READY STATUS RESTARTS AGE
  803. pod/foo 0/0 0 <unknown>
  804. pod/bar 0/0 0 <unknown>
  805. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  806. service/baz ClusterIP <none> <none> <none> <unknown>
  807. `
  808. if e, a := expected, buf.String(); e != a {
  809. t.Errorf("expected\n%v\ngot\n%v", e, a)
  810. }
  811. }
  812. func TestGetMultipleTypeObjectsAsList(t *testing.T) {
  813. pods, svc, _ := cmdtesting.TestData()
  814. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  815. defer tf.Cleanup()
  816. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  817. tf.UnstructuredClient = &fake.RESTClient{
  818. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  819. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  820. switch req.URL.Path {
  821. case "/namespaces/test/pods":
  822. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
  823. case "/namespaces/test/services":
  824. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svc)}, nil
  825. default:
  826. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  827. return nil, nil
  828. }
  829. }),
  830. }
  831. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  832. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  833. cmd := NewCmdGet("kubectl", tf, streams)
  834. cmd.SetOutput(buf)
  835. cmd.Flags().Set("output", "json")
  836. cmd.Run(cmd, []string{"pods,services"})
  837. expected := `{
  838. "apiVersion": "v1",
  839. "items": [
  840. {
  841. "apiVersion": "v1",
  842. "kind": "Pod",
  843. "metadata": {
  844. "creationTimestamp": null,
  845. "name": "foo",
  846. "namespace": "test",
  847. "resourceVersion": "10"
  848. },
  849. "spec": {
  850. "containers": null,
  851. "dnsPolicy": "ClusterFirst",
  852. "enableServiceLinks": true,
  853. "restartPolicy": "Always",
  854. "securityContext": {},
  855. "terminationGracePeriodSeconds": 30
  856. },
  857. "status": {}
  858. },
  859. {
  860. "apiVersion": "v1",
  861. "kind": "Pod",
  862. "metadata": {
  863. "creationTimestamp": null,
  864. "name": "bar",
  865. "namespace": "test",
  866. "resourceVersion": "11"
  867. },
  868. "spec": {
  869. "containers": null,
  870. "dnsPolicy": "ClusterFirst",
  871. "enableServiceLinks": true,
  872. "restartPolicy": "Always",
  873. "securityContext": {},
  874. "terminationGracePeriodSeconds": 30
  875. },
  876. "status": {}
  877. },
  878. {
  879. "apiVersion": "v1",
  880. "kind": "Service",
  881. "metadata": {
  882. "creationTimestamp": null,
  883. "name": "baz",
  884. "namespace": "test",
  885. "resourceVersion": "12"
  886. },
  887. "spec": {
  888. "sessionAffinity": "None",
  889. "type": "ClusterIP"
  890. },
  891. "status": {
  892. "loadBalancer": {}
  893. }
  894. }
  895. ],
  896. "kind": "List",
  897. "metadata": {
  898. "resourceVersion": "",
  899. "selfLink": ""
  900. }
  901. }
  902. `
  903. if e, a := expected, buf.String(); e != a {
  904. t.Errorf("did not match: %v", diff.StringDiff(e, a))
  905. }
  906. }
  907. func TestGetMultipleTypeObjectsWithLabelSelector(t *testing.T) {
  908. pods, svc, _ := cmdtesting.TestData()
  909. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  910. defer tf.Cleanup()
  911. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  912. tf.UnstructuredClient = &fake.RESTClient{
  913. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  914. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  915. if req.URL.Query().Get(metav1.LabelSelectorQueryParam("v1")) != "a=b" {
  916. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  917. }
  918. switch req.URL.Path {
  919. case "/namespaces/test/pods":
  920. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
  921. case "/namespaces/test/services":
  922. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svc)}, nil
  923. default:
  924. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  925. return nil, nil
  926. }
  927. }),
  928. }
  929. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  930. cmd := NewCmdGet("kubectl", tf, streams)
  931. cmd.SetOutput(buf)
  932. cmd.Flags().Set("selector", "a=b")
  933. cmd.Run(cmd, []string{"pods,services"})
  934. expected := `NAME READY STATUS RESTARTS AGE
  935. pod/foo 0/0 0 <unknown>
  936. pod/bar 0/0 0 <unknown>
  937. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  938. service/baz ClusterIP <none> <none> <none> <unknown>
  939. `
  940. if e, a := expected, buf.String(); e != a {
  941. t.Errorf("expected\n%v\ngot\n%v", e, a)
  942. }
  943. }
  944. func TestGetMultipleTypeObjectsWithFieldSelector(t *testing.T) {
  945. pods, svc, _ := cmdtesting.TestData()
  946. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  947. defer tf.Cleanup()
  948. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  949. tf.UnstructuredClient = &fake.RESTClient{
  950. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  951. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  952. if req.URL.Query().Get(metav1.FieldSelectorQueryParam("v1")) != "a=b" {
  953. t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
  954. }
  955. switch req.URL.Path {
  956. case "/namespaces/test/pods":
  957. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, pods)}, nil
  958. case "/namespaces/test/services":
  959. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, svc)}, nil
  960. default:
  961. t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
  962. return nil, nil
  963. }
  964. }),
  965. }
  966. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  967. cmd := NewCmdGet("kubectl", tf, streams)
  968. cmd.SetOutput(buf)
  969. cmd.Flags().Set("field-selector", "a=b")
  970. cmd.Run(cmd, []string{"pods,services"})
  971. expected := `NAME READY STATUS RESTARTS AGE
  972. pod/foo 0/0 0 <unknown>
  973. pod/bar 0/0 0 <unknown>
  974. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  975. service/baz ClusterIP <none> <none> <none> <unknown>
  976. `
  977. if e, a := expected, buf.String(); e != a {
  978. t.Errorf("expected\n%v\ngot\n%v", e, a)
  979. }
  980. }
  981. func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) {
  982. _, svc, _ := cmdtesting.TestData()
  983. node := &corev1.Node{
  984. ObjectMeta: metav1.ObjectMeta{
  985. Name: "foo",
  986. },
  987. }
  988. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  989. defer tf.Cleanup()
  990. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  991. tf.UnstructuredClient = &fake.RESTClient{
  992. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  993. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  994. switch req.URL.Path {
  995. case "/nodes/foo":
  996. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, node)}, nil
  997. case "/namespaces/test/services/bar":
  998. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &svc.Items[0])}, nil
  999. default:
  1000. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1001. return nil, nil
  1002. }
  1003. }),
  1004. }
  1005. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  1006. cmd := NewCmdGet("kubectl", tf, streams)
  1007. cmd.SetOutput(buf)
  1008. cmd.Run(cmd, []string{"services/bar", "node/foo"})
  1009. expected := `NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  1010. service/baz ClusterIP <none> <none> <none> <unknown>
  1011. NAME STATUS ROLES AGE VERSION
  1012. node/foo Unknown <none> <unknown>
  1013. `
  1014. if e, a := expected, buf.String(); e != a {
  1015. t.Errorf("expected\n%v\ngot\n%v", e, a)
  1016. }
  1017. }
  1018. func watchTestData() ([]corev1.Pod, []watch.Event) {
  1019. pods := []corev1.Pod{
  1020. {
  1021. ObjectMeta: metav1.ObjectMeta{
  1022. Name: "bar",
  1023. Namespace: "test",
  1024. ResourceVersion: "9",
  1025. },
  1026. Spec: corev1.PodSpec{
  1027. RestartPolicy: corev1.RestartPolicyAlways,
  1028. DNSPolicy: corev1.DNSClusterFirst,
  1029. TerminationGracePeriodSeconds: &grace,
  1030. SecurityContext: &corev1.PodSecurityContext{},
  1031. EnableServiceLinks: &enableServiceLinks,
  1032. },
  1033. },
  1034. {
  1035. ObjectMeta: metav1.ObjectMeta{
  1036. Name: "foo",
  1037. Namespace: "test",
  1038. ResourceVersion: "10",
  1039. },
  1040. Spec: corev1.PodSpec{
  1041. RestartPolicy: corev1.RestartPolicyAlways,
  1042. DNSPolicy: corev1.DNSClusterFirst,
  1043. TerminationGracePeriodSeconds: &grace,
  1044. SecurityContext: &corev1.PodSecurityContext{},
  1045. EnableServiceLinks: &enableServiceLinks,
  1046. },
  1047. },
  1048. }
  1049. events := []watch.Event{
  1050. // current state events
  1051. {
  1052. Type: watch.Added,
  1053. Object: &corev1.Pod{
  1054. ObjectMeta: metav1.ObjectMeta{
  1055. Name: "bar",
  1056. Namespace: "test",
  1057. ResourceVersion: "9",
  1058. },
  1059. Spec: corev1.PodSpec{
  1060. RestartPolicy: corev1.RestartPolicyAlways,
  1061. DNSPolicy: corev1.DNSClusterFirst,
  1062. TerminationGracePeriodSeconds: &grace,
  1063. SecurityContext: &corev1.PodSecurityContext{},
  1064. EnableServiceLinks: &enableServiceLinks,
  1065. },
  1066. },
  1067. },
  1068. {
  1069. Type: watch.Added,
  1070. Object: &corev1.Pod{
  1071. ObjectMeta: metav1.ObjectMeta{
  1072. Name: "foo",
  1073. Namespace: "test",
  1074. ResourceVersion: "10",
  1075. },
  1076. Spec: corev1.PodSpec{
  1077. RestartPolicy: corev1.RestartPolicyAlways,
  1078. DNSPolicy: corev1.DNSClusterFirst,
  1079. TerminationGracePeriodSeconds: &grace,
  1080. SecurityContext: &corev1.PodSecurityContext{},
  1081. EnableServiceLinks: &enableServiceLinks,
  1082. },
  1083. },
  1084. },
  1085. // resource events
  1086. {
  1087. Type: watch.Modified,
  1088. Object: &corev1.Pod{
  1089. ObjectMeta: metav1.ObjectMeta{
  1090. Name: "foo",
  1091. Namespace: "test",
  1092. ResourceVersion: "11",
  1093. },
  1094. Spec: corev1.PodSpec{
  1095. RestartPolicy: corev1.RestartPolicyAlways,
  1096. DNSPolicy: corev1.DNSClusterFirst,
  1097. TerminationGracePeriodSeconds: &grace,
  1098. SecurityContext: &corev1.PodSecurityContext{},
  1099. EnableServiceLinks: &enableServiceLinks,
  1100. },
  1101. },
  1102. },
  1103. {
  1104. Type: watch.Deleted,
  1105. Object: &corev1.Pod{
  1106. ObjectMeta: metav1.ObjectMeta{
  1107. Name: "foo",
  1108. Namespace: "test",
  1109. ResourceVersion: "12",
  1110. },
  1111. Spec: corev1.PodSpec{
  1112. RestartPolicy: corev1.RestartPolicyAlways,
  1113. DNSPolicy: corev1.DNSClusterFirst,
  1114. TerminationGracePeriodSeconds: &grace,
  1115. SecurityContext: &corev1.PodSecurityContext{},
  1116. EnableServiceLinks: &enableServiceLinks,
  1117. },
  1118. },
  1119. },
  1120. }
  1121. return pods, events
  1122. }
  1123. func TestWatchLabelSelector(t *testing.T) {
  1124. pods, events := watchTestData()
  1125. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  1126. defer tf.Cleanup()
  1127. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  1128. podList := &corev1.PodList{
  1129. Items: pods,
  1130. ListMeta: metav1.ListMeta{
  1131. ResourceVersion: "10",
  1132. },
  1133. }
  1134. tf.UnstructuredClient = &fake.RESTClient{
  1135. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  1136. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  1137. if req.URL.Query().Get(metav1.LabelSelectorQueryParam("v1")) != "a=b" {
  1138. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1139. }
  1140. switch req.URL.Path {
  1141. case "/namespaces/test/pods":
  1142. if req.URL.Query().Get("watch") == "true" {
  1143. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[2:])}, nil
  1144. }
  1145. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, podList)}, nil
  1146. default:
  1147. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1148. return nil, nil
  1149. }
  1150. }),
  1151. }
  1152. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  1153. cmd := NewCmdGet("kubectl", tf, streams)
  1154. cmd.SetOutput(buf)
  1155. cmd.Flags().Set("watch", "true")
  1156. cmd.Flags().Set("selector", "a=b")
  1157. cmd.Run(cmd, []string{"pods"})
  1158. expected := `NAME READY STATUS RESTARTS AGE
  1159. bar 0/0 0 <unknown>
  1160. foo 0/0 0 <unknown>
  1161. foo 0/0 0 <unknown>
  1162. foo 0/0 0 <unknown>
  1163. `
  1164. if e, a := expected, buf.String(); e != a {
  1165. t.Errorf("expected\n%v\ngot\n%v", e, a)
  1166. }
  1167. }
  1168. func TestWatchFieldSelector(t *testing.T) {
  1169. pods, events := watchTestData()
  1170. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  1171. defer tf.Cleanup()
  1172. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  1173. podList := &corev1.PodList{
  1174. Items: pods,
  1175. ListMeta: metav1.ListMeta{
  1176. ResourceVersion: "10",
  1177. },
  1178. }
  1179. tf.UnstructuredClient = &fake.RESTClient{
  1180. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  1181. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  1182. if req.URL.Query().Get(metav1.FieldSelectorQueryParam("v1")) != "a=b" {
  1183. t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
  1184. }
  1185. switch req.URL.Path {
  1186. case "/namespaces/test/pods":
  1187. if req.URL.Query().Get("watch") == "true" {
  1188. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[2:])}, nil
  1189. }
  1190. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, podList)}, nil
  1191. default:
  1192. t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
  1193. return nil, nil
  1194. }
  1195. }),
  1196. }
  1197. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  1198. cmd := NewCmdGet("kubectl", tf, streams)
  1199. cmd.SetOutput(buf)
  1200. cmd.Flags().Set("watch", "true")
  1201. cmd.Flags().Set("field-selector", "a=b")
  1202. cmd.Run(cmd, []string{"pods"})
  1203. expected := `NAME READY STATUS RESTARTS AGE
  1204. bar 0/0 0 <unknown>
  1205. foo 0/0 0 <unknown>
  1206. foo 0/0 0 <unknown>
  1207. foo 0/0 0 <unknown>
  1208. `
  1209. if e, a := expected, buf.String(); e != a {
  1210. t.Errorf("expected\n%v\ngot\n%v", e, a)
  1211. }
  1212. }
  1213. func TestWatchResource(t *testing.T) {
  1214. pods, events := watchTestData()
  1215. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  1216. defer tf.Cleanup()
  1217. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  1218. tf.UnstructuredClient = &fake.RESTClient{
  1219. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  1220. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  1221. switch req.URL.Path {
  1222. case "/namespaces/test/pods/foo":
  1223. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil
  1224. case "/namespaces/test/pods":
  1225. if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=foo" {
  1226. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[1:])}, nil
  1227. }
  1228. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1229. return nil, nil
  1230. default:
  1231. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1232. return nil, nil
  1233. }
  1234. }),
  1235. }
  1236. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  1237. cmd := NewCmdGet("kubectl", tf, streams)
  1238. cmd.SetOutput(buf)
  1239. cmd.Flags().Set("watch", "true")
  1240. cmd.Run(cmd, []string{"pods", "foo"})
  1241. expected := `NAME READY STATUS RESTARTS AGE
  1242. foo 0/0 0 <unknown>
  1243. foo 0/0 0 <unknown>
  1244. foo 0/0 0 <unknown>
  1245. `
  1246. if e, a := expected, buf.String(); e != a {
  1247. t.Errorf("expected\n%v\ngot\n%v", e, a)
  1248. }
  1249. }
  1250. func TestWatchResourceTable(t *testing.T) {
  1251. columns := []metav1beta1.TableColumnDefinition{
  1252. {Name: "Name", Type: "string", Format: "name", Description: "the name", Priority: 0},
  1253. {Name: "Active", Type: "boolean", Description: "active", Priority: 0},
  1254. }
  1255. listTable := &metav1beta1.Table{
  1256. TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1beta1", Kind: "Table"},
  1257. ColumnDefinitions: columns,
  1258. Rows: []metav1beta1.TableRow{
  1259. {
  1260. Cells: []interface{}{"a", true},
  1261. Object: runtime.RawExtension{
  1262. Object: &corev1.Pod{
  1263. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  1264. ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "10"},
  1265. },
  1266. },
  1267. },
  1268. {
  1269. Cells: []interface{}{"b", true},
  1270. Object: runtime.RawExtension{
  1271. Object: &corev1.Pod{
  1272. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  1273. ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "20"},
  1274. },
  1275. },
  1276. },
  1277. },
  1278. }
  1279. events := []watch.Event{
  1280. {
  1281. Type: watch.Added,
  1282. Object: &metav1beta1.Table{
  1283. TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1beta1", Kind: "Table"},
  1284. ColumnDefinitions: columns, // first event includes the columns
  1285. Rows: []metav1beta1.TableRow{{
  1286. Cells: []interface{}{"a", false},
  1287. Object: runtime.RawExtension{
  1288. Object: &corev1.Pod{
  1289. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  1290. ObjectMeta: metav1.ObjectMeta{Name: "a", Namespace: "test", ResourceVersion: "30"},
  1291. },
  1292. },
  1293. }},
  1294. },
  1295. },
  1296. {
  1297. Type: watch.Deleted,
  1298. Object: &metav1beta1.Table{
  1299. ColumnDefinitions: []metav1beta1.TableColumnDefinition{},
  1300. Rows: []metav1beta1.TableRow{{
  1301. Cells: []interface{}{"b", false},
  1302. Object: runtime.RawExtension{
  1303. Object: &corev1.Pod{
  1304. TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
  1305. ObjectMeta: metav1.ObjectMeta{Name: "b", Namespace: "test", ResourceVersion: "40"},
  1306. },
  1307. },
  1308. }},
  1309. },
  1310. },
  1311. }
  1312. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  1313. defer tf.Cleanup()
  1314. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  1315. tf.UnstructuredClient = &fake.RESTClient{
  1316. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  1317. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  1318. switch req.URL.Path {
  1319. case "/namespaces/test/pods":
  1320. if req.URL.Query().Get("watch") != "true" && req.URL.Query().Get("fieldSelector") == "" {
  1321. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, listTable)}, nil
  1322. }
  1323. if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "" {
  1324. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events)}, nil
  1325. }
  1326. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1327. return nil, nil
  1328. default:
  1329. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1330. return nil, nil
  1331. }
  1332. }),
  1333. }
  1334. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  1335. cmd := NewCmdGet("kubectl", tf, streams)
  1336. cmd.SetOutput(buf)
  1337. cmd.Flags().Set("watch", "true")
  1338. cmd.Run(cmd, []string{"pods"})
  1339. expected := `NAME ACTIVE
  1340. a true
  1341. b true
  1342. a false
  1343. b false
  1344. `
  1345. if e, a := expected, buf.String(); e != a {
  1346. t.Errorf("expected\n%v\ngot\n%v", e, a)
  1347. }
  1348. }
  1349. func TestWatchResourceIdentifiedByFile(t *testing.T) {
  1350. pods, events := watchTestData()
  1351. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  1352. defer tf.Cleanup()
  1353. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  1354. tf.UnstructuredClient = &fake.RESTClient{
  1355. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  1356. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  1357. switch req.URL.Path {
  1358. case "/namespaces/test/replicationcontrollers/cassandra":
  1359. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil
  1360. case "/namespaces/test/replicationcontrollers":
  1361. if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=cassandra" {
  1362. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[1:])}, nil
  1363. }
  1364. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1365. return nil, nil
  1366. default:
  1367. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1368. return nil, nil
  1369. }
  1370. }),
  1371. }
  1372. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  1373. cmd := NewCmdGet("kubectl", tf, streams)
  1374. cmd.SetOutput(buf)
  1375. cmd.Flags().Set("watch", "true")
  1376. cmd.Flags().Set("filename", "../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml")
  1377. cmd.Run(cmd, []string{})
  1378. expected := `NAME READY STATUS RESTARTS AGE
  1379. foo 0/0 0 <unknown>
  1380. foo 0/0 0 <unknown>
  1381. foo 0/0 0 <unknown>
  1382. `
  1383. if e, a := expected, buf.String(); e != a {
  1384. t.Errorf("expected\n%v\ngot\n%v", e, a)
  1385. }
  1386. }
  1387. func TestWatchOnlyResource(t *testing.T) {
  1388. pods, events := watchTestData()
  1389. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  1390. defer tf.Cleanup()
  1391. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  1392. tf.UnstructuredClient = &fake.RESTClient{
  1393. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  1394. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  1395. switch req.URL.Path {
  1396. case "/namespaces/test/pods/foo":
  1397. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &pods[1])}, nil
  1398. case "/namespaces/test/pods":
  1399. if req.URL.Query().Get("watch") == "true" && req.URL.Query().Get("fieldSelector") == "metadata.name=foo" {
  1400. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[1:])}, nil
  1401. }
  1402. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1403. return nil, nil
  1404. default:
  1405. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1406. return nil, nil
  1407. }
  1408. }),
  1409. }
  1410. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  1411. cmd := NewCmdGet("kubectl", tf, streams)
  1412. cmd.SetOutput(buf)
  1413. cmd.Flags().Set("watch-only", "true")
  1414. cmd.Run(cmd, []string{"pods", "foo"})
  1415. expected := `NAME READY STATUS RESTARTS AGE
  1416. foo 0/0 0 <unknown>
  1417. foo 0/0 0 <unknown>
  1418. `
  1419. if e, a := expected, buf.String(); e != a {
  1420. t.Errorf("expected\n%v\ngot\n%v", e, a)
  1421. }
  1422. }
  1423. func TestWatchOnlyList(t *testing.T) {
  1424. pods, events := watchTestData()
  1425. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  1426. defer tf.Cleanup()
  1427. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  1428. podList := &corev1.PodList{
  1429. Items: pods,
  1430. ListMeta: metav1.ListMeta{
  1431. ResourceVersion: "10",
  1432. },
  1433. }
  1434. tf.UnstructuredClient = &fake.RESTClient{
  1435. NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer,
  1436. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  1437. switch req.URL.Path {
  1438. case "/namespaces/test/pods":
  1439. if req.URL.Query().Get("watch") == "true" {
  1440. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: watchBody(codec, events[2:])}, nil
  1441. }
  1442. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, podList)}, nil
  1443. default:
  1444. t.Fatalf("request url: %#v,and request: %#v", req.URL, req)
  1445. return nil, nil
  1446. }
  1447. }),
  1448. }
  1449. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  1450. cmd := NewCmdGet("kubectl", tf, streams)
  1451. cmd.SetOutput(buf)
  1452. cmd.Flags().Set("watch-only", "true")
  1453. cmd.Run(cmd, []string{"pods"})
  1454. expected := `NAME READY STATUS RESTARTS AGE
  1455. foo 0/0 0 <unknown>
  1456. foo 0/0 0 <unknown>
  1457. `
  1458. if e, a := expected, buf.String(); e != a {
  1459. t.Errorf("expected\n%v\ngot\n%v", e, a)
  1460. }
  1461. }
  1462. func watchBody(codec runtime.Codec, events []watch.Event) io.ReadCloser {
  1463. buf := bytes.NewBuffer([]byte{})
  1464. enc := restclientwatch.NewEncoder(streaming.NewEncoder(buf, codec), codec)
  1465. for i := range events {
  1466. if err := enc.Encode(&events[i]); err != nil {
  1467. panic(err)
  1468. }
  1469. }
  1470. return json.Framer.NewFrameReader(ioutil.NopCloser(buf))
  1471. }