SemanticSearchPOC / usecases /config /environment_test.go
KevinStephenson
Adding in weaviate code
b110593
raw
history blame
16 kB
// _ _
// __ _____ __ ___ ___ __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
// \ V V / __/ (_| |\ V /| | (_| | || __/
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
//
// CONTACT: [email protected]
//
package config
import (
"errors"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/weaviate/weaviate/usecases/cluster"
)
const DefaultGoroutineFactor = 1.5
func TestEnvironmentImportGoroutineFactor(t *testing.T) {
factors := []struct {
name string
goroutineFactor []string
expected float64
expectedErr bool
}{
{"Valid factor", []string{"1"}, 1, false},
{"Low factor", []string{"0.5"}, 0.5, false},
{"not given", []string{}, DefaultGoroutineFactor, false},
{"High factor", []string{"5"}, 5, false},
{"invalid factor", []string{"-1"}, -1, true},
{"not parsable", []string{"I'm not a number"}, -1, true},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.goroutineFactor) == 1 {
t.Setenv("MAX_IMPORT_GOROUTINES_FACTOR", tt.goroutineFactor[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.MaxImportGoroutinesFactor)
}
})
}
}
func TestEnvironmentSetFlushAfter_BackwardCompatibility(t *testing.T) {
factors := []struct {
name string
flushAfter []string
expected int
expectedErr bool
}{
{"Valid", []string{"1"}, 1, false},
{"not given", []string{}, DefaultPersistenceFlushIdleMemtablesAfter, false},
{"invalid factor", []string{"-1"}, -1, true},
{"zero factor", []string{"0"}, -1, true},
{"not parsable", []string{"I'm not a number"}, -1, true},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.flushAfter) == 1 {
t.Setenv("PERSISTENCE_FLUSH_IDLE_MEMTABLES_AFTER", tt.flushAfter[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.Persistence.FlushIdleMemtablesAfter)
}
})
}
}
func TestEnvironmentSetFlushAfter_NewName(t *testing.T) {
factors := []struct {
name string
flushAfter []string
expected int
expectedErr bool
}{
{"Valid", []string{"1"}, 1, false},
{"not given", []string{}, DefaultPersistenceFlushIdleMemtablesAfter, false},
{"invalid factor", []string{"-1"}, -1, true},
{"zero factor", []string{"0"}, -1, true},
{"not parsable", []string{"I'm not a number"}, -1, true},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.flushAfter) == 1 {
t.Setenv("PERSISTENCE_MEMTABLES_FLUSH_IDLE_AFTER_SECONDS", tt.flushAfter[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.Persistence.FlushIdleMemtablesAfter)
}
})
}
}
func TestEnvironmentFlushConflictingValues(t *testing.T) {
// if both the old and new variable names are used the new variable name
// should be taken into consideration
os.Clearenv()
t.Setenv("PERSISTENCE_FLUSH_IDLE_MEMTABLES_AFTER", "16")
t.Setenv("PERSISTENCE_MEMTABLES_FLUSH_IDLE_AFTER_SECONDS", "17")
conf := Config{}
err := FromEnv(&conf)
require.Nil(t, err)
assert.Equal(t, 17, conf.Persistence.FlushIdleMemtablesAfter)
}
func TestEnvironmentMemtable_MaxSize(t *testing.T) {
factors := []struct {
name string
value []string
expected int
expectedErr bool
}{
{"Valid", []string{"100"}, 100, false},
{"not given", []string{}, DefaultPersistenceMemtablesMaxSize, false},
{"invalid factor", []string{"-1"}, -1, true},
{"zero factor", []string{"0"}, -1, true},
{"not parsable", []string{"I'm not a number"}, -1, true},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.value) == 1 {
t.Setenv("PERSISTENCE_MEMTABLES_MAX_SIZE_MB", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.Persistence.MemtablesMaxSizeMB)
}
})
}
}
func TestEnvironmentMemtable_MinDuration(t *testing.T) {
factors := []struct {
name string
value []string
expected int
expectedErr bool
}{
{"Valid", []string{"100"}, 100, false},
{"not given", []string{}, DefaultPersistenceMemtablesMinDuration, false},
{"invalid factor", []string{"-1"}, -1, true},
{"zero factor", []string{"0"}, -1, true},
{"not parsable", []string{"I'm not a number"}, -1, true},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.value) == 1 {
t.Setenv("PERSISTENCE_MEMTABLES_MIN_ACTIVE_DURATION_SECONDS", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.Persistence.MemtablesMinActiveDurationSeconds)
}
})
}
}
func TestEnvironmentMemtable_MaxDuration(t *testing.T) {
factors := []struct {
name string
value []string
expected int
expectedErr bool
}{
{"Valid", []string{"100"}, 100, false},
{"not given", []string{}, DefaultPersistenceMemtablesMaxDuration, false},
{"invalid factor", []string{"-1"}, -1, true},
{"zero factor", []string{"0"}, -1, true},
{"not parsable", []string{"I'm not a number"}, -1, true},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.value) == 1 {
t.Setenv("PERSISTENCE_MEMTABLES_MAX_ACTIVE_DURATION_SECONDS", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.Persistence.MemtablesMaxActiveDurationSeconds)
}
})
}
}
func TestEnvironmentParseClusterConfig(t *testing.T) {
tests := []struct {
name string
envVars map[string]string
expectedResult cluster.Config
expectedErr error
}{
{
name: "valid cluster config - both ports provided",
envVars: map[string]string{
"CLUSTER_GOSSIP_BIND_PORT": "7100",
"CLUSTER_DATA_BIND_PORT": "7101",
},
expectedResult: cluster.Config{
GossipBindPort: 7100,
DataBindPort: 7101,
},
},
{
name: "valid cluster config - no ports provided",
expectedResult: cluster.Config{
GossipBindPort: DefaultGossipBindPort,
DataBindPort: DefaultGossipBindPort + 1,
},
},
{
name: "valid cluster config - only gossip bind port provided",
envVars: map[string]string{
"CLUSTER_GOSSIP_BIND_PORT": "7777",
},
expectedResult: cluster.Config{
GossipBindPort: 7777,
DataBindPort: 7778,
},
},
{
name: "invalid cluster config - both ports provided",
envVars: map[string]string{
"CLUSTER_GOSSIP_BIND_PORT": "7100",
"CLUSTER_DATA_BIND_PORT": "7111",
},
expectedErr: errors.New("CLUSTER_DATA_BIND_PORT must be one port " +
"number greater than CLUSTER_GOSSIP_BIND_PORT"),
},
{
name: "invalid config - only data bind port provided",
envVars: map[string]string{
"CLUSTER_DATA_BIND_PORT": "7101",
},
expectedErr: errors.New("CLUSTER_DATA_BIND_PORT must be one port " +
"number greater than CLUSTER_GOSSIP_BIND_PORT"),
},
{
name: "schema sync disabled",
envVars: map[string]string{
"CLUSTER_IGNORE_SCHEMA_SYNC": "true",
},
expectedResult: cluster.Config{
GossipBindPort: 7946,
DataBindPort: 7947,
IgnoreStartupSchemaSync: true,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
for k, v := range test.envVars {
t.Setenv(k, v)
}
cfg, err := parseClusterConfig()
if test.expectedErr != nil {
assert.EqualError(t, err, test.expectedErr.Error(),
"expected err: %v, got: %v", test.expectedErr, err)
} else {
assert.Nil(t, err, "expected nil, got: %v", err)
assert.EqualValues(t, test.expectedResult, cfg)
}
})
}
}
func TestEnvironmentSetDefaultVectorDistanceMetric(t *testing.T) {
t.Run("DefaultVectorDistanceMetricIsEmpty", func(t *testing.T) {
os.Clearenv()
conf := Config{}
FromEnv(&conf)
require.Equal(t, "", conf.DefaultVectorDistanceMetric)
})
t.Run("NonEmptyDefaultVectorDistanceMetric", func(t *testing.T) {
os.Clearenv()
t.Setenv("DEFAULT_VECTOR_DISTANCE_METRIC", "l2-squared")
conf := Config{}
FromEnv(&conf)
require.Equal(t, "l2-squared", conf.DefaultVectorDistanceMetric)
})
}
func TestEnvironmentMaxConcurrentGetRequests(t *testing.T) {
factors := []struct {
name string
value []string
expected int
expectedErr bool
}{
{"Valid", []string{"100"}, 100, false},
{"not given", []string{}, DefaultMaxConcurrentGetRequests, false},
{"unlimited", []string{"-1"}, -1, false},
{"not parsable", []string{"I'm not a number"}, -1, true},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.value) == 1 {
t.Setenv("MAXIMUM_CONCURRENT_GET_REQUESTS", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.MaximumConcurrentGetRequests)
}
})
}
}
func TestEnvironmentCORS_Origin(t *testing.T) {
factors := []struct {
name string
value []string
expected string
expectedErr bool
}{
{"Valid", []string{"http://foo.com"}, "http://foo.com", false},
{"not given", []string{}, DefaultCORSAllowOrigin, false},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
os.Clearenv()
if len(tt.value) == 1 {
os.Setenv("CORS_ALLOW_ORIGIN", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.CORS.AllowOrigin)
}
})
}
}
func TestEnvironmentGRPCPort(t *testing.T) {
factors := []struct {
name string
value []string
expected int
expectedErr bool
}{
{"Valid", []string{"50052"}, 50052, false},
{"not given", []string{}, DefaultGRPCPort, false},
{"invalid factor", []string{"-1"}, -1, true},
{"zero factor", []string{"0"}, -1, true},
{"not parsable", []string{"I'm not a number"}, -1, true},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.value) == 1 {
t.Setenv("GRPC_PORT", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.GRPC.Port)
}
})
}
}
func TestEnvironmentCORS_Methods(t *testing.T) {
factors := []struct {
name string
value []string
expected string
expectedErr bool
}{
{"Valid", []string{"POST"}, "POST", false},
{"not given", []string{}, DefaultCORSAllowMethods, false},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
os.Clearenv()
if len(tt.value) == 1 {
os.Setenv("CORS_ALLOW_METHODS", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.CORS.AllowMethods)
}
})
}
}
func TestEnvironmentDisableGraphQL(t *testing.T) {
factors := []struct {
name string
value []string
expected bool
expectedErr bool
}{
{"Valid: true", []string{"true"}, true, false},
{"Valid: false", []string{"false"}, false, false},
{"Valid: 1", []string{"1"}, true, false},
{"Valid: 0", []string{"0"}, false, false},
{"Valid: on", []string{"on"}, true, false},
{"Valid: off", []string{"off"}, false, false},
{"not given", []string{}, false, false},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.value) == 1 {
t.Setenv("DISABLE_GRAPHQL", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.DisableGraphQL)
}
})
}
}
func TestEnvironmentCORS_Headers(t *testing.T) {
factors := []struct {
name string
value []string
expected string
expectedErr bool
}{
{"Valid", []string{"Authorization"}, "Authorization", false},
{"not given", []string{}, DefaultCORSAllowHeaders, false},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
os.Clearenv()
if len(tt.value) == 1 {
os.Setenv("CORS_ALLOW_HEADERS", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.CORS.AllowHeaders)
}
})
}
}
func TestEnvironmentPrometheusGroupClasses_OldName(t *testing.T) {
factors := []struct {
name string
value []string
expected bool
expectedErr bool
}{
{"Valid: true", []string{"true"}, true, false},
{"Valid: false", []string{"false"}, false, false},
{"Valid: 1", []string{"1"}, true, false},
{"Valid: 0", []string{"0"}, false, false},
{"Valid: on", []string{"on"}, true, false},
{"Valid: off", []string{"off"}, false, false},
{"not given", []string{}, false, false},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("PROMETHEUS_MONITORING_ENABLED", "true")
if len(tt.value) == 1 {
t.Setenv("PROMETHEUS_MONITORING_GROUP_CLASSES", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.Monitoring.Group)
}
})
}
}
func TestEnvironmentPrometheusGroupClasses_NewName(t *testing.T) {
factors := []struct {
name string
value []string
expected bool
expectedErr bool
}{
{"Valid: true", []string{"true"}, true, false},
{"Valid: false", []string{"false"}, false, false},
{"Valid: 1", []string{"1"}, true, false},
{"Valid: 0", []string{"0"}, false, false},
{"Valid: on", []string{"on"}, true, false},
{"Valid: off", []string{"off"}, false, false},
{"not given", []string{}, false, false},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("PROMETHEUS_MONITORING_ENABLED", "true")
if len(tt.value) == 1 {
t.Setenv("PROMETHEUS_MONITORING_GROUP", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.Monitoring.Group)
}
})
}
}
func TestEnvironmentMinimumReplicationFactor(t *testing.T) {
factors := []struct {
name string
value []string
expected int
expectedErr bool
}{
{"Valid", []string{"3"}, 3, false},
{"not given", []string{}, DefaultMinimumReplicationFactor, false},
{"invalid factor", []string{"-1"}, -1, true},
{"zero factor", []string{"0"}, -1, true},
{"not parsable", []string{"I'm not a number"}, -1, true},
}
for _, tt := range factors {
t.Run(tt.name, func(t *testing.T) {
if len(tt.value) == 1 {
t.Setenv("REPLICATION_MINIMUM_FACTOR", tt.value[0])
}
conf := Config{}
err := FromEnv(&conf)
if tt.expectedErr {
require.NotNil(t, err)
} else {
require.Equal(t, tt.expected, conf.Replication.MinimumFactor)
}
})
}
}