...

Source file src/k8s.io/cli-runtime/pkg/genericclioptions/template_flags_test.go

Documentation: k8s.io/cli-runtime/pkg/genericclioptions

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    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