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