...

Source file src/sigs.k8s.io/structured-merge-diff/v4/internal/cli/main_test.go

Documentation: sigs.k8s.io/structured-merge-diff/v4/internal/cli

     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 cli
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"io/ioutil"
    23  	"path/filepath"
    24  	"testing"
    25  )
    26  
    27  type testCase struct {
    28  	options   Options
    29  	expectErr bool
    30  
    31  	// if present, verify that the output matches; otherwise, output is ignored.
    32  	expectedOutputPath string
    33  }
    34  
    35  func testdata(file string) string {
    36  	return filepath.Join("..", "testdata", file)
    37  }
    38  
    39  func TestValidate(t *testing.T) {
    40  	cases := []testCase{{
    41  		options: Options{
    42  			schemaPath:   testdata("schema.yaml"),
    43  			validatePath: testdata("schema.yaml"),
    44  		},
    45  	}, {
    46  		options: Options{
    47  			schemaPath:   testdata("schema.yaml"),
    48  			validatePath: testdata("bad-schema.yaml"),
    49  		},
    50  		expectErr: true,
    51  	}}
    52  
    53  	for _, tt := range cases {
    54  		tt := tt
    55  		t.Run(tt.options.validatePath, func(t *testing.T) {
    56  			op, err := tt.options.Resolve()
    57  			if err != nil {
    58  				t.Fatal(err)
    59  			}
    60  			var b bytes.Buffer
    61  			err = op.Execute(&b)
    62  			if tt.expectErr {
    63  				if err == nil {
    64  					t.Error("unexpected success")
    65  				}
    66  			} else if err != nil {
    67  				t.Errorf("unexpected error: %v", err)
    68  			}
    69  		})
    70  	}
    71  }
    72  
    73  func TestMerge(t *testing.T) {
    74  	cases := []testCase{{
    75  		options: Options{
    76  			schemaPath: testdata("schema.yaml"),
    77  			merge:      true,
    78  			lhsPath:    testdata("struct.yaml"),
    79  			rhsPath:    testdata("list.yaml"),
    80  		},
    81  	}, {
    82  		options: Options{
    83  			schemaPath: testdata("schema.yaml"),
    84  			merge:      true,
    85  			lhsPath:    testdata("bad-scalar.yaml"),
    86  			rhsPath:    testdata("scalar.yaml"),
    87  		},
    88  		expectedOutputPath: testdata("scalar.yaml"),
    89  	}, {
    90  		options: Options{
    91  			schemaPath: testdata("schema.yaml"),
    92  			merge:      true,
    93  			lhsPath:    testdata("scalar.yaml"),
    94  			rhsPath:    testdata("bad-scalar.yaml"),
    95  		},
    96  		expectedOutputPath: testdata("bad-scalar.yaml"),
    97  	}, {
    98  		options: Options{
    99  			schemaPath: testdata("schema.yaml"),
   100  			merge:      true,
   101  			lhsPath:    testdata("struct.yaml"),
   102  			rhsPath:    testdata("bad-schema.yaml"),
   103  		},
   104  		expectErr: true,
   105  	}}
   106  
   107  	for _, tt := range cases {
   108  		tt := tt
   109  		t.Run(tt.options.rhsPath, func(t *testing.T) {
   110  			op, err := tt.options.Resolve()
   111  			if err != nil {
   112  				t.Fatal(err)
   113  			}
   114  			var b bytes.Buffer
   115  			err = op.Execute(&b)
   116  			if tt.expectErr {
   117  				if err == nil {
   118  					t.Error("unexpected success")
   119  				}
   120  				return
   121  			} else if err != nil {
   122  				t.Fatalf("unexpected error: %v", err)
   123  			}
   124  			tt.checkOutput(t, b.Bytes())
   125  		})
   126  	}
   127  }
   128  
   129  func (tt *testCase) checkOutput(t *testing.T, got []byte) {
   130  	if tt.expectedOutputPath == "" {
   131  		return
   132  	}
   133  	want, err := ioutil.ReadFile(tt.expectedOutputPath)
   134  	if err != nil {
   135  		t.Fatalf("couldn't read expected output %q: %v", tt.expectedOutputPath, err)
   136  	}
   137  
   138  	if a, e := string(got), string(want); a != e {
   139  		t.Errorf("output didn't match expected output: got:\n%v\nwanted:\n%v\n", a, e)
   140  	}
   141  }
   142  
   143  func TestCompare(t *testing.T) {
   144  	cases := []testCase{{
   145  		options: Options{
   146  			schemaPath: testdata("schema.yaml"),
   147  			compare:    true,
   148  			lhsPath:    testdata("struct.yaml"),
   149  			rhsPath:    testdata("list.yaml"),
   150  		},
   151  	}, {
   152  		options: Options{
   153  			schemaPath: testdata("schema.yaml"),
   154  			compare:    true,
   155  			lhsPath:    testdata("scalar.yaml"),
   156  			rhsPath:    testdata("bad-scalar.yaml"),
   157  		},
   158  		// Yes, this is a golden data test but it's only one and it's
   159  		// just to make sure the command output stays sane. All the
   160  		// actual operations are unit tested.
   161  		expectedOutputPath: testdata("scalar-compare-output.txt"),
   162  	}, {
   163  		options: Options{
   164  			schemaPath: testdata("schema.yaml"),
   165  			compare:    true,
   166  			lhsPath:    testdata("struct.yaml"),
   167  			rhsPath:    testdata("bad-schema.yaml"),
   168  		},
   169  		expectErr: true,
   170  	}}
   171  
   172  	for _, tt := range cases {
   173  		tt := tt
   174  		t.Run(tt.options.rhsPath, func(t *testing.T) {
   175  			op, err := tt.options.Resolve()
   176  			if err != nil {
   177  				t.Fatal(err)
   178  			}
   179  			var b bytes.Buffer
   180  			err = op.Execute(&b)
   181  			if tt.expectErr {
   182  				if err == nil {
   183  					t.Error("unexpected success")
   184  				}
   185  			} else if err != nil {
   186  				t.Errorf("unexpected error: %v", err)
   187  			}
   188  			tt.checkOutput(t, b.Bytes())
   189  		})
   190  	}
   191  }
   192  
   193  func TestFieldSet(t *testing.T) {
   194  	cases := []testCase{{
   195  		options: Options{
   196  			schemaPath: testdata("k8s-schema.yaml"),
   197  			fieldset:   testdata("pod.yaml"),
   198  			typeName:   "io.k8s.api.core.v1.Pod",
   199  		},
   200  		expectedOutputPath: testdata("podset.json"),
   201  	}, {
   202  		options: Options{
   203  			schemaPath: testdata("k8s-schema.yaml"),
   204  			fieldset:   testdata("node.yaml"),
   205  			typeName:   "io.k8s.api.core.v1.Node",
   206  		},
   207  		expectedOutputPath: testdata("nodeset.json"),
   208  	}, {
   209  		options: Options{
   210  			schemaPath: testdata("k8s-schema.yaml"),
   211  			fieldset:   testdata("endpoints.yaml"),
   212  			typeName:   "io.k8s.api.core.v1.Endpoints",
   213  		},
   214  		expectedOutputPath: testdata("endpointsset.json"),
   215  	}, {
   216  		options: Options{
   217  			schemaPath: testdata("k8s-schema.yaml"),
   218  			fieldset:   testdata("prometheus-crd.yaml"),
   219  			typeName:   "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinition",
   220  		},
   221  		expectedOutputPath: testdata("prometheus-crdset.json"),
   222  	}}
   223  
   224  	for _, tt := range cases {
   225  		tt := tt
   226  		t.Run(tt.options.typeName, func(t *testing.T) {
   227  			op, err := tt.options.Resolve()
   228  			if err != nil {
   229  				t.Fatal(err)
   230  			}
   231  			var b bytes.Buffer
   232  			err = op.Execute(&b)
   233  			if err != nil {
   234  				t.Errorf("unexpected error: %v", err)
   235  			}
   236  			tt.checkOutput(t, b.Bytes())
   237  
   238  			// Test that round tripping through unstructured will preserve ordering
   239  			u := map[string]interface{}{}
   240  			err = json.Unmarshal(b.Bytes(), &u)
   241  			if err != nil {
   242  				t.Errorf("unexpected error: %v", err)
   243  			}
   244  			m, err := json.Marshal(&u)
   245  			if err != nil {
   246  				t.Errorf("unexpected error: %v", err)
   247  			}
   248  			tt.checkOutput(t, m)
   249  		})
   250  	}
   251  }
   252  

View as plain text