top_node_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*
  2. Copyright 2016 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 top
  14. import (
  15. "bytes"
  16. "fmt"
  17. "io/ioutil"
  18. "net/http"
  19. "strings"
  20. "testing"
  21. "net/url"
  22. "k8s.io/api/core/v1"
  23. "k8s.io/apimachinery/pkg/runtime"
  24. "k8s.io/cli-runtime/pkg/genericclioptions"
  25. "k8s.io/client-go/rest/fake"
  26. core "k8s.io/client-go/testing"
  27. cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
  28. "k8s.io/kubernetes/pkg/kubectl/scheme"
  29. metricsv1alpha1api "k8s.io/metrics/pkg/apis/metrics/v1alpha1"
  30. metricsv1beta1api "k8s.io/metrics/pkg/apis/metrics/v1beta1"
  31. metricsfake "k8s.io/metrics/pkg/client/clientset/versioned/fake"
  32. )
  33. const (
  34. apiPrefix = "api"
  35. apiVersion = "v1"
  36. )
  37. func TestTopNodeAllMetrics(t *testing.T) {
  38. cmdtesting.InitTestErrorHandler(t)
  39. metrics, nodes := testNodeV1alpha1MetricsData()
  40. expectedMetricsPath := fmt.Sprintf("%s/%s/nodes", baseMetricsAddress, metricsAPIVersion)
  41. expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
  42. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  43. defer tf.Cleanup()
  44. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  45. ns := scheme.Codecs
  46. tf.Client = &fake.RESTClient{
  47. NegotiatedSerializer: ns,
  48. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  49. switch p, m := req.URL.Path, req.Method; {
  50. case p == "/api":
  51. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
  52. case p == "/apis":
  53. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbody)))}, nil
  54. case p == expectedMetricsPath && m == "GET":
  55. body, err := marshallBody(metrics)
  56. if err != nil {
  57. t.Errorf("unexpected error: %v", err)
  58. }
  59. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
  60. case p == expectedNodePath && m == "GET":
  61. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, nodes)}, nil
  62. default:
  63. t.Fatalf("unexpected request: %#v\nGot URL: %#v\nExpected path: %#v", req, req.URL, expectedMetricsPath)
  64. return nil, nil
  65. }
  66. }),
  67. }
  68. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  69. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  70. cmd := NewCmdTopNode(tf, nil, streams)
  71. cmd.Flags().Set("no-headers", "true")
  72. cmd.Run(cmd, []string{})
  73. // Check the presence of node names in the output.
  74. result := buf.String()
  75. for _, m := range metrics.Items {
  76. if !strings.Contains(result, m.Name) {
  77. t.Errorf("missing metrics for %s: \n%s", m.Name, result)
  78. }
  79. }
  80. if strings.Contains(result, "MEMORY") {
  81. t.Errorf("should not print headers with --no-headers option set:\n%s\n", result)
  82. }
  83. }
  84. func TestTopNodeAllMetricsCustomDefaults(t *testing.T) {
  85. customBaseHeapsterServiceAddress := "/api/v1/namespaces/custom-namespace/services/https:custom-heapster-service:/proxy"
  86. customBaseMetricsAddress := customBaseHeapsterServiceAddress + "/apis/metrics"
  87. cmdtesting.InitTestErrorHandler(t)
  88. metrics, nodes := testNodeV1alpha1MetricsData()
  89. expectedMetricsPath := fmt.Sprintf("%s/%s/nodes", customBaseMetricsAddress, metricsAPIVersion)
  90. expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
  91. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  92. defer tf.Cleanup()
  93. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  94. ns := scheme.Codecs
  95. tf.Client = &fake.RESTClient{
  96. NegotiatedSerializer: ns,
  97. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  98. switch p, m := req.URL.Path, req.Method; {
  99. case p == "/api":
  100. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
  101. case p == "/apis":
  102. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbody)))}, nil
  103. case p == expectedMetricsPath && m == "GET":
  104. body, err := marshallBody(metrics)
  105. if err != nil {
  106. t.Errorf("unexpected error: %v", err)
  107. }
  108. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
  109. case p == expectedNodePath && m == "GET":
  110. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, nodes)}, nil
  111. default:
  112. t.Fatalf("unexpected request: %#v\nGot URL: %#v\nExpected path: %#v", req, req.URL, expectedMetricsPath)
  113. return nil, nil
  114. }
  115. }),
  116. }
  117. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  118. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  119. opts := &TopNodeOptions{
  120. HeapsterOptions: HeapsterTopOptions{
  121. Namespace: "custom-namespace",
  122. Scheme: "https",
  123. Service: "custom-heapster-service",
  124. },
  125. IOStreams: streams,
  126. }
  127. cmd := NewCmdTopNode(tf, opts, streams)
  128. cmd.Run(cmd, []string{})
  129. // Check the presence of node names in the output.
  130. result := buf.String()
  131. for _, m := range metrics.Items {
  132. if !strings.Contains(result, m.Name) {
  133. t.Errorf("missing metrics for %s: \n%s", m.Name, result)
  134. }
  135. }
  136. }
  137. func TestTopNodeWithNameMetrics(t *testing.T) {
  138. cmdtesting.InitTestErrorHandler(t)
  139. metrics, nodes := testNodeV1alpha1MetricsData()
  140. expectedMetrics := metrics.Items[0]
  141. expectedNode := nodes.Items[0]
  142. nonExpectedMetrics := metricsv1alpha1api.NodeMetricsList{
  143. ListMeta: metrics.ListMeta,
  144. Items: metrics.Items[1:],
  145. }
  146. expectedPath := fmt.Sprintf("%s/%s/nodes/%s", baseMetricsAddress, metricsAPIVersion, expectedMetrics.Name)
  147. expectedNodePath := fmt.Sprintf("/%s/%s/nodes/%s", apiPrefix, apiVersion, expectedMetrics.Name)
  148. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  149. defer tf.Cleanup()
  150. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  151. ns := scheme.Codecs
  152. tf.Client = &fake.RESTClient{
  153. NegotiatedSerializer: ns,
  154. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  155. switch p, m := req.URL.Path, req.Method; {
  156. case p == "/api":
  157. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
  158. case p == "/apis":
  159. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbody)))}, nil
  160. case p == expectedPath && m == "GET":
  161. body, err := marshallBody(expectedMetrics)
  162. if err != nil {
  163. t.Errorf("unexpected error: %v", err)
  164. }
  165. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
  166. case p == expectedNodePath && m == "GET":
  167. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &expectedNode)}, nil
  168. default:
  169. t.Fatalf("unexpected request: %#v\nGot URL: %#v\nExpected path: %#v", req, req.URL, expectedPath)
  170. return nil, nil
  171. }
  172. }),
  173. }
  174. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  175. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  176. cmd := NewCmdTopNode(tf, nil, streams)
  177. cmd.Run(cmd, []string{expectedMetrics.Name})
  178. // Check the presence of node names in the output.
  179. result := buf.String()
  180. if !strings.Contains(result, expectedMetrics.Name) {
  181. t.Errorf("missing metrics for %s: \n%s", expectedMetrics.Name, result)
  182. }
  183. for _, m := range nonExpectedMetrics.Items {
  184. if strings.Contains(result, m.Name) {
  185. t.Errorf("unexpected metrics for %s: \n%s", m.Name, result)
  186. }
  187. }
  188. }
  189. func TestTopNodeWithLabelSelectorMetrics(t *testing.T) {
  190. cmdtesting.InitTestErrorHandler(t)
  191. metrics, nodes := testNodeV1alpha1MetricsData()
  192. expectedMetrics := metricsv1alpha1api.NodeMetricsList{
  193. ListMeta: metrics.ListMeta,
  194. Items: metrics.Items[0:1],
  195. }
  196. expectedNodes := v1.NodeList{
  197. ListMeta: nodes.ListMeta,
  198. Items: nodes.Items[0:1],
  199. }
  200. nonExpectedMetrics := metricsv1alpha1api.NodeMetricsList{
  201. ListMeta: metrics.ListMeta,
  202. Items: metrics.Items[1:],
  203. }
  204. label := "key=value"
  205. expectedPath := fmt.Sprintf("%s/%s/nodes", baseMetricsAddress, metricsAPIVersion)
  206. expectedQuery := fmt.Sprintf("labelSelector=%s", url.QueryEscape(label))
  207. expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
  208. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  209. defer tf.Cleanup()
  210. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  211. ns := scheme.Codecs
  212. tf.Client = &fake.RESTClient{
  213. NegotiatedSerializer: ns,
  214. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  215. switch p, m, q := req.URL.Path, req.Method, req.URL.RawQuery; {
  216. case p == "/api":
  217. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
  218. case p == "/apis":
  219. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbody)))}, nil
  220. case p == expectedPath && m == "GET" && q == expectedQuery:
  221. body, err := marshallBody(expectedMetrics)
  222. if err != nil {
  223. t.Errorf("unexpected error: %v", err)
  224. }
  225. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: body}, nil
  226. case p == expectedNodePath && m == "GET":
  227. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &expectedNodes)}, nil
  228. default:
  229. t.Fatalf("unexpected request: %#v\nGot URL: %#v\nExpected path: %#v", req, req.URL, expectedPath)
  230. return nil, nil
  231. }
  232. }),
  233. }
  234. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  235. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  236. cmd := NewCmdTopNode(tf, nil, streams)
  237. cmd.Flags().Set("selector", label)
  238. cmd.Run(cmd, []string{})
  239. // Check the presence of node names in the output.
  240. result := buf.String()
  241. for _, m := range expectedMetrics.Items {
  242. if !strings.Contains(result, m.Name) {
  243. t.Errorf("missing metrics for %s: \n%s", m.Name, result)
  244. }
  245. }
  246. for _, m := range nonExpectedMetrics.Items {
  247. if strings.Contains(result, m.Name) {
  248. t.Errorf("unexpected metrics for %s: \n%s", m.Name, result)
  249. }
  250. }
  251. }
  252. func TestTopNodeAllMetricsFromMetricsServer(t *testing.T) {
  253. cmdtesting.InitTestErrorHandler(t)
  254. expectedMetrics, nodes := testNodeV1beta1MetricsData()
  255. expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
  256. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  257. defer tf.Cleanup()
  258. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  259. ns := scheme.Codecs
  260. tf.Client = &fake.RESTClient{
  261. NegotiatedSerializer: ns,
  262. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  263. switch p, m := req.URL.Path, req.Method; {
  264. case p == "/api":
  265. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
  266. case p == "/apis":
  267. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbodyWithMetrics)))}, nil
  268. case p == expectedNodePath && m == "GET":
  269. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, nodes)}, nil
  270. default:
  271. t.Fatalf("unexpected request: %#v\nGot URL: %#v\n", req, req.URL)
  272. return nil, nil
  273. }
  274. }),
  275. }
  276. fakemetricsClientset := &metricsfake.Clientset{}
  277. fakemetricsClientset.AddReactor("list", "nodes", func(action core.Action) (handled bool, ret runtime.Object, err error) {
  278. return true, expectedMetrics, nil
  279. })
  280. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  281. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  282. cmd := NewCmdTopNode(tf, nil, streams)
  283. // TODO in the long run, we want to test most of our commands like this. Wire the options struct with specific mocks
  284. // TODO then check the particular Run functionality and harvest results from fake clients
  285. cmdOptions := &TopNodeOptions{
  286. IOStreams: streams,
  287. }
  288. if err := cmdOptions.Complete(tf, cmd, []string{}); err != nil {
  289. t.Fatal(err)
  290. }
  291. cmdOptions.MetricsClient = fakemetricsClientset
  292. if err := cmdOptions.Validate(); err != nil {
  293. t.Fatal(err)
  294. }
  295. if err := cmdOptions.RunTopNode(); err != nil {
  296. t.Fatal(err)
  297. }
  298. // Check the presence of node names in the output.
  299. result := buf.String()
  300. for _, m := range expectedMetrics.Items {
  301. if !strings.Contains(result, m.Name) {
  302. t.Errorf("missing metrics for %s: \n%s", m.Name, result)
  303. }
  304. }
  305. }
  306. func TestTopNodeWithNameMetricsFromMetricsServer(t *testing.T) {
  307. cmdtesting.InitTestErrorHandler(t)
  308. metrics, nodes := testNodeV1beta1MetricsData()
  309. expectedMetrics := metrics.Items[0]
  310. expectedNode := nodes.Items[0]
  311. nonExpectedMetrics := metricsv1beta1api.NodeMetricsList{
  312. ListMeta: metrics.ListMeta,
  313. Items: metrics.Items[1:],
  314. }
  315. expectedNodePath := fmt.Sprintf("/%s/%s/nodes/%s", apiPrefix, apiVersion, expectedMetrics.Name)
  316. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  317. defer tf.Cleanup()
  318. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  319. ns := scheme.Codecs
  320. tf.Client = &fake.RESTClient{
  321. NegotiatedSerializer: ns,
  322. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  323. switch p, m := req.URL.Path, req.Method; {
  324. case p == "/api":
  325. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
  326. case p == "/apis":
  327. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbodyWithMetrics)))}, nil
  328. case p == expectedNodePath && m == "GET":
  329. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &expectedNode)}, nil
  330. default:
  331. t.Fatalf("unexpected request: %#v\nGot URL: %#v\n", req, req.URL)
  332. return nil, nil
  333. }
  334. }),
  335. }
  336. fakemetricsClientset := &metricsfake.Clientset{}
  337. fakemetricsClientset.AddReactor("get", "nodes", func(action core.Action) (handled bool, ret runtime.Object, err error) {
  338. return true, &expectedMetrics, nil
  339. })
  340. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  341. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  342. cmd := NewCmdTopNode(tf, nil, streams)
  343. // TODO in the long run, we want to test most of our commands like this. Wire the options struct with specific mocks
  344. // TODO then check the particular Run functionality and harvest results from fake clients
  345. cmdOptions := &TopNodeOptions{
  346. IOStreams: streams,
  347. }
  348. if err := cmdOptions.Complete(tf, cmd, []string{expectedMetrics.Name}); err != nil {
  349. t.Fatal(err)
  350. }
  351. cmdOptions.MetricsClient = fakemetricsClientset
  352. if err := cmdOptions.Validate(); err != nil {
  353. t.Fatal(err)
  354. }
  355. if err := cmdOptions.RunTopNode(); err != nil {
  356. t.Fatal(err)
  357. }
  358. // Check the presence of node names in the output.
  359. result := buf.String()
  360. if !strings.Contains(result, expectedMetrics.Name) {
  361. t.Errorf("missing metrics for %s: \n%s", expectedMetrics.Name, result)
  362. }
  363. for _, m := range nonExpectedMetrics.Items {
  364. if strings.Contains(result, m.Name) {
  365. t.Errorf("unexpected metrics for %s: \n%s", m.Name, result)
  366. }
  367. }
  368. }
  369. func TestTopNodeWithLabelSelectorMetricsFromMetricsServer(t *testing.T) {
  370. cmdtesting.InitTestErrorHandler(t)
  371. metrics, nodes := testNodeV1beta1MetricsData()
  372. expectedMetrics := &metricsv1beta1api.NodeMetricsList{
  373. ListMeta: metrics.ListMeta,
  374. Items: metrics.Items[0:1],
  375. }
  376. expectedNodes := v1.NodeList{
  377. ListMeta: nodes.ListMeta,
  378. Items: nodes.Items[0:1],
  379. }
  380. nonExpectedMetrics := &metricsv1beta1api.NodeMetricsList{
  381. ListMeta: metrics.ListMeta,
  382. Items: metrics.Items[1:],
  383. }
  384. label := "key=value"
  385. expectedNodePath := fmt.Sprintf("/%s/%s/nodes", apiPrefix, apiVersion)
  386. tf := cmdtesting.NewTestFactory().WithNamespace("test")
  387. defer tf.Cleanup()
  388. codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...)
  389. ns := scheme.Codecs
  390. tf.Client = &fake.RESTClient{
  391. NegotiatedSerializer: ns,
  392. Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
  393. switch p, m, _ := req.URL.Path, req.Method, req.URL.RawQuery; {
  394. case p == "/api":
  395. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apibody)))}, nil
  396. case p == "/apis":
  397. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: ioutil.NopCloser(bytes.NewReader([]byte(apisbodyWithMetrics)))}, nil
  398. case p == expectedNodePath && m == "GET":
  399. return &http.Response{StatusCode: 200, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &expectedNodes)}, nil
  400. default:
  401. t.Fatalf("unexpected request: %#v\nGot URL: %#v\n", req, req.URL)
  402. return nil, nil
  403. }
  404. }),
  405. }
  406. fakemetricsClientset := &metricsfake.Clientset{}
  407. fakemetricsClientset.AddReactor("list", "nodes", func(action core.Action) (handled bool, ret runtime.Object, err error) {
  408. return true, expectedMetrics, nil
  409. })
  410. tf.ClientConfigVal = cmdtesting.DefaultClientConfig()
  411. streams, _, buf, _ := genericclioptions.NewTestIOStreams()
  412. cmd := NewCmdTopNode(tf, nil, streams)
  413. cmd.Flags().Set("selector", label)
  414. // TODO in the long run, we want to test most of our commands like this. Wire the options struct with specific mocks
  415. // TODO then check the particular Run functionality and harvest results from fake clients
  416. cmdOptions := &TopNodeOptions{
  417. IOStreams: streams,
  418. }
  419. if err := cmdOptions.Complete(tf, cmd, []string{}); err != nil {
  420. t.Fatal(err)
  421. }
  422. cmdOptions.MetricsClient = fakemetricsClientset
  423. if err := cmdOptions.Validate(); err != nil {
  424. t.Fatal(err)
  425. }
  426. if err := cmdOptions.RunTopNode(); err != nil {
  427. t.Fatal(err)
  428. }
  429. // Check the presence of node names in the output.
  430. result := buf.String()
  431. for _, m := range expectedMetrics.Items {
  432. if !strings.Contains(result, m.Name) {
  433. t.Errorf("missing metrics for %s: \n%s", m.Name, result)
  434. }
  435. }
  436. for _, m := range nonExpectedMetrics.Items {
  437. if strings.Contains(result, m.Name) {
  438. t.Errorf("unexpected metrics for %s: \n%s", m.Name, result)
  439. }
  440. }
  441. }