1
16
17 package genericclioptions
18
19 import (
20 "bytes"
21 "fmt"
22 "os"
23 "sort"
24 "strings"
25 "testing"
26
27 v1 "k8s.io/api/core/v1"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 )
30
31 func TestPrinterSupportsExpectedJSONPathFormats(t *testing.T) {
32 testObject := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
33
34 jsonpathFile, err := os.CreateTemp("", "printers_jsonpath_flags")
35 if err != nil {
36 t.Fatalf("unexpected error: %v", err)
37 }
38 defer func(tempFile *os.File) {
39 tempFile.Close()
40 os.Remove(tempFile.Name())
41 }(jsonpathFile)
42
43 fmt.Fprintf(jsonpathFile, "{ .metadata.name }\n")
44
45 testCases := []struct {
46 name string
47 outputFormat string
48 templateArg string
49 expectedError string
50 expectedParseError string
51 expectedOutput string
52 expectNoMatch bool
53 }{
54 {
55 name: "valid output format also containing the jsonpath argument succeeds",
56 outputFormat: "jsonpath={ .metadata.name }",
57 expectedOutput: "foo",
58 },
59 {
60 name: "valid output format and no --template argument results in an error",
61 outputFormat: "jsonpath",
62 expectedError: "template format specified but no template given",
63 },
64 {
65 name: "valid output format and --template argument succeeds",
66 outputFormat: "jsonpath",
67 templateArg: "{ .metadata.name }",
68 expectedOutput: "foo",
69 },
70 {
71 name: "valid jsonpath-as-json output format also containing argument succeeds",
72 outputFormat: "jsonpath-as-json={ .metadata.name }",
73 expectedOutput: "foo",
74 },
75 {
76 name: "valid jsonpath-as-json output format and no --template argument results in an error",
77 outputFormat: "jsonpath-as-json",
78 expectedError: "template format specified but no template given",
79 },
80 {
81 name: "valid jsonpath-as-json output format and --template argument succeeds",
82 outputFormat: "jsonpath-as-json",
83 templateArg: "{ .metadata.name }",
84 expectedOutput: "foo",
85 },
86 {
87 name: "jsonpath template file should match, and successfully return correct value",
88 outputFormat: "jsonpath-file",
89 templateArg: jsonpathFile.Name(),
90 expectedOutput: "foo",
91 },
92 {
93 name: "valid output format and invalid --template argument results in a parsing from the printer",
94 outputFormat: "jsonpath",
95 templateArg: "{invalid}",
96 expectedParseError: "unrecognized identifier invalid",
97 },
98 {
99 name: "no printer is matched on an invalid outputFormat",
100 outputFormat: "invalid",
101 expectNoMatch: true,
102 },
103 {
104 name: "jsonpath printer should not match on any other format supported by another printer",
105 outputFormat: "go-template",
106 expectNoMatch: true,
107 },
108 }
109
110 for _, tc := range testCases {
111 t.Run(tc.name, func(t *testing.T) {
112 templateArg := &tc.templateArg
113 if len(tc.templateArg) == 0 {
114 templateArg = nil
115 }
116
117 printFlags := JSONPathPrintFlags{
118 TemplateArgument: templateArg,
119 }
120 if !sort.StringsAreSorted(printFlags.AllowedFormats()) {
121 t.Fatalf("allowed formats are not sorted")
122 }
123
124 p, err := printFlags.ToPrinter(tc.outputFormat)
125 if tc.expectNoMatch {
126 if !IsNoCompatiblePrinterError(err) {
127 t.Fatalf("expected no printer matches for output format %q", tc.outputFormat)
128 }
129 return
130 }
131 if IsNoCompatiblePrinterError(err) {
132 t.Fatalf("expected to match template printer for output format %q", tc.outputFormat)
133 }
134
135 if len(tc.expectedError) > 0 {
136 if err == nil || !strings.Contains(err.Error(), tc.expectedError) {
137 t.Errorf("expecting error %q, got %v", tc.expectedError, err)
138 }
139 return
140 }
141 if err != nil {
142 t.Fatalf("unexpected error: %v", err)
143 }
144
145 out := bytes.NewBuffer([]byte{})
146 err = p.PrintObj(testObject, out)
147 if len(tc.expectedParseError) > 0 {
148 if err == nil || !strings.Contains(err.Error(), tc.expectedParseError) {
149 t.Errorf("expecting error %q, got %v", tc.expectedError, err)
150 }
151 return
152 }
153 if err != nil {
154 t.Errorf("unexpected error: %v", err)
155 }
156
157 if !strings.Contains(out.String(), tc.expectedOutput) {
158 t.Errorf("unexpected output: expecting %q, got %q", tc.expectedOutput, out.String())
159 }
160 })
161 }
162 }
163
164 func TestJSONPathPrinterDefaultsAllowMissingKeysToTrue(t *testing.T) {
165 testObject := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
166
167 allowMissingKeys := false
168
169 testCases := []struct {
170 name string
171 templateArg string
172 expectedOutput string
173 expectedError string
174 allowMissingKeys *bool
175 }{
176 {
177 name: "existing field does not error and returns expected value",
178 templateArg: "{ .metadata.name }",
179 expectedOutput: "foo",
180 allowMissingKeys: &allowMissingKeys,
181 },
182 {
183 name: "missing field does not error and returns an empty string since missing keys are allowed by default",
184 templateArg: "{ .metadata.missing }",
185 expectedOutput: "",
186 allowMissingKeys: nil,
187 },
188 {
189 name: "missing field returns expected error if field is missing and allowMissingKeys is explicitly set to false",
190 templateArg: "{ .metadata.missing }",
191 expectedError: "error executing jsonpath",
192 allowMissingKeys: &allowMissingKeys,
193 },
194 }
195
196 for _, tc := range testCases {
197 t.Run(tc.name, func(t *testing.T) {
198 printFlags := JSONPathPrintFlags{
199 TemplateArgument: &tc.templateArg,
200 AllowMissingKeys: tc.allowMissingKeys,
201 }
202 if !sort.StringsAreSorted(printFlags.AllowedFormats()) {
203 t.Fatalf("allowed formats are not sorted")
204 }
205
206 outputFormat := "jsonpath"
207 p, err := printFlags.ToPrinter(outputFormat)
208 if IsNoCompatiblePrinterError(err) {
209 t.Fatalf("expected to match template printer for output format %q", outputFormat)
210 }
211 if err != nil {
212 t.Fatalf("unexpected error: %v", err)
213 }
214
215 out := bytes.NewBuffer([]byte{})
216 err = p.PrintObj(testObject, out)
217
218 if len(tc.expectedError) > 0 {
219 if err == nil || !strings.Contains(err.Error(), tc.expectedError) {
220 t.Errorf("expecting error %q, got %v", tc.expectedError, err)
221 }
222 return
223 }
224 if err != nil {
225 t.Errorf("unexpected error: %v", err)
226 }
227
228 if len(out.String()) != len(tc.expectedOutput) {
229 t.Errorf("unexpected output: expecting %q, got %q", tc.expectedOutput, out.String())
230 }
231 })
232 }
233 }
234
View as plain text