sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/client/config/reader_viper_test.go (about)

     1  /*
     2  Copyright 2019 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 config
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"os"
    25  	"path/filepath"
    26  	"strings"
    27  	"testing"
    28  
    29  	. "github.com/onsi/gomega"
    30  )
    31  
    32  func Test_viperReader_Init(t *testing.T) {
    33  	g := NewWithT(t)
    34  
    35  	// Change HOME dir and do not specify config file
    36  	// (.cluster-api/clusterctl) in it.
    37  	clusterctlHomeDir, err := os.MkdirTemp("", "clusterctl-default")
    38  	g.Expect(err).ToNot(HaveOccurred())
    39  	defer os.RemoveAll(clusterctlHomeDir)
    40  
    41  	dir, err := os.MkdirTemp("", "clusterctl")
    42  	g.Expect(err).ToNot(HaveOccurred())
    43  	defer os.RemoveAll(dir)
    44  
    45  	configFile := filepath.Join(dir, "clusterctl.yaml")
    46  	g.Expect(os.WriteFile(configFile, []byte("bar: bar"), 0600)).To(Succeed())
    47  
    48  	configFileBadContents := filepath.Join(dir, "clusterctl-bad.yaml")
    49  	g.Expect(os.WriteFile(configFileBadContents, []byte("bad-contents"), 0600)).To(Succeed())
    50  
    51  	// To test the remote config file
    52  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
    53  		w.Header().Set("Content-Type", "text/plain")
    54  		_, err := w.Write([]byte("bar: bar"))
    55  		g.Expect(err).ToNot(HaveOccurred())
    56  	}))
    57  	defer ts.Close()
    58  
    59  	// To test the remote config file when fails to fetch
    60  	tsFail := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
    61  		w.WriteHeader(http.StatusNotFound)
    62  	}))
    63  	defer tsFail.Close()
    64  
    65  	tests := []struct {
    66  		name       string
    67  		configPath string
    68  		configDirs []string
    69  		expectErr  bool
    70  	}{
    71  		{
    72  			name:       "reads in config successfully",
    73  			configPath: configFile,
    74  			configDirs: []string{clusterctlHomeDir},
    75  			expectErr:  false,
    76  		},
    77  		{
    78  			name:       "returns error for invalid config file path",
    79  			configPath: "do-not-exist.yaml",
    80  			configDirs: []string{clusterctlHomeDir},
    81  			expectErr:  true,
    82  		},
    83  		{
    84  			name:       "does not return error if default file doesn't exist",
    85  			configPath: "",
    86  			configDirs: []string{clusterctlHomeDir},
    87  			expectErr:  false,
    88  		},
    89  		{
    90  			name:       "returns error for malformed config",
    91  			configPath: configFileBadContents,
    92  			configDirs: []string{clusterctlHomeDir},
    93  			expectErr:  true,
    94  		},
    95  		{
    96  			name:       "reads in config from remote successfully",
    97  			configPath: ts.URL,
    98  			configDirs: []string{clusterctlHomeDir},
    99  			expectErr:  false,
   100  		},
   101  		{
   102  			name:       "fail to read remote config",
   103  			configPath: tsFail.URL,
   104  			configDirs: []string{clusterctlHomeDir},
   105  			expectErr:  true,
   106  		},
   107  	}
   108  
   109  	for _, tt := range tests {
   110  		t.Run(tt.name, func(t *testing.T) {
   111  			gg := NewWithT(t)
   112  
   113  			ctx := context.Background()
   114  
   115  			v, _ := newViperReader(injectConfigPaths(tt.configDirs))
   116  			if tt.expectErr {
   117  				gg.Expect(v.Init(ctx, tt.configPath)).ToNot(Succeed())
   118  				return
   119  			}
   120  			gg.Expect(v.Init(ctx, tt.configPath)).To(Succeed())
   121  		})
   122  	}
   123  }
   124  
   125  func Test_viperReader_Get(t *testing.T) {
   126  	g := NewWithT(t)
   127  
   128  	dir, err := os.MkdirTemp("", "clusterctl")
   129  	g.Expect(err).ToNot(HaveOccurred())
   130  	defer os.RemoveAll(dir)
   131  
   132  	_ = os.Setenv("FOO", "foo")
   133  
   134  	configFile := filepath.Join(dir, "clusterctl.yaml")
   135  	g.Expect(os.WriteFile(configFile, []byte("bar: bar"), 0600)).To(Succeed())
   136  
   137  	type args struct {
   138  		key string
   139  	}
   140  	tests := []struct {
   141  		name    string
   142  		args    args
   143  		want    string
   144  		wantErr bool
   145  	}{
   146  		{
   147  			name: "Read from env",
   148  			args: args{
   149  				key: "FOO",
   150  			},
   151  			want:    "foo",
   152  			wantErr: false,
   153  		},
   154  		{
   155  			name: "Read from file",
   156  			args: args{
   157  				key: "BAR",
   158  			},
   159  			want:    "bar",
   160  			wantErr: false,
   161  		},
   162  		{
   163  			name: "Fails if missing",
   164  			args: args{
   165  				key: "BAZ",
   166  			},
   167  			want:    "",
   168  			wantErr: true,
   169  		},
   170  	}
   171  	for _, tt := range tests {
   172  		t.Run(tt.name, func(t *testing.T) {
   173  			gs := NewWithT(t)
   174  
   175  			ctx := context.Background()
   176  
   177  			v, _ := newViperReader(injectConfigPaths([]string{dir}))
   178  
   179  			gs.Expect(v.Init(ctx, configFile)).To(Succeed())
   180  
   181  			got, err := v.Get(tt.args.key)
   182  			if tt.wantErr {
   183  				gs.Expect(err).To(HaveOccurred())
   184  				return
   185  			}
   186  
   187  			gs.Expect(err).ToNot(HaveOccurred())
   188  			gs.Expect(got).To(Equal(tt.want))
   189  		})
   190  	}
   191  }
   192  
   193  func Test_viperReader_GetWithoutDefaultConfig(t *testing.T) {
   194  	g := NewWithT(t)
   195  
   196  	ctx := context.Background()
   197  
   198  	dir, err := os.MkdirTemp("", "clusterctl")
   199  	g.Expect(err).ToNot(HaveOccurred())
   200  	defer os.RemoveAll(dir)
   201  
   202  	_ = os.Setenv("FOO_FOO", "bar")
   203  
   204  	v, err := newViperReader(injectConfigPaths([]string{dir}))
   205  	g.Expect(err).ToNot(HaveOccurred())
   206  	g.Expect(v.Init(ctx, "")).To(Succeed())
   207  
   208  	got, err := v.Get("FOO_FOO")
   209  	g.Expect(err).ToNot(HaveOccurred())
   210  	g.Expect(got).To(Equal("bar"))
   211  }
   212  
   213  func Test_viperReader_Set(t *testing.T) {
   214  	g := NewWithT(t)
   215  
   216  	dir, err := os.MkdirTemp("", "clusterctl")
   217  	g.Expect(err).ToNot(HaveOccurred())
   218  	defer os.RemoveAll(dir)
   219  
   220  	_ = os.Setenv("FOO", "foo")
   221  
   222  	configFile := filepath.Join(dir, "clusterctl.yaml")
   223  
   224  	g.Expect(os.WriteFile(configFile, []byte("bar: bar"), 0600)).To(Succeed())
   225  
   226  	type args struct {
   227  		key   string
   228  		value string
   229  	}
   230  	tests := []struct {
   231  		name string
   232  		args args
   233  		want string
   234  	}{
   235  		{
   236  			name: "",
   237  			args: args{
   238  				key:   "FOO",
   239  				value: "bar",
   240  			},
   241  			want: "bar",
   242  		},
   243  	}
   244  	for _, tt := range tests {
   245  		t.Run(tt.name, func(t *testing.T) {
   246  			gs := NewWithT(t)
   247  
   248  			ctx := context.Background()
   249  
   250  			v := &viperReader{}
   251  
   252  			gs.Expect(v.Init(ctx, configFile)).To(Succeed())
   253  
   254  			v.Set(tt.args.key, tt.args.value)
   255  
   256  			got, err := v.Get(tt.args.key)
   257  			gs.Expect(err).ToNot(HaveOccurred())
   258  			gs.Expect(got).To(Equal(tt.want))
   259  		})
   260  	}
   261  }
   262  
   263  func Test_viperReader_checkDefaultConfig(t *testing.T) {
   264  	g := NewWithT(t)
   265  	dir, err := os.MkdirTemp("", "clusterctl")
   266  	g.Expect(err).ToNot(HaveOccurred())
   267  	defer os.RemoveAll(dir)
   268  	dir = strings.TrimSuffix(dir, "/")
   269  
   270  	configFile := filepath.Join(dir, "clusterctl.yaml")
   271  	g.Expect(os.WriteFile(configFile, []byte("bar: bar"), 0600)).To(Succeed())
   272  
   273  	type fields struct {
   274  		configPaths []string
   275  	}
   276  	tests := []struct {
   277  		name   string
   278  		fields fields
   279  		want   bool
   280  	}{
   281  		{
   282  			name: "tmp path without final /",
   283  			fields: fields{
   284  				configPaths: []string{dir},
   285  			},
   286  			want: true,
   287  		},
   288  		{
   289  			name: "tmp path with final /",
   290  			fields: fields{
   291  				configPaths: []string{fmt.Sprintf("%s/", dir)},
   292  			},
   293  			want: true,
   294  		},
   295  	}
   296  	for _, tt := range tests {
   297  		t.Run(tt.name, func(t *testing.T) {
   298  			gs := NewWithT(t)
   299  
   300  			v := &viperReader{
   301  				configPaths: tt.fields.configPaths,
   302  			}
   303  			gs.Expect(v.checkDefaultConfig()).To(Equal(tt.want))
   304  		})
   305  	}
   306  }