From 7dde71505c7bc4d54d97537e79344d9452211f57 Mon Sep 17 00:00:00 2001 From: matheusgomes28 Date: Tue, 20 Feb 2024 12:00:25 +0000 Subject: [PATCH] Adding a simple toml parser and cmd-line parser --- .air.toml | 2 +- cmd/urchin/main.go | 27 +++- common/app_settings.go | 24 +++- common/app_settings_test.go | 254 ++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 + urchin_config.toml | 18 +++ 7 files changed, 316 insertions(+), 12 deletions(-) create mode 100644 common/app_settings_test.go create mode 100644 urchin_config.toml diff --git a/.air.toml b/.air.toml index 95f91b9..b9d186a 100644 --- a/.air.toml +++ b/.air.toml @@ -6,7 +6,7 @@ tmp_dir = "tmp" cmd = "make build" args_bin = [] bin = "./tmp/urchin" - full_bin = "URCHIN_WEBSERVER_PORT=8080 URCHIN_DATABASE_ADDRESS=mariadb URCHIN_DATABASE_PORT=3306 URCHIN_DATABASE_USER=root URCHIN_DATABASE_PASSWORD=root URCHIN_DATABASE_NAME=urchin ./tmp/urchin" + full_bin = "./tmp/urchin --config urchin_config.toml" delay = 1000 exclude_dir = ["assets", "tmp", "vendor", "testdata"] exclude_file = [] diff --git a/cmd/urchin/main.go b/cmd/urchin/main.go index 9878ea3..3b100d8 100644 --- a/cmd/urchin/main.go +++ b/cmd/urchin/main.go @@ -1,6 +1,7 @@ package main import ( + "flag" "fmt" "os" @@ -12,11 +13,27 @@ import ( ) func main() { - /// Load global application settings - app_settings, err := common.LoadSettings() - if err != nil { - log.Error().Msgf("could not get app settings: %v\n", err) - os.Exit(-1) + config_toml := flag.String("config", "", "path to the config to be used") + flag.Parse() + + var app_settings common.AppSettings + if (*config_toml) != "" { + log.Info().Msgf("reading config file %s", *config_toml) + settings, err := common.ReadConfigToml(*config_toml) + if err != nil { + log.Error().Msgf("could not read config file: %v", err) + os.Exit(-1) + } + + app_settings = settings + } else { + log.Info().Msgf("no config file, reading environment variables") + settings, err := common.LoadSettings() + if err != nil { + log.Error().Msgf("could not load settings: %v", err) + os.Exit(-1) + } + app_settings = settings } db_connection, err := database.MakeSqlConnection( diff --git a/common/app_settings.go b/common/app_settings.go index 334537b..2aaa6ed 100644 --- a/common/app_settings.go +++ b/common/app_settings.go @@ -4,15 +4,17 @@ import ( "fmt" "os" "strconv" + + "github.com/BurntSushi/toml" ) type AppSettings struct { - DatabaseAddress string - DatabasePort int - DatabaseUser string - DatabasePassword string - DatabaseName string - WebserverPort int + DatabaseAddress string `toml:"database_address"` + DatabasePort int `toml:"database_port"` + DatabaseUser string `toml:"database_user"` + DatabasePassword string `toml:"database_password"` + DatabaseName string `toml:"database_name"` + WebserverPort int `toml:"webserver_port"` } func LoadSettings() (AppSettings, error) { @@ -66,3 +68,13 @@ func LoadSettings() (AppSettings, error) { WebserverPort: webserver_port, }, nil } + +func ReadConfigToml(filepath string) (AppSettings, error) { + var config AppSettings + _, err := toml.DecodeFile(filepath, &config) + if err != nil { + return AppSettings{}, err + } + + return config, nil +} diff --git a/common/app_settings_test.go b/common/app_settings_test.go new file mode 100644 index 0000000..324a875 --- /dev/null +++ b/common/app_settings_test.go @@ -0,0 +1,254 @@ +package common + +import ( + "errors" + "os" + "testing" + + "github.com/pelletier/go-toml/v2" + "github.com/stretchr/testify/assert" +) + +// Writes the contents into a temporary +// toml file +func writeToml(contents []byte) (s string, err error) { + file, err := os.CreateTemp(os.TempDir(), "*.toml") + if err != nil { + return "", err + } + defer func() { + err = errors.Join(file.Close(), err) + }() + + _, err = file.Write(contents) + if err != nil { + return "", err + } + return file.Name(), nil +} + +func TestCorrectToml(t *testing.T) { + expected := AppSettings{ + DatabaseAddress: "test_database_address", + DatabaseUser: "test_database_user", + DatabasePassword: "test_database_password", + DatabaseName: "test_database_name", + WebserverPort: 99999, + DatabasePort: 666, + } + bytes, err := toml.Marshal(expected) + assert.Nil(t, err) + + filepath, err := writeToml(bytes) + assert.Nil(t, err) + + actual, err := ReadConfigToml(filepath) + assert.Nil(t, err) + assert.Equal(t, actual, expected) +} + +func TestMissingDatabaseAddress(t *testing.T) { + + missing_database_address := struct { + DatabaseUser string `toml:"database_user"` + DatabasePassword string `toml:"database_password"` + DatabaseName string `toml:"database_name"` + WebserverPort string `toml:"webserver_port"` + DatabasePort string `toml:"database_port"` + }{ + DatabaseUser: "test_database_user", + DatabasePassword: "test_database_password", + DatabaseName: "test_database_name", + WebserverPort: "99999", + DatabasePort: "666", + } + + bytes, err := toml.Marshal(missing_database_address) + assert.Nil(t, err) + + filepath, err := writeToml(bytes) + assert.Nil(t, err) + + _, err = ReadConfigToml(filepath) + assert.NotNil(t, err) +} + +func TestMissingDatabaseUser(t *testing.T) { + + missing_database_user := struct { + DatabaseAddress string `toml:"database_address"` + DatabasePassword string `toml:"database_password"` + DatabaseName string `toml:"database_name"` + WebserverPort string `toml:"webserver_port"` + DatabasePort string `toml:"database_port"` + }{ + DatabaseAddress: "test_database_address", + DatabasePassword: "test_database_password", + DatabaseName: "test_database_name", + WebserverPort: "99999", + DatabasePort: "666", + } + + bytes, err := toml.Marshal(missing_database_user) + assert.Nil(t, err) + + filepath, err := writeToml(bytes) + assert.Nil(t, err) + + _, err = ReadConfigToml(filepath) + assert.NotNil(t, err) +} + +func TestMissingDatabasePassword(t *testing.T) { + missing_database_password := struct { + DatabaseAddress string `toml:"database_address"` + DatabaseUser string `toml:"database_user"` + DatabaseName string `toml:"database_name"` + WebserverPort string `toml:"webserver_port"` + DatabasePort string `toml:"database_port"` + }{ + DatabaseAddress: "test_database_address", + DatabaseUser: "test_database_user", + DatabaseName: "test_database_name", + WebserverPort: "99999", + DatabasePort: "666", + } + + bytes, err := toml.Marshal(missing_database_password) + assert.Nil(t, err) + + filepath, err := writeToml(bytes) + assert.Nil(t, err) + + _, err = ReadConfigToml(filepath) + assert.NotNil(t, err) +} + +func TestMissingDatabaseName(t *testing.T) { + missing_database_name := struct { + DatabaseAddress string `toml:"database_address"` + DatabaseUser string `toml:"database_user"` + DatabasePassword string `toml:"database_password"` + WebserverPort string `toml:"webserver_port"` + DatabasePort string `toml:"database_port"` + }{ + DatabaseAddress: "test_database_address", + DatabaseUser: "test_database_user", + DatabasePassword: "test_database_password", + WebserverPort: "99999", + DatabasePort: "666", + } + + bytes, err := toml.Marshal(missing_database_name) + assert.Nil(t, err) + + filepath, err := writeToml(bytes) + assert.Nil(t, err) + + _, err = ReadConfigToml(filepath) + assert.NotNil(t, err) +} + +func TestMissingWebserverPort(t *testing.T) { + missing_webserver_port := struct { + DatabaseAddress string `toml:"database_address"` + DatabaseUser string `toml:"database_user"` + DatabasePassword string `toml:"database_password"` + DatabaseName string `toml:"database_name"` + DatabasePort string `toml:"database_port"` + }{ + DatabaseAddress: "test_database_address", + DatabaseUser: "test_database_user", + DatabasePassword: "test_database_password", + DatabaseName: "test_database_name", + DatabasePort: "666", + } + + bytes, err := toml.Marshal(missing_webserver_port) + assert.Nil(t, err) + + filepath, err := writeToml(bytes) + assert.Nil(t, err) + + _, err = ReadConfigToml(filepath) + assert.NotNil(t, err) +} + +func TestMissingDatabasePort(t *testing.T) { + missing_database_address := struct { + DatabaseAddress string `toml:"database_address"` + DatabaseUser string `toml:"database_user"` + DatabasePassword string `toml:"database_password"` + DatabaseName string `toml:"database_name"` + WebserverPort string `toml:"webserver_port"` + }{ + DatabaseAddress: "test_database_address", + DatabaseUser: "test_database_user", + DatabasePassword: "test_database_password", + DatabaseName: "test_database_name", + WebserverPort: "99999", + } + + bytes, err := toml.Marshal(missing_database_address) + assert.Nil(t, err) + + filepath, err := writeToml(bytes) + assert.Nil(t, err) + + _, err = ReadConfigToml(filepath) + assert.NotNil(t, err) +} + +func TestWrongDatabasePortValueType(t *testing.T) { + missing_database_address := struct { + DatabaseAddress string `toml:"database_address"` + DatabaseUser string `toml:"database_user"` + DatabasePassword string `toml:"database_password"` + DatabaseName string `toml:"database_name"` + DatabasePort string `toml:"database_port"` + WebserverPort int `toml:"webserver_port"` + }{ + DatabaseAddress: "test_database_address", + DatabaseUser: "test_database_user", + DatabasePassword: "test_database_password", + DatabaseName: "test_database_name", + DatabasePort: "String Should Not Work", + WebserverPort: 99999, + } + + bytes, err := toml.Marshal(missing_database_address) + assert.Nil(t, err) + + filepath, err := writeToml(bytes) + assert.Nil(t, err) + + _, err = ReadConfigToml(filepath) + assert.NotNil(t, err) +} + +func TestWrongwebserverPortValueType(t *testing.T) { + missing_database_address := struct { + DatabaseAddress string `toml:"database_address"` + DatabaseUser string `toml:"database_user"` + DatabasePassword string `toml:"database_password"` + DatabaseName string `toml:"database_name"` + DatabasePort int `toml:"database_port"` + WebserverPort string `toml:"webserver_port"` + }{ + DatabaseAddress: "test_database_address", + DatabaseUser: "test_database_user", + DatabasePassword: "test_database_password", + DatabaseName: "test_database_name", + DatabasePort: 10, + WebserverPort: "99999", + } + + bytes, err := toml.Marshal(missing_database_address) + assert.Nil(t, err) + + filepath, err := writeToml(bytes) + assert.Nil(t, err) + + _, err = ReadConfigToml(filepath) + assert.NotNil(t, err) +} diff --git a/go.mod b/go.mod index b2af3bf..b820d55 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( ) require ( + github.com/BurntSushi/toml v1.3.2 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index 6c5e826..2eebcad 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/a-h/templ v0.2.543 h1:8YyLvyUtf0/IE2nIwZ62Z/m2o2NqwhnMynzOL78Lzbk= github.com/a-h/templ v0.2.543/go.mod h1:jP908DQCwI08IrnTalhzSEH9WJqG/Q94+EODQcJGFUA= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= diff --git a/urchin_config.toml b/urchin_config.toml new file mode 100644 index 0000000..be27741 --- /dev/null +++ b/urchin_config.toml @@ -0,0 +1,18 @@ +# Address to the MariaDB database +database_address = "localhost" + +# User to access datbaase +database_user = "root" + +# Password for the database user +database_password = "root" + +# port +database_port = 3006 + +# name of database where urchin's +# migrations was installed +database_name = "urchin" + +# port to run the webserver on +webserver_port = 8080