1
16
17 package apiresources
18
19 import (
20 "testing"
21
22 "github.com/spf13/cobra"
23
24 v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 "k8s.io/cli-runtime/pkg/genericiooptions"
26 cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
27 )
28
29 func TestAPIResourcesComplete(t *testing.T) {
30 tf := cmdtesting.NewTestFactory()
31 defer tf.Cleanup()
32 cmd := NewCmdAPIResources(tf, genericiooptions.NewTestIOStreamsDiscard())
33 parentCmd := &cobra.Command{Use: "kubectl"}
34 parentCmd.AddCommand(cmd)
35 o := NewAPIResourceOptions(genericiooptions.NewTestIOStreamsDiscard())
36
37 err := o.Complete(tf, cmd, []string{})
38 if err != nil {
39 t.Fatalf("Unexpected error: %v", err)
40 }
41
42 err = o.Complete(tf, cmd, []string{"foo"})
43 if err == nil {
44 t.Fatalf("An error was expected but not returned")
45 }
46 expectedError := `unexpected arguments: [foo]
47 See 'kubectl api-resources -h' for help and examples`
48 if err.Error() != expectedError {
49 t.Fatalf("Unexpected error: %v\n expected: %v", err, expectedError)
50 }
51 }
52
53 func TestAPIResourcesValidate(t *testing.T) {
54 testCases := []struct {
55 name string
56 optionSetupFn func(o *APIResourceOptions)
57 expectedError string
58 }{
59 {
60 name: "no errors",
61 optionSetupFn: func(o *APIResourceOptions) {},
62 expectedError: "",
63 },
64 {
65 name: "invalid output",
66 optionSetupFn: func(o *APIResourceOptions) {
67 o.Output = "foo"
68 },
69 expectedError: "--output foo is not available",
70 },
71 {
72 name: "invalid sort by",
73 optionSetupFn: func(o *APIResourceOptions) {
74 o.SortBy = "foo"
75 },
76 expectedError: "--sort-by accepts only name or kind",
77 },
78 }
79
80 for _, tc := range testCases {
81 t.Run(tc.name, func(tt *testing.T) {
82 o := NewAPIResourceOptions(genericiooptions.NewTestIOStreamsDiscard())
83 tc.optionSetupFn(o)
84 err := o.Validate()
85 if tc.expectedError == "" {
86 if err != nil {
87 tt.Fatalf("Unexpected error: %v", err)
88 }
89 } else {
90 if err == nil {
91 tt.Fatalf("An error was expected but not returned")
92 }
93 if err.Error() != tc.expectedError {
94 tt.Fatalf("Unexpected error: %v, expected: %v", err, tc.expectedError)
95 }
96 }
97 })
98 }
99 }
100
101 func TestAPIResourcesRun(t *testing.T) {
102 dc := cmdtesting.NewFakeCachedDiscoveryClient()
103 dc.PreferredResources = []*v1.APIResourceList{
104 {
105 GroupVersion: "v1",
106 APIResources: []v1.APIResource{
107 {
108 Name: "foos",
109 Namespaced: false,
110 Kind: "Foo",
111 Verbs: []string{"get", "list"},
112 ShortNames: []string{"f", "fo"},
113 Categories: []string{"some-category"},
114 },
115 {
116 Name: "bars",
117 Namespaced: true,
118 Kind: "Bar",
119 Verbs: []string{"get", "list", "create"},
120 ShortNames: []string{},
121 Categories: []string{},
122 },
123 },
124 },
125 {
126 GroupVersion: "somegroup/v1",
127 APIResources: []v1.APIResource{
128 {
129 Name: "bazzes",
130 Namespaced: true,
131 Kind: "Baz",
132 Verbs: []string{"get", "list", "create", "delete"},
133 ShortNames: []string{"b"},
134 Categories: []string{"some-category", "another-category"},
135 },
136 {
137 Name: "NoVerbs",
138 Namespaced: true,
139 Kind: "NoVerbs",
140 Verbs: []string{},
141 ShortNames: []string{"b"},
142 Categories: []string{},
143 },
144 },
145 },
146 {
147 GroupVersion: "someothergroup/v1",
148 APIResources: []v1.APIResource{},
149 },
150 }
151 tf := cmdtesting.NewTestFactory().WithDiscoveryClient(dc)
152 defer tf.Cleanup()
153
154 testCases := []struct {
155 name string
156 commandSetupFn func(cmd *cobra.Command)
157 expectedOutput string
158 expectedInvalidations int
159 }{
160 {
161 name: "defaults",
162 commandSetupFn: func(cmd *cobra.Command) {},
163 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
164 bars v1 true Bar
165 foos f,fo v1 false Foo
166 bazzes b somegroup/v1 true Baz
167 `,
168 expectedInvalidations: 1,
169 },
170 {
171 name: "no headers",
172 commandSetupFn: func(cmd *cobra.Command) {
173 cmd.Flags().Set("no-headers", "true")
174 },
175 expectedOutput: `bars v1 true Bar
176 foos f,fo v1 false Foo
177 bazzes b somegroup/v1 true Baz
178 `,
179 expectedInvalidations: 1,
180 },
181 {
182 name: "specific api group",
183 commandSetupFn: func(cmd *cobra.Command) {
184 cmd.Flags().Set("api-group", "somegroup")
185 },
186 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
187 bazzes b somegroup/v1 true Baz
188 `,
189 expectedInvalidations: 1,
190 },
191 {
192 name: "output wide",
193 commandSetupFn: func(cmd *cobra.Command) {
194 cmd.Flags().Set("output", "wide")
195 },
196 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND VERBS CATEGORIES
197 bars v1 true Bar get,list,create
198 foos f,fo v1 false Foo get,list some-category
199 bazzes b somegroup/v1 true Baz get,list,create,delete some-category,another-category
200 `,
201 expectedInvalidations: 1,
202 },
203 {
204 name: "output name",
205 commandSetupFn: func(cmd *cobra.Command) {
206 cmd.Flags().Set("output", "name")
207 },
208 expectedOutput: `bars
209 foos
210 bazzes.somegroup
211 `,
212 expectedInvalidations: 1,
213 },
214 {
215 name: "namespaced",
216 commandSetupFn: func(cmd *cobra.Command) {
217 cmd.Flags().Set("namespaced", "true")
218 },
219 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
220 bars v1 true Bar
221 bazzes b somegroup/v1 true Baz
222 `,
223 expectedInvalidations: 1,
224 },
225 {
226 name: "single verb",
227 commandSetupFn: func(cmd *cobra.Command) {
228 cmd.Flags().Set("verbs", "create")
229 },
230 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
231 bars v1 true Bar
232 bazzes b somegroup/v1 true Baz
233 `,
234 expectedInvalidations: 1,
235 },
236 {
237 name: "multiple verbs",
238 commandSetupFn: func(cmd *cobra.Command) {
239 cmd.Flags().Set("verbs", "create,delete")
240 },
241 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
242 bazzes b somegroup/v1 true Baz
243 `,
244 expectedInvalidations: 1,
245 },
246 {
247 name: "single category",
248 commandSetupFn: func(cmd *cobra.Command) {
249 cmd.Flags().Set("categories", "some-category")
250 },
251 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
252 foos f,fo v1 false Foo
253 bazzes b somegroup/v1 true Baz
254 `,
255 expectedInvalidations: 1,
256 },
257 {
258 name: "multiple categories",
259 commandSetupFn: func(cmd *cobra.Command) {
260 cmd.Flags().Set("categories", "some-category,another-category")
261 },
262 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
263 bazzes b somegroup/v1 true Baz
264 `,
265 expectedInvalidations: 1,
266 },
267 {
268 name: "sort by name",
269 commandSetupFn: func(cmd *cobra.Command) {
270 cmd.Flags().Set("sort-by", "name")
271 },
272 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
273 bars v1 true Bar
274 bazzes b somegroup/v1 true Baz
275 foos f,fo v1 false Foo
276 `,
277 expectedInvalidations: 1,
278 },
279 {
280 name: "sort by kind",
281 commandSetupFn: func(cmd *cobra.Command) {
282 cmd.Flags().Set("sort-by", "kind")
283 },
284 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
285 bars v1 true Bar
286 bazzes b somegroup/v1 true Baz
287 foos f,fo v1 false Foo
288 `,
289 expectedInvalidations: 1,
290 },
291 {
292 name: "cached",
293 commandSetupFn: func(cmd *cobra.Command) {
294 cmd.Flags().Set("cached", "true")
295 },
296 expectedOutput: `NAME SHORTNAMES APIVERSION NAMESPACED KIND
297 bars v1 true Bar
298 foos f,fo v1 false Foo
299 bazzes b somegroup/v1 true Baz
300 `,
301 expectedInvalidations: 0,
302 },
303 }
304
305 for _, tc := range testCases {
306 t.Run(tc.name, func(tt *testing.T) {
307 dc.Invalidations = 0
308 ioStreams, _, out, errOut := genericiooptions.NewTestIOStreams()
309 cmd := NewCmdAPIResources(tf, ioStreams)
310 tc.commandSetupFn(cmd)
311 cmd.Run(cmd, []string{})
312
313 if errOut.Len() > 0 {
314 t.Fatalf("unexpected error output: %s", errOut.String())
315 }
316 if out.String() != tc.expectedOutput {
317 tt.Fatalf("unexpected output: %s\nexpected: %s", out.String(), tc.expectedOutput)
318 }
319 if dc.Invalidations != tc.expectedInvalidations {
320 tt.Fatalf("unexpected invalidations: %d, expected: %d", dc.Invalidations, tc.expectedInvalidations)
321 }
322 })
323 }
324 }
325
View as plain text