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  }