github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/config/config_test.go (about) 1 package config_test 2 3 import ( 4 "bufio" 5 "context" 6 "encoding/json" 7 "errors" 8 "os" 9 "strings" 10 "testing" 11 12 awsconfig "github.com/aws/aws-sdk-go-v2/config" 13 "github.com/go-test/deep" 14 "github.com/spf13/viper" 15 "github.com/treeverse/lakefs/pkg/block/factory" 16 "github.com/treeverse/lakefs/pkg/block/gs" 17 "github.com/treeverse/lakefs/pkg/block/local" 18 "github.com/treeverse/lakefs/pkg/config" 19 "github.com/treeverse/lakefs/pkg/kv/kvparams" 20 "github.com/treeverse/lakefs/pkg/logging" 21 "github.com/treeverse/lakefs/pkg/testutil" 22 ) 23 24 func newConfigFromFile(fn string) (*config.Config, error) { 25 viper.SetConfigFile(fn) 26 err := viper.ReadInConfig() 27 if err != nil { 28 return nil, err 29 } 30 cfg, err := config.NewConfig("") 31 if err != nil { 32 return nil, err 33 } 34 err = cfg.Validate() 35 return cfg, err 36 } 37 38 func TestConfig_Setup(t *testing.T) { 39 // test defaults 40 c, err := config.NewConfig("") 41 testutil.Must(t, err) 42 // Don't validate, some tested configs don't have all required fields. 43 if c.ListenAddress != config.DefaultListenAddress { 44 t.Fatalf("expected listen addr '%s', got '%s'", config.DefaultListenAddress, c.ListenAddress) 45 } 46 } 47 48 func TestConfig_NewFromFile(t *testing.T) { 49 t.Run("valid config", func(t *testing.T) { 50 c, err := newConfigFromFile("testdata/valid_config.yaml") 51 testutil.Must(t, err) 52 if c.ListenAddress != "0.0.0.0:8005" { 53 t.Fatalf("expected listen addr 0.0.0.0:8005, got %s", c.ListenAddress) 54 } 55 if diffs := deep.Equal([]string(c.Gateways.S3.DomainNames), []string{"s3.example.com", "gs3.example.com", "gcp.example.net"}); diffs != nil { 56 t.Fatalf("expected domain name s3.example.com, diffs %s", diffs) 57 } 58 }) 59 60 t.Run("invalid config", func(t *testing.T) { 61 _, err := newConfigFromFile("testdata/invalid_config.yaml") 62 // viper errors are not 63 if err == nil || !strings.HasPrefix(err.Error(), "While parsing config:") { 64 t.Fatalf("expected invalid configuration file to fail, got %v", err) 65 } 66 }) 67 68 t.Run("missing config", func(t *testing.T) { 69 _, err := newConfigFromFile("testdata/valid_configgggggggggggggggg.yaml") 70 if !errors.Is(err, os.ErrNotExist) { 71 t.Fatalf("expected missing configuration file to fail, got %v", err) 72 } 73 }) 74 } 75 76 func pushEnv(key, value string) func() { 77 oldValue := os.Getenv(key) 78 _ = os.Setenv(key, value) 79 return func() { 80 _ = os.Setenv(key, oldValue) 81 } 82 } 83 84 func TestConfig_EnvironmentVariables(t *testing.T) { 85 const dbString = "not://a/database" 86 defer pushEnv("LAKEFS_DATABASE_POSTGRES_CONNECTION_STRING", dbString)() 87 88 viper.SetEnvPrefix("LAKEFS") 89 viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) // support nested config 90 // read in environment variables 91 viper.AutomaticEnv() 92 93 c, err := newConfigFromFile("testdata/valid_config.yaml") 94 testutil.Must(t, err) 95 kvParams, err := kvparams.NewConfig(c) 96 testutil.Must(t, err) 97 if kvParams.Postgres.ConnectionString != dbString { 98 t.Errorf("got DB connection string %s, expected to override to %s", kvParams.Postgres.ConnectionString, dbString) 99 } 100 } 101 102 func TestConfig_DomainNamePrefix(t *testing.T) { 103 _, err := newConfigFromFile("testdata/domain_name_prefix.yaml") 104 if !errors.Is(err, config.ErrBadDomainNames) { 105 t.Errorf("got error %s not %s", err, config.ErrBadDomainNames) 106 } 107 } 108 109 func TestConfig_BuildBlockAdapter(t *testing.T) { 110 ctx := context.Background() 111 t.Run("local block adapter", func(t *testing.T) { 112 c, err := newConfigFromFile("testdata/valid_config.yaml") 113 testutil.Must(t, err) 114 adapter, err := factory.BuildBlockAdapter(ctx, nil, c) 115 testutil.Must(t, err) 116 if _, ok := adapter.(*local.Adapter); !ok { 117 t.Fatalf("expected a local block adapter, got something else instead") 118 } 119 }) 120 121 t.Run("s3 block adapter", func(t *testing.T) { 122 c, err := newConfigFromFile("testdata/valid_s3_adapter_config.yaml") 123 testutil.Must(t, err) 124 125 _, err = factory.BuildBlockAdapter(ctx, nil, c) 126 var errProfileNotExists awsconfig.SharedConfigProfileNotExistError 127 if !errors.As(err, &errProfileNotExists) { 128 t.Fatalf("expected a config.SharedConfigProfileNotExistError, got '%v'", err) 129 } 130 }) 131 132 t.Run("gs block adapter", func(t *testing.T) { 133 c, err := newConfigFromFile("testdata/valid_gs_adapter_config.yaml") 134 testutil.Must(t, err) 135 adapter, err := factory.BuildBlockAdapter(ctx, nil, c) 136 testutil.Must(t, err) 137 if _, ok := adapter.(*gs.Adapter); !ok { 138 t.Fatalf("expected an gs block adapter, got something else instead") 139 } 140 }) 141 } 142 143 func TestConfig_JSONLogger(t *testing.T) { 144 logfile := "/tmp/lakefs_json_logger_test.log" 145 _ = os.Remove(logfile) 146 _, err := newConfigFromFile("testdata/valid_json_logger_config.yaml") 147 testutil.Must(t, err) 148 149 logging.ContextUnavailable().Info("some message that I should be looking for") 150 151 content, err := os.Open(logfile) 152 if err != nil { 153 t.Fatalf("unexpected error reading log file: %s", err) 154 } 155 defer func() { 156 _ = content.Close() 157 }() 158 reader := bufio.NewReader(content) 159 line, err := reader.ReadString('\n') 160 if err != nil { 161 t.Fatalf("could not read line from logfile: %s", err) 162 } 163 m := make(map[string]string) 164 err = json.Unmarshal([]byte(line), &m) 165 if err != nil { 166 t.Fatalf("could not parse JSON line from logfile: %s", err) 167 } 168 if _, ok := m["msg"]; !ok { 169 t.Fatalf("expected a msg field, could not find one") 170 } 171 }