istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/util/yaml_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package util
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  )
    21  
    22  func TestToYAML(t *testing.T) {
    23  	tests := []struct {
    24  		desc        string
    25  		inVals      any
    26  		expectedOut string
    27  	}{
    28  		{
    29  			desc: "valid-yaml",
    30  			inVals: map[string]any{
    31  				"foo": "bar",
    32  				"yo": map[string]any{
    33  					"istio": "bar",
    34  				},
    35  			},
    36  			expectedOut: `foo: bar
    37  yo:
    38    istio: bar
    39  `,
    40  		},
    41  		{
    42  			desc: "alphabetical",
    43  			inVals: map[string]any{
    44  				"foo": "yaml",
    45  				"abc": "f",
    46  			},
    47  			expectedOut: `abc: f
    48  foo: yaml
    49  `,
    50  		},
    51  		{
    52  			desc:        "expected-err-nil",
    53  			inVals:      nil,
    54  			expectedOut: "null\n",
    55  		},
    56  	}
    57  	for _, tt := range tests {
    58  		t.Run(tt.desc, func(t *testing.T) {
    59  			if got := ToYAML(tt.inVals); got != tt.expectedOut {
    60  				t.Errorf("%s: expected out %v got %s", tt.desc, tt.expectedOut, got)
    61  			}
    62  		})
    63  	}
    64  }
    65  
    66  func TestOverlayTrees(t *testing.T) {
    67  	tests := []struct {
    68  		desc            string
    69  		inBase          map[string]any
    70  		inOverlays      map[string]any
    71  		expectedOverlay map[string]any
    72  		expectedErr     error
    73  	}{
    74  		{
    75  			desc: "overlay-valid",
    76  			inBase: map[string]any{
    77  				"foo": "bar",
    78  				"baz": "naz",
    79  			},
    80  			inOverlays: map[string]any{
    81  				"foo": "laz",
    82  			},
    83  			expectedOverlay: map[string]any{
    84  				"baz": "naz",
    85  				"foo": "laz",
    86  			},
    87  			expectedErr: nil,
    88  		},
    89  		{
    90  			desc: "overlay-key-does-not-exist",
    91  			inBase: map[string]any{
    92  				"foo": "bar",
    93  				"baz": "naz",
    94  			},
    95  			inOverlays: map[string]any{
    96  				"i-dont-exist": "i-really-dont-exist",
    97  			},
    98  			expectedOverlay: map[string]any{
    99  				"baz":          "naz",
   100  				"foo":          "bar",
   101  				"i-dont-exist": "i-really-dont-exist",
   102  			},
   103  			expectedErr: nil,
   104  		},
   105  		{
   106  			desc: "remove-key-val",
   107  			inBase: map[string]any{
   108  				"foo": "bar",
   109  			},
   110  			inOverlays: map[string]any{
   111  				"foo": nil,
   112  			},
   113  			expectedOverlay: map[string]any{},
   114  			expectedErr:     nil,
   115  		},
   116  	}
   117  	for _, tt := range tests {
   118  		t.Run(tt.desc, func(t *testing.T) {
   119  			if gotOverlays, err := OverlayTrees(tt.inBase, tt.inOverlays); !reflect.DeepEqual(gotOverlays, tt.expectedOverlay) ||
   120  				((err != nil && tt.expectedErr == nil) || (err == nil && tt.expectedErr != nil)) {
   121  				t.Errorf("%s: expected overlay & err %v %v got %v %v", tt.desc, tt.expectedOverlay, tt.expectedErr,
   122  					gotOverlays, err)
   123  			}
   124  		})
   125  	}
   126  }
   127  
   128  func TestOverlayYAML(t *testing.T) {
   129  	tests := []struct {
   130  		desc    string
   131  		base    string
   132  		overlay string
   133  		expect  string
   134  		err     error
   135  	}{
   136  		{
   137  			desc: "overlay-yaml",
   138  			base: `foo: bar
   139  yo: lo
   140  `,
   141  			overlay: `yo: go`,
   142  			expect: `foo: bar
   143  yo: go
   144  `,
   145  			err: nil,
   146  		},
   147  		{
   148  			desc:    "combine-yaml",
   149  			base:    `foo: bar`,
   150  			overlay: `baz: razmatazz`,
   151  			expect: `baz: razmatazz
   152  foo: bar
   153  `,
   154  			err: nil,
   155  		},
   156  		{
   157  			desc:    "blank",
   158  			base:    `R#)*J#FN`,
   159  			overlay: `FM#)M#F(*#M`,
   160  			expect:  "FM#)M#F(*#M\n",
   161  			err:     nil,
   162  		},
   163  	}
   164  	for _, tt := range tests {
   165  		t.Run(tt.desc, func(t *testing.T) {
   166  			if got, err := OverlayYAML(tt.base, tt.overlay); got != tt.expect || ((tt.err != nil && err == nil) || (tt.err == nil && err != nil)) {
   167  				t.Errorf("%s: expected overlay&err %v %v got %v %v", tt.desc, tt.expect, tt.err, got, err)
   168  			}
   169  		})
   170  	}
   171  }
   172  
   173  func TestYAMLDiff(t *testing.T) {
   174  	tests := []struct {
   175  		desc   string
   176  		diff1  string
   177  		diff2  string
   178  		expect string
   179  	}{
   180  		{
   181  			desc: "1-line-diff",
   182  			diff1: `hola: yo
   183  foo: bar
   184  goo: tar
   185  `,
   186  			diff2: `hola: yo
   187  foo: bar
   188  notgoo: nottar
   189  `,
   190  			expect: ` foo: bar
   191  -goo: tar
   192   hola: yo
   193  +notgoo: nottar
   194   `,
   195  		},
   196  		{
   197  			desc:   "no-diff",
   198  			diff1:  `foo: bar`,
   199  			diff2:  `foo: bar`,
   200  			expect: ``,
   201  		},
   202  		{
   203  			desc:   "invalid-yaml",
   204  			diff1:  `Ij#**#f#`,
   205  			diff2:  `fm*##)n`,
   206  			expect: "error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}",
   207  		},
   208  	}
   209  	for _, tt := range tests {
   210  		t.Run(tt.desc, func(t *testing.T) {
   211  			if got := YAMLDiff(tt.diff1, tt.diff2); got != tt.expect {
   212  				t.Errorf("%s: expect %v got %v", tt.desc, tt.expect, got)
   213  			}
   214  		})
   215  	}
   216  }
   217  
   218  func TestMultipleYAMLDiff(t *testing.T) {
   219  	tests := []struct {
   220  		desc   string
   221  		diff1  string
   222  		diff2  string
   223  		expect string
   224  	}{
   225  		{
   226  			desc: "1-line-diff",
   227  			diff1: `hola: yo
   228  foo: bar
   229  goo: tar
   230  ---
   231  hola: yo1
   232  foo: bar1
   233  goo: tar1
   234  `,
   235  			diff2: `hola: yo
   236  foo: bar
   237  notgoo: nottar
   238  `,
   239  			expect: ` foo: bar
   240  -goo: tar
   241   hola: yo
   242  +notgoo: nottar
   243   
   244  -foo: bar1
   245  -goo: tar1
   246  -hola: yo1
   247  +{}
   248   `,
   249  		},
   250  		{
   251  			desc: "no-diff",
   252  			diff1: `foo: bar
   253  ---
   254  foo: bar1
   255  `,
   256  			diff2: `foo: bar
   257  ---
   258  foo: bar1
   259  `,
   260  			expect: ``,
   261  		},
   262  	}
   263  	for _, tt := range tests {
   264  		t.Run(tt.desc, func(t *testing.T) {
   265  			if got := YAMLDiff(tt.diff1, tt.diff2); got != tt.expect {
   266  				t.Errorf("%s: expect %v got %v", tt.desc, tt.expect, got)
   267  			}
   268  		})
   269  	}
   270  }
   271  
   272  func TestIsYAMLEqual(t *testing.T) {
   273  	tests := []struct {
   274  		desc   string
   275  		in1    string
   276  		in2    string
   277  		expect bool
   278  	}{
   279  		{
   280  			desc:   "yaml-equal",
   281  			in1:    `foo: bar`,
   282  			in2:    `foo: bar`,
   283  			expect: true,
   284  		},
   285  		{
   286  			desc:   "bad-yaml-1",
   287  			in1:    "O#JF*()#",
   288  			in2:    `foo: bar`,
   289  			expect: false,
   290  		},
   291  		{
   292  			desc:   "bad-yaml-2",
   293  			in1:    `foo: bar`,
   294  			in2:    "#OHJ*#()F",
   295  			expect: false,
   296  		},
   297  		{
   298  			desc: "yaml-not-equal",
   299  			in1: `zinc: iron
   300  stoichiometry: avagadro
   301  `,
   302  			in2: `i-swear: i-am
   303  definitely-not: in1
   304  `,
   305  			expect: false,
   306  		},
   307  	}
   308  	for _, tt := range tests {
   309  		t.Run(tt.desc, func(t *testing.T) {
   310  			if got := IsYAMLEqual(tt.in1, tt.in2); got != tt.expect {
   311  				t.Errorf("%v: got %v want %v", tt.desc, got, tt.expect)
   312  			}
   313  		})
   314  	}
   315  }
   316  
   317  func TestIsYAMLEmpty(t *testing.T) {
   318  	tests := []struct {
   319  		desc   string
   320  		in     string
   321  		expect bool
   322  	}{
   323  		{
   324  			desc:   "completely-empty",
   325  			in:     "",
   326  			expect: true,
   327  		},
   328  		{
   329  			desc: "comment-logically-empty",
   330  			in: `# this is a comment
   331  # this is another comment that serves no purpose
   332  # (like all comments usually do)
   333  `,
   334  			expect: true,
   335  		},
   336  		{
   337  			desc:   "start-yaml",
   338  			in:     `--- I dont mean anything`,
   339  			expect: true,
   340  		},
   341  		{
   342  			desc: "combine-comments-and-yaml",
   343  			in: `#this is another comment
   344  foo: bar
   345  # ^ that serves purpose
   346  `,
   347  			expect: false,
   348  		},
   349  		{
   350  			desc:   "yaml-not-empty",
   351  			in:     `foo: bar`,
   352  			expect: false,
   353  		},
   354  	}
   355  	for _, tt := range tests {
   356  		t.Run(tt.desc, func(t *testing.T) {
   357  			if got := IsYAMLEmpty(tt.in); got != tt.expect {
   358  				t.Errorf("%v: expect %v got %v", tt.desc, tt.expect, got)
   359  			}
   360  		})
   361  	}
   362  }