github.com/weaviate/weaviate@v1.24.6/usecases/config/environment_test.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package config
    13  
    14  import (
    15  	"errors"
    16  	"os"
    17  	"testing"
    18  
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/require"
    21  	"github.com/weaviate/weaviate/usecases/cluster"
    22  )
    23  
    24  const DefaultGoroutineFactor = 1.5
    25  
    26  func TestEnvironmentImportGoroutineFactor(t *testing.T) {
    27  	factors := []struct {
    28  		name            string
    29  		goroutineFactor []string
    30  		expected        float64
    31  		expectedErr     bool
    32  	}{
    33  		{"Valid factor", []string{"1"}, 1, false},
    34  		{"Low factor", []string{"0.5"}, 0.5, false},
    35  		{"not given", []string{}, DefaultGoroutineFactor, false},
    36  		{"High factor", []string{"5"}, 5, false},
    37  		{"invalid factor", []string{"-1"}, -1, true},
    38  		{"not parsable", []string{"I'm not a number"}, -1, true},
    39  	}
    40  	for _, tt := range factors {
    41  		t.Run(tt.name, func(t *testing.T) {
    42  			if len(tt.goroutineFactor) == 1 {
    43  				t.Setenv("MAX_IMPORT_GOROUTINES_FACTOR", tt.goroutineFactor[0])
    44  			}
    45  			conf := Config{}
    46  			err := FromEnv(&conf)
    47  
    48  			if tt.expectedErr {
    49  				require.NotNil(t, err)
    50  			} else {
    51  				require.Equal(t, tt.expected, conf.MaxImportGoroutinesFactor)
    52  			}
    53  		})
    54  	}
    55  }
    56  
    57  func TestEnvironmentSetFlushAfter_AllNames(t *testing.T) {
    58  	factors := []struct {
    59  		name        string
    60  		flushAfter  []string
    61  		expected    int
    62  		expectedErr bool
    63  	}{
    64  		{"Valid", []string{"1"}, 1, false},
    65  		{"not given", []string{}, DefaultPersistenceMemtablesFlushDirtyAfter, false},
    66  		{"invalid factor", []string{"-1"}, -1, true},
    67  		{"zero factor", []string{"0"}, -1, true},
    68  		{"not parsable", []string{"I'm not a number"}, -1, true},
    69  	}
    70  	envNames := []struct {
    71  		name    string
    72  		envName string
    73  	}{
    74  		{name: "fallback idle (1st)", envName: "PERSISTENCE_FLUSH_IDLE_MEMTABLES_AFTER"},
    75  		{name: "fallback idle (2nd)", envName: "PERSISTENCE_MEMTABLES_FLUSH_IDLE_AFTER_SECONDS"},
    76  		{name: "dirty", envName: "PERSISTENCE_MEMTABLES_FLUSH_DIRTY_AFTER_SECONDS"},
    77  	}
    78  
    79  	for _, n := range envNames {
    80  		t.Run(n.name, func(t *testing.T) {
    81  			for _, tt := range factors {
    82  				t.Run(tt.name, func(t *testing.T) {
    83  					if len(tt.flushAfter) == 1 {
    84  						t.Setenv(n.envName, tt.flushAfter[0])
    85  					}
    86  					conf := Config{}
    87  					err := FromEnv(&conf)
    88  
    89  					if tt.expectedErr {
    90  						require.NotNil(t, err)
    91  					} else {
    92  						require.Equal(t, tt.expected, conf.Persistence.MemtablesFlushDirtyAfter)
    93  					}
    94  				})
    95  			}
    96  		})
    97  	}
    98  }
    99  
   100  func TestEnvironmentFlushConflictingValues(t *testing.T) {
   101  	// if all 3 variable names are used, the newest variable name
   102  	// should be taken into consideration
   103  	os.Clearenv()
   104  	t.Setenv("PERSISTENCE_FLUSH_IDLE_MEMTABLES_AFTER", "16")
   105  	t.Setenv("PERSISTENCE_MEMTABLES_FLUSH_IDLE_AFTER_SECONDS", "17")
   106  	t.Setenv("PERSISTENCE_MEMTABLES_FLUSH_DIRTY_AFTER_SECONDS", "18")
   107  	conf := Config{}
   108  	err := FromEnv(&conf)
   109  	require.Nil(t, err)
   110  
   111  	assert.Equal(t, 18, conf.Persistence.MemtablesFlushDirtyAfter)
   112  }
   113  
   114  func TestEnvironmentPersistence_dataPath(t *testing.T) {
   115  	factors := []struct {
   116  		name     string
   117  		value    []string
   118  		config   Config
   119  		expected string
   120  	}{
   121  		{
   122  			name:     "given",
   123  			value:    []string{"/var/lib/weaviate"},
   124  			config:   Config{},
   125  			expected: "/var/lib/weaviate",
   126  		},
   127  		{
   128  			name:  "given with config set",
   129  			value: []string{"/var/lib/weaviate"},
   130  			config: Config{
   131  				Persistence: Persistence{
   132  					DataPath: "/var/data/weaviate",
   133  				},
   134  			},
   135  			expected: "/var/lib/weaviate",
   136  		},
   137  		{
   138  			name:     "not given",
   139  			value:    []string{},
   140  			config:   Config{},
   141  			expected: DefaultPersistenceDataPath,
   142  		},
   143  		{
   144  			name:  "not given with config set",
   145  			value: []string{},
   146  			config: Config{
   147  				Persistence: Persistence{
   148  					DataPath: "/var/data/weaviate",
   149  				},
   150  			},
   151  			expected: "/var/data/weaviate",
   152  		},
   153  	}
   154  	for _, tt := range factors {
   155  		t.Run(tt.name, func(t *testing.T) {
   156  			if len(tt.value) == 1 {
   157  				t.Setenv("PERSISTENCE_DATA_PATH", tt.value[0])
   158  			}
   159  			conf := tt.config
   160  			err := FromEnv(&conf)
   161  			require.Nil(t, err)
   162  			require.Equal(t, tt.expected, conf.Persistence.DataPath)
   163  		})
   164  	}
   165  }
   166  
   167  func TestEnvironmentMemtable_MaxSize(t *testing.T) {
   168  	factors := []struct {
   169  		name        string
   170  		value       []string
   171  		expected    int
   172  		expectedErr bool
   173  	}{
   174  		{"Valid", []string{"100"}, 100, false},
   175  		{"not given", []string{}, DefaultPersistenceMemtablesMaxSize, false},
   176  		{"invalid factor", []string{"-1"}, -1, true},
   177  		{"zero factor", []string{"0"}, -1, true},
   178  		{"not parsable", []string{"I'm not a number"}, -1, true},
   179  	}
   180  	for _, tt := range factors {
   181  		t.Run(tt.name, func(t *testing.T) {
   182  			if len(tt.value) == 1 {
   183  				t.Setenv("PERSISTENCE_MEMTABLES_MAX_SIZE_MB", tt.value[0])
   184  			}
   185  			conf := Config{}
   186  			err := FromEnv(&conf)
   187  
   188  			if tt.expectedErr {
   189  				require.NotNil(t, err)
   190  			} else {
   191  				require.Equal(t, tt.expected, conf.Persistence.MemtablesMaxSizeMB)
   192  			}
   193  		})
   194  	}
   195  }
   196  
   197  func TestEnvironmentMemtable_MinDuration(t *testing.T) {
   198  	factors := []struct {
   199  		name        string
   200  		value       []string
   201  		expected    int
   202  		expectedErr bool
   203  	}{
   204  		{"Valid", []string{"100"}, 100, false},
   205  		{"not given", []string{}, DefaultPersistenceMemtablesMinDuration, false},
   206  		{"invalid factor", []string{"-1"}, -1, true},
   207  		{"zero factor", []string{"0"}, -1, true},
   208  		{"not parsable", []string{"I'm not a number"}, -1, true},
   209  	}
   210  	for _, tt := range factors {
   211  		t.Run(tt.name, func(t *testing.T) {
   212  			if len(tt.value) == 1 {
   213  				t.Setenv("PERSISTENCE_MEMTABLES_MIN_ACTIVE_DURATION_SECONDS", tt.value[0])
   214  			}
   215  			conf := Config{}
   216  			err := FromEnv(&conf)
   217  
   218  			if tt.expectedErr {
   219  				require.NotNil(t, err)
   220  			} else {
   221  				require.Equal(t, tt.expected, conf.Persistence.MemtablesMinActiveDurationSeconds)
   222  			}
   223  		})
   224  	}
   225  }
   226  
   227  func TestEnvironmentMemtable_MaxDuration(t *testing.T) {
   228  	factors := []struct {
   229  		name        string
   230  		value       []string
   231  		expected    int
   232  		expectedErr bool
   233  	}{
   234  		{"Valid", []string{"100"}, 100, false},
   235  		{"not given", []string{}, DefaultPersistenceMemtablesMaxDuration, false},
   236  		{"invalid factor", []string{"-1"}, -1, true},
   237  		{"zero factor", []string{"0"}, -1, true},
   238  		{"not parsable", []string{"I'm not a number"}, -1, true},
   239  	}
   240  	for _, tt := range factors {
   241  		t.Run(tt.name, func(t *testing.T) {
   242  			if len(tt.value) == 1 {
   243  				t.Setenv("PERSISTENCE_MEMTABLES_MAX_ACTIVE_DURATION_SECONDS", tt.value[0])
   244  			}
   245  			conf := Config{}
   246  			err := FromEnv(&conf)
   247  
   248  			if tt.expectedErr {
   249  				require.NotNil(t, err)
   250  			} else {
   251  				require.Equal(t, tt.expected, conf.Persistence.MemtablesMaxActiveDurationSeconds)
   252  			}
   253  		})
   254  	}
   255  }
   256  
   257  func TestEnvironmentParseClusterConfig(t *testing.T) {
   258  	tests := []struct {
   259  		name           string
   260  		envVars        map[string]string
   261  		expectedResult cluster.Config
   262  		expectedErr    error
   263  	}{
   264  		{
   265  			name: "valid cluster config - ports and advertiseaddr provided",
   266  			envVars: map[string]string{
   267  				"CLUSTER_GOSSIP_BIND_PORT": "7100",
   268  				"CLUSTER_DATA_BIND_PORT":   "7101",
   269  				"CLUSTER_ADVERTISE_ADDR":   "193.0.0.1",
   270  				"CLUSTER_ADVERTISE_PORT":   "9999",
   271  			},
   272  			expectedResult: cluster.Config{
   273  				GossipBindPort: 7100,
   274  				DataBindPort:   7101,
   275  				AdvertiseAddr:  "193.0.0.1",
   276  				AdvertisePort:  9999,
   277  			},
   278  		},
   279  		{
   280  			name: "valid cluster config - no ports and advertiseaddr provided",
   281  			expectedResult: cluster.Config{
   282  				GossipBindPort: DefaultGossipBindPort,
   283  				DataBindPort:   DefaultGossipBindPort + 1,
   284  				AdvertiseAddr:  "",
   285  			},
   286  		},
   287  		{
   288  			name: "valid cluster config - only gossip bind port provided",
   289  			envVars: map[string]string{
   290  				"CLUSTER_GOSSIP_BIND_PORT": "7777",
   291  			},
   292  			expectedResult: cluster.Config{
   293  				GossipBindPort: 7777,
   294  				DataBindPort:   7778,
   295  			},
   296  		},
   297  		{
   298  			name: "invalid cluster config - both ports provided",
   299  			envVars: map[string]string{
   300  				"CLUSTER_GOSSIP_BIND_PORT": "7100",
   301  				"CLUSTER_DATA_BIND_PORT":   "7111",
   302  			},
   303  			expectedErr: errors.New("CLUSTER_DATA_BIND_PORT must be one port " +
   304  				"number greater than CLUSTER_GOSSIP_BIND_PORT"),
   305  		},
   306  		{
   307  			name: "invalid config - only data bind port provided",
   308  			envVars: map[string]string{
   309  				"CLUSTER_DATA_BIND_PORT": "7101",
   310  			},
   311  			expectedErr: errors.New("CLUSTER_DATA_BIND_PORT must be one port " +
   312  				"number greater than CLUSTER_GOSSIP_BIND_PORT"),
   313  		},
   314  		{
   315  			name: "schema sync disabled",
   316  			envVars: map[string]string{
   317  				"CLUSTER_IGNORE_SCHEMA_SYNC": "true",
   318  			},
   319  			expectedResult: cluster.Config{
   320  				GossipBindPort:          7946,
   321  				DataBindPort:            7947,
   322  				IgnoreStartupSchemaSync: true,
   323  			},
   324  		},
   325  	}
   326  
   327  	for _, test := range tests {
   328  		t.Run(test.name, func(t *testing.T) {
   329  			for k, v := range test.envVars {
   330  				t.Setenv(k, v)
   331  			}
   332  			cfg, err := parseClusterConfig()
   333  			if test.expectedErr != nil {
   334  				assert.EqualError(t, err, test.expectedErr.Error(),
   335  					"expected err: %v, got: %v", test.expectedErr, err)
   336  			} else {
   337  				assert.Nil(t, err, "expected nil, got: %v", err)
   338  				assert.EqualValues(t, test.expectedResult, cfg)
   339  			}
   340  		})
   341  	}
   342  }
   343  
   344  func TestEnvironmentSetDefaultVectorDistanceMetric(t *testing.T) {
   345  	t.Run("DefaultVectorDistanceMetricIsEmpty", func(t *testing.T) {
   346  		os.Clearenv()
   347  		conf := Config{}
   348  		FromEnv(&conf)
   349  		require.Equal(t, "", conf.DefaultVectorDistanceMetric)
   350  	})
   351  
   352  	t.Run("NonEmptyDefaultVectorDistanceMetric", func(t *testing.T) {
   353  		os.Clearenv()
   354  		t.Setenv("DEFAULT_VECTOR_DISTANCE_METRIC", "l2-squared")
   355  		conf := Config{}
   356  		FromEnv(&conf)
   357  		require.Equal(t, "l2-squared", conf.DefaultVectorDistanceMetric)
   358  	})
   359  }
   360  
   361  func TestEnvironmentMaxConcurrentGetRequests(t *testing.T) {
   362  	factors := []struct {
   363  		name        string
   364  		value       []string
   365  		expected    int
   366  		expectedErr bool
   367  	}{
   368  		{"Valid", []string{"100"}, 100, false},
   369  		{"not given", []string{}, DefaultMaxConcurrentGetRequests, false},
   370  		{"unlimited", []string{"-1"}, -1, false},
   371  		{"not parsable", []string{"I'm not a number"}, -1, true},
   372  	}
   373  	for _, tt := range factors {
   374  		t.Run(tt.name, func(t *testing.T) {
   375  			if len(tt.value) == 1 {
   376  				t.Setenv("MAXIMUM_CONCURRENT_GET_REQUESTS", tt.value[0])
   377  			}
   378  			conf := Config{}
   379  			err := FromEnv(&conf)
   380  
   381  			if tt.expectedErr {
   382  				require.NotNil(t, err)
   383  			} else {
   384  				require.Equal(t, tt.expected, conf.MaximumConcurrentGetRequests)
   385  			}
   386  		})
   387  	}
   388  }
   389  
   390  func TestEnvironmentCORS_Origin(t *testing.T) {
   391  	factors := []struct {
   392  		name        string
   393  		value       []string
   394  		expected    string
   395  		expectedErr bool
   396  	}{
   397  		{"Valid", []string{"http://foo.com"}, "http://foo.com", false},
   398  		{"not given", []string{}, DefaultCORSAllowOrigin, false},
   399  	}
   400  	for _, tt := range factors {
   401  		t.Run(tt.name, func(t *testing.T) {
   402  			os.Clearenv()
   403  			if len(tt.value) == 1 {
   404  				os.Setenv("CORS_ALLOW_ORIGIN", tt.value[0])
   405  			}
   406  			conf := Config{}
   407  			err := FromEnv(&conf)
   408  
   409  			if tt.expectedErr {
   410  				require.NotNil(t, err)
   411  			} else {
   412  				require.Equal(t, tt.expected, conf.CORS.AllowOrigin)
   413  			}
   414  		})
   415  	}
   416  }
   417  
   418  func TestEnvironmentGRPCPort(t *testing.T) {
   419  	factors := []struct {
   420  		name        string
   421  		value       []string
   422  		expected    int
   423  		expectedErr bool
   424  	}{
   425  		{"Valid", []string{"50052"}, 50052, false},
   426  		{"not given", []string{}, DefaultGRPCPort, false},
   427  		{"invalid factor", []string{"-1"}, -1, true},
   428  		{"zero factor", []string{"0"}, -1, true},
   429  		{"not parsable", []string{"I'm not a number"}, -1, true},
   430  	}
   431  	for _, tt := range factors {
   432  		t.Run(tt.name, func(t *testing.T) {
   433  			if len(tt.value) == 1 {
   434  				t.Setenv("GRPC_PORT", tt.value[0])
   435  			}
   436  			conf := Config{}
   437  			err := FromEnv(&conf)
   438  
   439  			if tt.expectedErr {
   440  				require.NotNil(t, err)
   441  			} else {
   442  				require.Equal(t, tt.expected, conf.GRPC.Port)
   443  			}
   444  		})
   445  	}
   446  }
   447  
   448  func TestEnvironmentCORS_Methods(t *testing.T) {
   449  	factors := []struct {
   450  		name        string
   451  		value       []string
   452  		expected    string
   453  		expectedErr bool
   454  	}{
   455  		{"Valid", []string{"POST"}, "POST", false},
   456  		{"not given", []string{}, DefaultCORSAllowMethods, false},
   457  	}
   458  	for _, tt := range factors {
   459  		t.Run(tt.name, func(t *testing.T) {
   460  			os.Clearenv()
   461  			if len(tt.value) == 1 {
   462  				os.Setenv("CORS_ALLOW_METHODS", tt.value[0])
   463  			}
   464  			conf := Config{}
   465  			err := FromEnv(&conf)
   466  
   467  			if tt.expectedErr {
   468  				require.NotNil(t, err)
   469  			} else {
   470  				require.Equal(t, tt.expected, conf.CORS.AllowMethods)
   471  			}
   472  		})
   473  	}
   474  }
   475  
   476  func TestEnvironmentDisableGraphQL(t *testing.T) {
   477  	factors := []struct {
   478  		name        string
   479  		value       []string
   480  		expected    bool
   481  		expectedErr bool
   482  	}{
   483  		{"Valid: true", []string{"true"}, true, false},
   484  		{"Valid: false", []string{"false"}, false, false},
   485  		{"Valid: 1", []string{"1"}, true, false},
   486  		{"Valid: 0", []string{"0"}, false, false},
   487  		{"Valid: on", []string{"on"}, true, false},
   488  		{"Valid: off", []string{"off"}, false, false},
   489  		{"not given", []string{}, false, false},
   490  	}
   491  	for _, tt := range factors {
   492  		t.Run(tt.name, func(t *testing.T) {
   493  			if len(tt.value) == 1 {
   494  				t.Setenv("DISABLE_GRAPHQL", tt.value[0])
   495  			}
   496  			conf := Config{}
   497  			err := FromEnv(&conf)
   498  
   499  			if tt.expectedErr {
   500  				require.NotNil(t, err)
   501  			} else {
   502  				require.Equal(t, tt.expected, conf.DisableGraphQL)
   503  			}
   504  		})
   505  	}
   506  }
   507  
   508  func TestEnvironmentCORS_Headers(t *testing.T) {
   509  	factors := []struct {
   510  		name        string
   511  		value       []string
   512  		expected    string
   513  		expectedErr bool
   514  	}{
   515  		{"Valid", []string{"Authorization"}, "Authorization", false},
   516  		{"not given", []string{}, DefaultCORSAllowHeaders, false},
   517  	}
   518  	for _, tt := range factors {
   519  		t.Run(tt.name, func(t *testing.T) {
   520  			os.Clearenv()
   521  			if len(tt.value) == 1 {
   522  				os.Setenv("CORS_ALLOW_HEADERS", tt.value[0])
   523  			}
   524  			conf := Config{}
   525  			err := FromEnv(&conf)
   526  
   527  			if tt.expectedErr {
   528  				require.NotNil(t, err)
   529  			} else {
   530  				require.Equal(t, tt.expected, conf.CORS.AllowHeaders)
   531  			}
   532  		})
   533  	}
   534  }
   535  
   536  func TestEnvironmentPrometheusGroupClasses_OldName(t *testing.T) {
   537  	factors := []struct {
   538  		name        string
   539  		value       []string
   540  		expected    bool
   541  		expectedErr bool
   542  	}{
   543  		{"Valid: true", []string{"true"}, true, false},
   544  		{"Valid: false", []string{"false"}, false, false},
   545  		{"Valid: 1", []string{"1"}, true, false},
   546  		{"Valid: 0", []string{"0"}, false, false},
   547  		{"Valid: on", []string{"on"}, true, false},
   548  		{"Valid: off", []string{"off"}, false, false},
   549  		{"not given", []string{}, false, false},
   550  	}
   551  	for _, tt := range factors {
   552  		t.Run(tt.name, func(t *testing.T) {
   553  			t.Setenv("PROMETHEUS_MONITORING_ENABLED", "true")
   554  			if len(tt.value) == 1 {
   555  				t.Setenv("PROMETHEUS_MONITORING_GROUP_CLASSES", tt.value[0])
   556  			}
   557  			conf := Config{}
   558  			err := FromEnv(&conf)
   559  
   560  			if tt.expectedErr {
   561  				require.NotNil(t, err)
   562  			} else {
   563  				require.Equal(t, tt.expected, conf.Monitoring.Group)
   564  			}
   565  		})
   566  	}
   567  }
   568  
   569  func TestEnvironmentPrometheusGroupClasses_NewName(t *testing.T) {
   570  	factors := []struct {
   571  		name        string
   572  		value       []string
   573  		expected    bool
   574  		expectedErr bool
   575  	}{
   576  		{"Valid: true", []string{"true"}, true, false},
   577  		{"Valid: false", []string{"false"}, false, false},
   578  		{"Valid: 1", []string{"1"}, true, false},
   579  		{"Valid: 0", []string{"0"}, false, false},
   580  		{"Valid: on", []string{"on"}, true, false},
   581  		{"Valid: off", []string{"off"}, false, false},
   582  		{"not given", []string{}, false, false},
   583  	}
   584  	for _, tt := range factors {
   585  		t.Run(tt.name, func(t *testing.T) {
   586  			t.Setenv("PROMETHEUS_MONITORING_ENABLED", "true")
   587  			if len(tt.value) == 1 {
   588  				t.Setenv("PROMETHEUS_MONITORING_GROUP", tt.value[0])
   589  			}
   590  			conf := Config{}
   591  			err := FromEnv(&conf)
   592  
   593  			if tt.expectedErr {
   594  				require.NotNil(t, err)
   595  			} else {
   596  				require.Equal(t, tt.expected, conf.Monitoring.Group)
   597  			}
   598  		})
   599  	}
   600  }
   601  
   602  func TestEnvironmentMinimumReplicationFactor(t *testing.T) {
   603  	factors := []struct {
   604  		name        string
   605  		value       []string
   606  		expected    int
   607  		expectedErr bool
   608  	}{
   609  		{"Valid", []string{"3"}, 3, false},
   610  		{"not given", []string{}, DefaultMinimumReplicationFactor, false},
   611  		{"invalid factor", []string{"-1"}, -1, true},
   612  		{"zero factor", []string{"0"}, -1, true},
   613  		{"not parsable", []string{"I'm not a number"}, -1, true},
   614  	}
   615  	for _, tt := range factors {
   616  		t.Run(tt.name, func(t *testing.T) {
   617  			if len(tt.value) == 1 {
   618  				t.Setenv("REPLICATION_MINIMUM_FACTOR", tt.value[0])
   619  			}
   620  			conf := Config{}
   621  			err := FromEnv(&conf)
   622  
   623  			if tt.expectedErr {
   624  				require.NotNil(t, err)
   625  			} else {
   626  				require.Equal(t, tt.expected, conf.Replication.MinimumFactor)
   627  			}
   628  		})
   629  	}
   630  }
   631  
   632  func TestEnvironmentQueryDefaults_Limit(t *testing.T) {
   633  	factors := []struct {
   634  		name     string
   635  		value    []string
   636  		config   Config
   637  		expected int64
   638  	}{
   639  		{
   640  			name:     "Valid",
   641  			value:    []string{"3"},
   642  			config:   Config{},
   643  			expected: 3,
   644  		},
   645  		{
   646  			name:  "Valid with config already set",
   647  			value: []string{"3"},
   648  			config: Config{
   649  				QueryDefaults: QueryDefaults{
   650  					Limit: 20,
   651  				},
   652  			},
   653  			expected: 3,
   654  		},
   655  		{
   656  			name:  "not given with config set",
   657  			value: []string{},
   658  			config: Config{
   659  				QueryDefaults: QueryDefaults{
   660  					Limit: 20,
   661  				},
   662  			},
   663  			expected: 20,
   664  		},
   665  		{
   666  			name:     "not given with config set",
   667  			value:    []string{},
   668  			config:   Config{},
   669  			expected: DefaultQueryDefaultsLimit,
   670  		},
   671  	}
   672  	for _, tt := range factors {
   673  		t.Run(tt.name, func(t *testing.T) {
   674  			if len(tt.value) == 1 {
   675  				t.Setenv("QUERY_DEFAULTS_LIMIT", tt.value[0])
   676  			}
   677  			conf := tt.config
   678  			err := FromEnv(&conf)
   679  
   680  			require.Nil(t, err)
   681  			require.Equal(t, tt.expected, conf.QueryDefaults.Limit)
   682  		})
   683  	}
   684  }
   685  
   686  func TestEnvironmentAuthentication(t *testing.T) {
   687  	factors := []struct {
   688  		name         string
   689  		auth_env_var []string
   690  		expected     Authentication
   691  	}{
   692  		{
   693  			name:         "Valid API Key",
   694  			auth_env_var: []string{"AUTHENTICATION_APIKEY_ENABLED"},
   695  			expected: Authentication{
   696  				APIKey: APIKey{
   697  					Enabled: true,
   698  				},
   699  			},
   700  		},
   701  		{
   702  			name:         "Valid Anonymous Access",
   703  			auth_env_var: []string{"AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED"},
   704  			expected: Authentication{
   705  				AnonymousAccess: AnonymousAccess{
   706  					Enabled: true,
   707  				},
   708  			},
   709  		},
   710  		{
   711  			name:         "Valid OIDC Auth",
   712  			auth_env_var: []string{"AUTHENTICATION_OIDC_ENABLED"},
   713  			expected: Authentication{
   714  				OIDC: OIDC{
   715  					Enabled: true,
   716  				},
   717  			},
   718  		},
   719  		{
   720  			name:         "not given",
   721  			auth_env_var: []string{},
   722  			expected: Authentication{
   723  				AnonymousAccess: AnonymousAccess{
   724  					Enabled: true,
   725  				},
   726  			},
   727  		},
   728  	}
   729  	for _, tt := range factors {
   730  		t.Run(tt.name, func(t *testing.T) {
   731  			if len(tt.auth_env_var) == 1 {
   732  				t.Setenv(tt.auth_env_var[0], "true")
   733  			}
   734  			conf := Config{}
   735  			err := FromEnv(&conf)
   736  			require.Nil(t, err)
   737  			require.Equal(t, tt.expected, conf.Authentication)
   738  		})
   739  	}
   740  }