github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/common/expand_test.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package common
    21  
    22  import (
    23  	"testing"
    24  
    25  	corev1 "k8s.io/api/core/v1"
    26  )
    27  
    28  // forked from k8s.io/kubernetes/third_party/forked/golang/expansion
    29  func TestMapReference(t *testing.T) {
    30  	envs := []corev1.EnvVar{
    31  		{
    32  			Name:  "FOO",
    33  			Value: "bar",
    34  		},
    35  		{
    36  			Name:  "ZOO",
    37  			Value: "$(FOO)-1",
    38  		},
    39  		{
    40  			Name:  "BLU",
    41  			Value: "$(ZOO)-2",
    42  		},
    43  	}
    44  
    45  	declaredEnv := map[string]string{
    46  		"FOO": "bar",
    47  		"ZOO": "$(FOO)-1",
    48  		"BLU": "$(ZOO)-2",
    49  	}
    50  
    51  	serviceEnv := map[string]string{}
    52  
    53  	mapping := MappingFuncFor(declaredEnv, serviceEnv)
    54  
    55  	for _, env := range envs {
    56  		declaredEnv[env.Name] = Expand(env.Value, mapping)
    57  	}
    58  
    59  	expectedEnv := map[string]string{
    60  		"FOO": "bar",
    61  		"ZOO": "bar-1",
    62  		"BLU": "bar-1-2",
    63  	}
    64  
    65  	for k, v := range expectedEnv {
    66  		if e, a := v, declaredEnv[k]; e != a {
    67  			t.Errorf("Expected %v, got %v", e, a)
    68  		} else {
    69  			delete(declaredEnv, k)
    70  		}
    71  	}
    72  
    73  	if len(declaredEnv) != 0 {
    74  		t.Errorf("Unexpected keys in declared env: %v", declaredEnv)
    75  	}
    76  }
    77  
    78  func TestMapping(t *testing.T) {
    79  	context := map[string]string{
    80  		"VAR_A":     "A",
    81  		"VAR_B":     "B",
    82  		"VAR_C":     "C",
    83  		"VAR_REF":   "$(VAR_A)",
    84  		"VAR_EMPTY": "",
    85  	}
    86  	mapping := MappingFuncFor(context)
    87  
    88  	doExpansionTest(t, mapping)
    89  }
    90  
    91  func TestMappingDual(t *testing.T) {
    92  	context := map[string]string{
    93  		"VAR_A":     "A",
    94  		"VAR_EMPTY": "",
    95  	}
    96  	context2 := map[string]string{
    97  		"VAR_B":   "B",
    98  		"VAR_C":   "C",
    99  		"VAR_REF": "$(VAR_A)",
   100  	}
   101  	mapping := MappingFuncFor(context, context2)
   102  
   103  	doExpansionTest(t, mapping)
   104  }
   105  
   106  func doExpansionTest(t *testing.T, mapping func(string) string) {
   107  	cases := []struct {
   108  		name     string
   109  		input    string
   110  		expected string
   111  	}{
   112  		{
   113  			name:     "whole string",
   114  			input:    "$(VAR_A)",
   115  			expected: "A",
   116  		},
   117  		{
   118  			name:     "repeat",
   119  			input:    "$(VAR_A)-$(VAR_A)",
   120  			expected: "A-A",
   121  		},
   122  		{
   123  			name:     "beginning",
   124  			input:    "$(VAR_A)-1",
   125  			expected: "A-1",
   126  		},
   127  		{
   128  			name:     "middle",
   129  			input:    "___$(VAR_B)___",
   130  			expected: "___B___",
   131  		},
   132  		{
   133  			name:     "end",
   134  			input:    "___$(VAR_C)",
   135  			expected: "___C",
   136  		},
   137  		{
   138  			name:     "compound",
   139  			input:    "$(VAR_A)_$(VAR_B)_$(VAR_C)",
   140  			expected: "A_B_C",
   141  		},
   142  		{
   143  			name:     "escape & expand",
   144  			input:    "$$(VAR_B)_$(VAR_A)",
   145  			expected: "$(VAR_B)_A",
   146  		},
   147  		{
   148  			name:     "compound escape",
   149  			input:    "$$(VAR_A)_$$(VAR_B)",
   150  			expected: "$(VAR_A)_$(VAR_B)",
   151  		},
   152  		{
   153  			name:     "mixed in escapes",
   154  			input:    "f000-$$VAR_A",
   155  			expected: "f000-$VAR_A",
   156  		},
   157  		{
   158  			name:     "backslash escape ignored",
   159  			input:    "foo\\$(VAR_C)bar",
   160  			expected: "foo\\Cbar",
   161  		},
   162  		{
   163  			name:     "backslash escape ignored",
   164  			input:    "foo\\\\$(VAR_C)bar",
   165  			expected: "foo\\\\Cbar",
   166  		},
   167  		{
   168  			name:     "lots of backslashes",
   169  			input:    "foo\\\\\\\\$(VAR_A)bar",
   170  			expected: "foo\\\\\\\\Abar",
   171  		},
   172  		{
   173  			name:     "nested var references",
   174  			input:    "$(VAR_A$(VAR_B))",
   175  			expected: "$(VAR_A$(VAR_B))",
   176  		},
   177  		{
   178  			name:     "nested var references second type",
   179  			input:    "$(VAR_A$(VAR_B)",
   180  			expected: "$(VAR_A$(VAR_B)",
   181  		},
   182  		{
   183  			name:     "value is a reference",
   184  			input:    "$(VAR_REF)",
   185  			expected: "$(VAR_A)",
   186  		},
   187  		{
   188  			name:     "value is a reference x 2",
   189  			input:    "%%$(VAR_REF)--$(VAR_REF)%%",
   190  			expected: "%%$(VAR_A)--$(VAR_A)%%",
   191  		},
   192  		{
   193  			name:     "empty var",
   194  			input:    "foo$(VAR_EMPTY)bar",
   195  			expected: "foobar",
   196  		},
   197  		{
   198  			name:     "unterminated expression",
   199  			input:    "foo$(VAR_Awhoops!",
   200  			expected: "foo$(VAR_Awhoops!",
   201  		},
   202  		{
   203  			name:     "expression without operator",
   204  			input:    "f00__(VAR_A)__",
   205  			expected: "f00__(VAR_A)__",
   206  		},
   207  		{
   208  			name:     "shell special vars pass through",
   209  			input:    "$?_boo_$!",
   210  			expected: "$?_boo_$!",
   211  		},
   212  		{
   213  			name:     "bare operators are ignored",
   214  			input:    "$VAR_A",
   215  			expected: "$VAR_A",
   216  		},
   217  		{
   218  			name:     "undefined vars are passed through",
   219  			input:    "$(VAR_DNE)",
   220  			expected: "$(VAR_DNE)",
   221  		},
   222  		{
   223  			name:     "multiple (even) operators, var undefined",
   224  			input:    "$$$$$$(BIG_MONEY)",
   225  			expected: "$$$(BIG_MONEY)",
   226  		},
   227  		{
   228  			name:     "multiple (even) operators, var defined",
   229  			input:    "$$$$$$(VAR_A)",
   230  			expected: "$$$(VAR_A)",
   231  		},
   232  		{
   233  			name:     "multiple (odd) operators, var undefined",
   234  			input:    "$$$$$$$(GOOD_ODDS)",
   235  			expected: "$$$$(GOOD_ODDS)",
   236  		},
   237  		{
   238  			name:     "multiple (odd) operators, var defined",
   239  			input:    "$$$$$$$(VAR_A)",
   240  			expected: "$$$A",
   241  		},
   242  		{
   243  			name:     "missing open expression",
   244  			input:    "$VAR_A)",
   245  			expected: "$VAR_A)",
   246  		},
   247  		{
   248  			name:     "shell syntax ignored",
   249  			input:    "${VAR_A}",
   250  			expected: "${VAR_A}",
   251  		},
   252  		{
   253  			name:     "trailing incomplete expression not consumed",
   254  			input:    "$(VAR_B)_______$(A",
   255  			expected: "B_______$(A",
   256  		},
   257  		{
   258  			name:     "trailing incomplete expression, no content, is not consumed",
   259  			input:    "$(VAR_C)_______$(",
   260  			expected: "C_______$(",
   261  		},
   262  		{
   263  			name:     "operator at end of input string is preserved",
   264  			input:    "$(VAR_A)foobarzab$",
   265  			expected: "Afoobarzab$",
   266  		},
   267  		{
   268  			name:     "shell escaped incomplete expr",
   269  			input:    "foo-\\$(VAR_A",
   270  			expected: "foo-\\$(VAR_A",
   271  		},
   272  		{
   273  			name:     "lots of $( in middle",
   274  			input:    "--$($($($($--",
   275  			expected: "--$($($($($--",
   276  		},
   277  		{
   278  			name:     "lots of $( in beginning",
   279  			input:    "$($($($($--foo$(",
   280  			expected: "$($($($($--foo$(",
   281  		},
   282  		{
   283  			name:     "lots of $( at end",
   284  			input:    "foo0--$($($($(",
   285  			expected: "foo0--$($($($(",
   286  		},
   287  		{
   288  			name:     "escaped operators in variable names are not escaped",
   289  			input:    "$(foo$$var)",
   290  			expected: "$(foo$$var)",
   291  		},
   292  		{
   293  			name:     "newline not expanded",
   294  			input:    "\n",
   295  			expected: "\n",
   296  		},
   297  	}
   298  
   299  	for _, tc := range cases {
   300  		expanded := Expand(tc.input, mapping)
   301  		if e, a := tc.expected, expanded; e != a {
   302  			t.Errorf("%v: expected %q, got %q", tc.name, e, a)
   303  		}
   304  	}
   305  }