github.com/go-maxhub/gremlins@v1.0.1-0.20231227222204-b03a6a1e3e09/core/configuration/configuration_test.go (about)

     1  /*
     2   * Copyright 2022 The Gremlins 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 configuration
    18  
    19  import (
    20  	"os"
    21  	"path/filepath"
    22  	"runtime"
    23  	"testing"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	"github.com/mitchellh/go-homedir"
    27  	"github.com/spf13/viper"
    28  
    29  	"github.com/go-maxhub/gremlins/core/mutator"
    30  )
    31  
    32  type envEntry struct {
    33  	name  string
    34  	value string
    35  }
    36  
    37  func TestConfiguration(t *testing.T) {
    38  	testCases := []struct {
    39  		wantedConfig map[string]interface{}
    40  		name         string
    41  		configPaths  []string
    42  		envEntries   []envEntry
    43  		expectErr    bool
    44  	}{
    45  		{
    46  			name:        "from single file",
    47  			configPaths: []string{"testdata/config1/.gremlins.yaml"},
    48  			wantedConfig: map[string]interface{}{
    49  				"unleash.dry-run": true,
    50  				"unleash.tags":    "tag1,tag2,tag3",
    51  			},
    52  		},
    53  		{
    54  			name:        "from returns error if unreadable",
    55  			configPaths: []string{"testdata/config1/.gremlin"},
    56  			wantedConfig: map[string]interface{}{
    57  				"unleash.dry-run": true,
    58  				"unleash.tags":    "tag1,tag2,tag3",
    59  			},
    60  			expectErr: true,
    61  		},
    62  		{
    63  			name:        "from cfg",
    64  			configPaths: []string{"./testdata/config1"},
    65  			wantedConfig: map[string]interface{}{
    66  				"unleash.dry-run": true,
    67  				"unleash.tags":    "tag1,tag2,tag3",
    68  			},
    69  		},
    70  		{
    71  			name:        "from cfg multi",
    72  			configPaths: []string{"./testdata/config2", "./testdata/config1"},
    73  			wantedConfig: map[string]interface{}{
    74  				"unleash.dry-run": true,
    75  				"unleash.tags":    "tag1.2,tag2.2,tag3.2",
    76  			},
    77  		},
    78  		{
    79  			name: "from env",
    80  			envEntries: []envEntry{
    81  				{name: "GREMLINS_UNLEASH_DRY_RUN", value: "true"},
    82  				{name: "GREMLINS_UNLEASH_TAGS", value: "tag1,tag2,tag3"},
    83  			},
    84  			wantedConfig: map[string]interface{}{
    85  				"unleash.dry-run": "true",
    86  				"unleash.tags":    "tag1,tag2,tag3",
    87  			},
    88  		},
    89  		{
    90  			name: "from cfg override with env",
    91  			envEntries: []envEntry{
    92  				{name: "GREMLINS_UNLEASH_TAGS", value: "tag1env,tag2env,tag3env"},
    93  			},
    94  			configPaths: []string{"./testdata/config1"},
    95  			wantedConfig: map[string]interface{}{
    96  				"unleash.dry-run": true,
    97  				"unleash.tags":    "tag1env,tag2env,tag3env",
    98  			},
    99  		},
   100  	}
   101  
   102  	for _, tc := range testCases {
   103  		tc := tc
   104  		t.Run(tc.name, func(t *testing.T) {
   105  			if tc.envEntries != nil {
   106  				for _, e := range tc.envEntries {
   107  					t.Setenv(e.name, e.value)
   108  				}
   109  			}
   110  			err := Init(tc.configPaths)
   111  			if tc.expectErr && err == nil {
   112  				t.Fatal("expected error")
   113  			}
   114  			if tc.expectErr {
   115  				return
   116  			}
   117  
   118  			for key, wanted := range tc.wantedConfig {
   119  				got := Get[any](key)
   120  				if got != wanted {
   121  					t.Errorf(cmp.Diff(got, wanted))
   122  				}
   123  			}
   124  			viper.Reset()
   125  		})
   126  	}
   127  }
   128  
   129  func TestConfigPaths(t *testing.T) {
   130  	home, _ := homedir.Dir()
   131  
   132  	t.Run("it lookups in default locations", func(t *testing.T) {
   133  		oldDir, _ := os.Getwd()
   134  		_ = os.Chdir("testdata/config1")
   135  		defer func(dir string) {
   136  			_ = os.Chdir(dir)
   137  		}(oldDir)
   138  
   139  		var want []string
   140  
   141  		// First global
   142  		if runtime.GOOS != windowsOs {
   143  			want = append(want, "/etc/gremlins")
   144  		}
   145  
   146  		// Then $XDG_CONFIG_HOME and $HOME
   147  		want = append(want,
   148  			filepath.Join(home, ".config", "gremlins", "gremlins"),
   149  			filepath.Join(home, ".gremlins"),
   150  		)
   151  
   152  		// Then module root
   153  		moduleRoot, _ := os.Getwd()
   154  		want = append(want, moduleRoot)
   155  
   156  		// Last current folder
   157  		want = append(want, ".")
   158  
   159  		got := defaultConfigPaths()
   160  
   161  		if !cmp.Equal(got, want) {
   162  			t.Errorf(cmp.Diff(got, want))
   163  		}
   164  	})
   165  
   166  	t.Run("no module root if not in go module", func(t *testing.T) {
   167  		oldDir, _ := os.Getwd()
   168  		_ = os.Chdir(t.TempDir())
   169  		defer func(dir string) {
   170  			_ = os.Chdir(dir)
   171  		}(oldDir)
   172  
   173  		var want []string
   174  
   175  		// First global
   176  		if runtime.GOOS != windowsOs {
   177  			want = append(want, "/etc/gremlins")
   178  		}
   179  
   180  		// Then $XDG_CONFIG_HOME and $HOME
   181  		want = append(want,
   182  			filepath.Join(home, ".config", "gremlins", "gremlins"),
   183  			filepath.Join(home, ".gremlins"),
   184  		)
   185  
   186  		// Last current folder
   187  		want = append(want, ".")
   188  
   189  		got := defaultConfigPaths()
   190  
   191  		if !cmp.Equal(got, want) {
   192  			t.Errorf(cmp.Diff(got, want))
   193  		}
   194  	})
   195  
   196  	t.Run("when XDG_CONFIG_HOME is set, it lookups in that locations", func(t *testing.T) {
   197  		oldDir, _ := os.Getwd()
   198  		_ = os.Chdir("testdata/config1")
   199  		defer func(dir string) {
   200  			_ = os.Chdir(dir)
   201  		}(oldDir)
   202  
   203  		customPath := filepath.Join("my", "custom", "path")
   204  		t.Setenv("XDG_CONFIG_HOME", customPath)
   205  
   206  		var want []string
   207  
   208  		// First global
   209  		if runtime.GOOS != windowsOs {
   210  			want = append(want, "/etc/gremlins")
   211  		}
   212  
   213  		// Then $XDG_CONFIG_HOME and $HOME
   214  		want = append(want,
   215  			filepath.Join(customPath, "gremlins", "gremlins"),
   216  			filepath.Join(home, ".gremlins"))
   217  
   218  		// Then Go module root
   219  		moduleRoot, _ := os.Getwd()
   220  		want = append(want, moduleRoot)
   221  
   222  		// Last the current directory
   223  		want = append(want, ".")
   224  
   225  		got := defaultConfigPaths()
   226  
   227  		if !cmp.Equal(got, want) {
   228  			t.Errorf(cmp.Diff(got, want))
   229  		}
   230  	})
   231  }
   232  
   233  func TestGeneratesMutantTypeEnabledKey(t *testing.T) {
   234  	mt := mutator.ArithmeticBase
   235  	want := "mutants.arithmetic-base.enabled"
   236  
   237  	got := MutantTypeEnabledKey(mt)
   238  
   239  	if got != want {
   240  		t.Errorf("expected %q, got %q", mt, want)
   241  	}
   242  }
   243  
   244  func TestViperSynchronisedAccess(t *testing.T) {
   245  	t.Parallel()
   246  	testCases := []struct {
   247  		value any
   248  		name  string
   249  		key   string
   250  	}{
   251  		{
   252  			name:  "bool",
   253  			key:   "tvsa.bool.key",
   254  			value: true,
   255  		},
   256  		{
   257  			name:  "int",
   258  			key:   "tvsa.int.key",
   259  			value: 10,
   260  		},
   261  		{
   262  			name:  "float64",
   263  			key:   "tvsa.float64.key",
   264  			value: float64(10),
   265  		},
   266  		{
   267  			name:  "string",
   268  			key:   "tvsa.string.key",
   269  			value: "test string",
   270  		},
   271  		{
   272  			name:  "char",
   273  			key:   "tvsa.char.key",
   274  			value: 'a',
   275  		},
   276  	}
   277  	for _, tc := range testCases {
   278  		tc := tc
   279  		t.Run(tc.name, func(t *testing.T) {
   280  			t.Parallel()
   281  
   282  			Set(tc.key, tc.value)
   283  
   284  			got := Get[any](tc.key)
   285  
   286  			if !cmp.Equal(got, tc.value) {
   287  				t.Errorf("expected %v, got %v", tc.value, got)
   288  			}
   289  		})
   290  	}
   291  }
   292  
   293  func TestReset(t *testing.T) {
   294  	Set("test.key", true)
   295  
   296  	Reset()
   297  
   298  	got := Get[bool]("test.key")
   299  
   300  	if got != false {
   301  		t.Errorf("expected config to be reset")
   302  	}
   303  }