github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controllerutil/cue_value_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 controllerutil
    21  
    22  import (
    23  	"strings"
    24  	"testing"
    25  )
    26  
    27  func TestNewCUETplFromPath(t *testing.T) {
    28  	_, err := NewCUETplFromPath("cue.cue")
    29  	if err == nil {
    30  		t.Error("Expected error to fall through, got err")
    31  	}
    32  }
    33  
    34  func TestNewCUETplFromBytes(t *testing.T) {
    35  	_, err := NewCUETplFromBytes([]byte(""), nil)
    36  	if err != nil {
    37  		t.Error("Expected error to fall through, got nil")
    38  	}
    39  }
    40  
    41  func TestNewCUETpl(t *testing.T) {
    42  	NewCUETpl([]byte{})
    43  }
    44  
    45  type testCUEInput struct {
    46  	Replicas int `json:"replicas"`
    47  }
    48  
    49  type testCUEInputIntOmitEmpty struct {
    50  	Replicas int `json:"replicas,omitempty"`
    51  }
    52  
    53  type testCUEInputBoolOmitEmpty struct {
    54  	Flag bool `json:"flag,omitempty"`
    55  }
    56  
    57  // This test shows that the omitempty tag should be used with much care if the field
    58  // is used in cue template.
    59  func TestCUE(t *testing.T) {
    60  	cueTplIntJSON := `
    61  input: {
    62  	replicas:       int32
    63  }
    64  output: {
    65  	replicas:       input.replicas
    66  }
    67  `
    68  	cueTplBoolJSON := `
    69  input: {
    70  	flag:       bool
    71  }
    72  output: {
    73  	flag:       input.flag
    74  }
    75  `
    76  
    77  	testCases := []struct {
    78  		name  string
    79  		tpl   string
    80  		input any
    81  		err   string
    82  	}{{
    83  		name:  "testCUEInput",
    84  		tpl:   cueTplIntJSON,
    85  		input: testCUEInput{Replicas: 0},
    86  	}, {
    87  		name:  "testCUEInputIntOmitEmptyWithNonZeroValue",
    88  		tpl:   cueTplIntJSON,
    89  		input: testCUEInputIntOmitEmpty{Replicas: 1},
    90  	}, {
    91  		name:  "testCUEInputIntOmitEmpty",
    92  		tpl:   cueTplIntJSON,
    93  		input: testCUEInputIntOmitEmpty{Replicas: 0},
    94  		err:   "marshal error",
    95  	}, {
    96  		name:  "testCUEInputBoolOmitEmptyWithNonZeroValue",
    97  		tpl:   cueTplBoolJSON,
    98  		input: testCUEInputBoolOmitEmpty{Flag: true},
    99  	}, {
   100  		name:  "testCUEInputBoolOmitEmpty",
   101  		tpl:   cueTplBoolJSON,
   102  		input: testCUEInputBoolOmitEmpty{Flag: false},
   103  		err:   "marshal error",
   104  	}}
   105  
   106  	for _, tc := range testCases {
   107  		cueTpl := NewCUETpl([]byte(tc.tpl))
   108  		cueValue := NewCUEBuilder(*cueTpl)
   109  
   110  		if err := cueValue.FillObj("input", tc.input); err != nil {
   111  			t.Error("Expected non-nil input error")
   112  		}
   113  		_, err := cueValue.Lookup("output")
   114  		checkErr(t, err, tc.err, tc.name)
   115  	}
   116  }
   117  
   118  func TestCUEFillObj(t *testing.T) {
   119  	cueTplIntJSON := `
   120  	input: {
   121  		replicas:       int32
   122  	}
   123  	output: {
   124  		replicas:       input.replicas
   125  	}
   126  	`
   127  
   128  	testCases := []struct {
   129  		name  string
   130  		tpl   string
   131  		input any
   132  		err   string
   133  	}{
   134  		{
   135  			name:  "testCUEInvalidInput",
   136  			tpl:   cueTplIntJSON,
   137  			input: make(chan int),
   138  			err:   "unsupported type",
   139  		},
   140  		{
   141  			name:  "testCUEInput",
   142  			tpl:   cueTplIntJSON,
   143  			input: testCUEInput{Replicas: 0},
   144  		},
   145  	}
   146  
   147  	for _, tc := range testCases {
   148  		cueTpl := NewCUETpl([]byte(tc.tpl))
   149  		cueValue := NewCUEBuilder(*cueTpl)
   150  
   151  		err := cueValue.FillObj("input", tc.input)
   152  		checkErr(t, err, tc.err, tc.name)
   153  	}
   154  }
   155  
   156  func TestCUEFill(t *testing.T) {
   157  	cueTplIntJSON := `
   158  	input: {
   159  		replicas:       int32
   160  	}
   161  	output: {
   162  		replicas:       input.replicas
   163  	}
   164  	`
   165  
   166  	testCases := []struct {
   167  		name  string
   168  		tpl   string
   169  		input string
   170  		err   string
   171  	}{
   172  		{
   173  			name:  "testCUEInvalidJSON",
   174  			tpl:   cueTplIntJSON,
   175  			input: "",
   176  			err:   "invalid JSON",
   177  		},
   178  		{
   179  			name:  "testCUEInput",
   180  			input: `{ "replicas": 0}`,
   181  			tpl:   cueTplIntJSON,
   182  		},
   183  	}
   184  
   185  	for _, tc := range testCases {
   186  		cueTpl := NewCUETpl([]byte(tc.tpl))
   187  		cueValue := NewCUEBuilder(*cueTpl)
   188  
   189  		err := cueValue.Fill("input", []byte(tc.input))
   190  		checkErr(t, err, tc.err, tc.name)
   191  	}
   192  }
   193  
   194  func checkErr(t *testing.T, err error, str, name string) bool {
   195  	t.Helper()
   196  	if err == nil {
   197  		if str != "" {
   198  			t.Errorf(`err:%s: got ""; want %q`, name, str)
   199  		}
   200  		return true
   201  	}
   202  	return checkFailed(t, err, str, name)
   203  }
   204  
   205  func checkFailed(t *testing.T, err error, str, name string) bool {
   206  	t.Helper()
   207  	if err != nil {
   208  		got := err.Error()
   209  		if str == "" {
   210  			t.Fatalf(`err:%s: got %q; want ""`, name, got)
   211  		}
   212  		if !strings.Contains(got, str) {
   213  			t.Errorf(`err:%s: got %q; want %q`, name, got, str)
   214  		}
   215  		return false
   216  	}
   217  	return true
   218  }