...

Source file src/k8s.io/cli-runtime/pkg/genericclioptions/jsonpath_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  	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