Skip to content

Commit

Permalink
fix: fix .env file parser, add test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
soulteary committed Jan 6, 2024
1 parent 4462acd commit 7a43896
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 96 deletions.
101 changes: 74 additions & 27 deletions cmd/envfile.go
Original file line number Diff line number Diff line change
@@ -1,60 +1,107 @@
package FlareCMD

import (
"log/slog"
"fmt"
"os"
"path"
"strings"

FlareDefine "github.com/soulteary/flare/config/define"
FlareModel "github.com/soulteary/flare/config/model"
FlareFn "github.com/soulteary/flare/internal/fn"
FlareLogger "github.com/soulteary/flare/internal/logger"
"gopkg.in/ini.v1"
)

func CheckDotEnvFileExist(filePath string) bool {
if _, err := os.Stat(filePath); os.IsNotExist(err) {
log := FlareLogger.GetLogger()
log.Debug("默认的 .env 文件不存在,跳过解析。")
return false
}
return true
}

func GetDotEnvFileStringOrDefault(envs *ini.File, key string, def string) string {
value := strings.TrimSpace(envs.Section("").Key(key).String())
if value == "" {
log := FlareLogger.GetLogger()
log.Debug(fmt.Sprintf("%s 配置文件值为空,使用默认值。", key))
return def
}
return value
}

func GetDotEnvFileBoolOrDefault(envs *ini.File, key string, def bool) bool {
value, err := envs.Section("").Key(key).Bool()
if err != nil {
log := FlareLogger.GetLogger()
log.Debug(fmt.Sprintf("%s 配置文件值异常,使用默认值。", key))
return def
}
return value
}

func ParseEnvFile(baseFlags FlareModel.Flags) FlareModel.Flags {
log := FlareLogger.GetLogger()

workDir, _ := os.Getwd()
envPath := path.Join(workDir, ".env")
envPath := FlareFn.GetWorkDirFile(".env")

if _, err := os.Stat(envPath); os.IsNotExist(err) {
log.Debug("默认的 .env 文件不存在,跳过解析。")
if !CheckDotEnvFileExist(envPath) {
return baseFlags
}

envs, err := ini.Load(envPath)
if err != nil {
log.Error("解析 .env 文件出错,请检查文件格式或程序是否具备文件读取权限。", slog.Any("error", err))
os.Exit(1)
log.Error("解析 .env 文件出错,请检查文件格式或程序是否具备文件读取权限。")
log.Warn("程序将使用默认配置继续运行。")
return baseFlags
}

defaults := FlareDefine.GetDefaultEnvVars()
err = envs.MapTo(&FlareModel.Envs{})
if err != nil {
log.Error("解析 .env 文件出错,请检查文件内容是否正确。")
log.Warn("程序使用默认配置继续运行。")
return baseFlags
}

port, err := envs.Section("").Key("FLARE_PORT").Int()
if err != nil {
log.Warn("FLARE_PORT 的值不是有效的数字,使用默认值。")
} else {
if port < 1 || port > 65535 {
log.Warn("FLARE_PORT 的值不在有效范围内,使用默认值。")
} else {
baseFlags.Port = port
}
}

err = envs.MapTo(&defaults)
user := GetDotEnvFileStringOrDefault(envs, "FLARE_USER", baseFlags.User)
baseFlags.User = user

if envs.Section("").Key("FLARE_PASS") != nil {
baseFlags.User = defaults.Pass
defaults := FlareDefine.GetDefaultEnvVars()

if user == defaults.User {
baseFlags.UserIsGenerated = false
baseFlags.PassIsGenerated = false
} else {
baseFlags.UserIsGenerated = true
}

if err != nil {
log.Error("解析 .env 文件出错,请检查文件内容是否正确。", slog.Any("error", err))
os.Exit(1)
pass := GetDotEnvFileStringOrDefault(envs, "FLARE_PASS", baseFlags.Pass)
baseFlags.Pass = pass
if pass == defaults.Pass {
baseFlags.UserIsGenerated = false
} else {
baseFlags.Port = defaults.Port
baseFlags.EnableGuide = defaults.EnableGuide
baseFlags.EnableDeprecatedNotice = defaults.EnableDeprecatedNotice
baseFlags.EnableMinimumRequest = defaults.EnableMinimumRequest
baseFlags.EnableOfflineMode = defaults.EnableOfflineMode
baseFlags.EnableEditor = defaults.EnableEditor
baseFlags.DisableCSP = defaults.DisableCSP
baseFlags.Visibility = defaults.Visibility
baseFlags.DisableLoginMode = defaults.DisableLoginMode
baseFlags.User = defaults.User
baseFlags.Pass = defaults.Pass
baseFlags.UserIsGenerated = true
}

baseFlags.DisableLoginMode = GetDotEnvFileBoolOrDefault(envs, "FLARE_DISABLE_LOGIN", baseFlags.DisableLoginMode)
baseFlags.DisableCSP = GetDotEnvFileBoolOrDefault(envs, "FLARE_DISABLE_CSP", baseFlags.DisableCSP)
baseFlags.EnableDeprecatedNotice = GetDotEnvFileBoolOrDefault(envs, "FLARE_DEPRECATED_NOTICE", baseFlags.EnableDeprecatedNotice)
baseFlags.EnableMinimumRequest = GetDotEnvFileBoolOrDefault(envs, "FLARE_MINI_REQUEST", baseFlags.EnableMinimumRequest)
baseFlags.EnableOfflineMode = GetDotEnvFileBoolOrDefault(envs, "FLARE_OFFLINE", baseFlags.EnableOfflineMode)
baseFlags.EnableEditor = GetDotEnvFileBoolOrDefault(envs, "FLARE_EDITOR", baseFlags.EnableEditor)
baseFlags.EnableGuide = GetDotEnvFileBoolOrDefault(envs, "FLARE_GUIDE", baseFlags.EnableGuide)
baseFlags.Visibility = GetDotEnvFileStringOrDefault(envs, "FLARE_VISIBILITY", baseFlags.Visibility)

return baseFlags
}
187 changes: 118 additions & 69 deletions cmd/envfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,90 +2,139 @@ package FlareCMD_test

import (
"os"
"path"
"testing"

FlareCMD "github.com/soulteary/flare/cmd"
FlareDefine "github.com/soulteary/flare/config/define"
FlareFn "github.com/soulteary/flare/internal/fn"
"github.com/stretchr/testify/assert"
)

func TestCheckDotEnvFileExist(t *testing.T) {
envPath := FlareFn.GetWorkDirFile(".env")

// test .env not exist
os.Remove(envPath)
assert.Equal(t, FlareCMD.CheckDotEnvFileExist(envPath), false)

// test .env exist
f, _ := os.Create(envPath)
defer os.Remove(f.Name())
assert.Equal(t, FlareCMD.CheckDotEnvFileExist(envPath), true)
}

func TestParseEnvFile_NotExist(t *testing.T) {
os.Setenv("FLARE_DEBUG", "true")
defer os.Unsetenv("FLARE_DEBUG")

envParsed := FlareCMD.ParseEnvVars()

workDir, _ := os.Getwd()
envPath := path.Join(workDir, ".env")
envPath := FlareFn.GetWorkDirFile(".env")

// test .env not exist
os.Remove(envPath)
flags := FlareCMD.ParseEnvFile(envParsed)
defaultEnvs := FlareDefine.GetDefaultEnvVars()

assert.Equal(t, flags.Port, defaultEnvs.Port)
assert.Equal(t, flags.EnableGuide, defaultEnvs.EnableGuide)
assert.Equal(t, flags.EnableDeprecatedNotice, defaultEnvs.EnableDeprecatedNotice)
assert.Equal(t, flags.EnableMinimumRequest, defaultEnvs.EnableMinimumRequest)
assert.Equal(t, flags.DisableLoginMode, defaultEnvs.DisableLoginMode)
assert.Equal(t, flags.Visibility, defaultEnvs.Visibility)
assert.Equal(t, flags.EnableOfflineMode, defaultEnvs.EnableOfflineMode)
assert.Equal(t, flags.EnableEditor, defaultEnvs.EnableEditor)
assert.Equal(t, flags, envParsed)
}

// func TestParseEnvFile_Normal(t *testing.T) {
// os.Setenv("FLARE_DEBUG", "true")
// defer os.Unsetenv("FLARE_DEBUG")

// envParsed := FlareCMD.ParseEnvVars()

// workDir, _ := os.Getwd()
// envPath := path.Join(workDir, ".env")

// // test normal
// os.Remove(envPath)
// f, _ := os.Create(envPath)
// defer os.Remove(f.Name())
// f.Write([]byte("FLARE_PORT=5000\nFLARE_GUIDE=false\nFLARE_OFFLINE=true\nFLARE_VISIBILITY=private"))
// flags := FlareCMD.ParseEnvFile(envParsed)
// assert.Equal(t, flags.Port, 5000)
// assert.Equal(t, flags.EnableGuide, false)
// assert.Equal(t, flags.EnableOfflineMode, true)
// assert.Equal(t, flags.Visibility, "private")
// }

// func TestParseEnvFile_EmptyConfig(t *testing.T) {
// os.Setenv("FLARE_DEBUG", "true")
// defer os.Unsetenv("FLARE_DEBUG")

// envParsed := FlareCMD.ParseEnvVars()
// defaultEnvs := FlareDefine.GetDefaultEnvVars()

// workDir, _ := os.Getwd()
// envPath := path.Join(workDir, ".env")

// // test empty .env
// os.Remove(envPath)
// f, _ := os.Create(envPath)
// defer os.Remove(f.Name())
// f.Write([]byte(""))
// flags := FlareCMD.ParseEnvFile(envParsed)
// assert.Equal(t, flags.Port, defaultEnvs.Port)
// assert.Equal(t, flags.EnableGuide, defaultEnvs.EnableGuide)
// assert.Equal(t, flags.EnableDeprecatedNotice, defaultEnvs.EnableDeprecatedNotice)
// assert.Equal(t, flags.EnableMinimumRequest, defaultEnvs.EnableMinimumRequest)
// assert.Equal(t, flags.DisableLoginMode, defaultEnvs.DisableLoginMode)
// assert.Equal(t, flags.Visibility, defaultEnvs.Visibility)
// assert.Equal(t, flags.EnableOfflineMode, defaultEnvs.EnableOfflineMode)
// assert.Equal(t, flags.EnableEditor, defaultEnvs.EnableEditor)
// }

// func TestParseEnvFile(t *testing.T) {
// // test unmarshal error
// // os.MkdirAll(".env", 0755)
// // defer os.Remove(".env")
// // flags := FlareCMD.ParseEnvFile(envParsed)
// // defaultEnvs := FlareDefine.GetDefaultEnvVars()
// // assert.Equal(t, flags.Port, defaultEnvs.Port)
// }
func TestParseEnvFile_NotParsed(t *testing.T) {
os.Setenv("FLARE_DEBUG", "true")
defer os.Unsetenv("FLARE_DEBUG")

envParsed := FlareCMD.ParseEnvVars()
envPath := FlareFn.GetWorkDirFile(".env")

// test .env not exist
os.Mkdir(envPath, 0755)
defer os.Remove(envPath)
flags := FlareCMD.ParseEnvFile(envParsed)
assert.Equal(t, flags, envParsed)
}

func TestParseEnvFile_ParseErr(t *testing.T) {
os.Setenv("FLARE_DEBUG", "true")
defer os.Unsetenv("FLARE_DEBUG")

envParsed := FlareCMD.ParseEnvVars()
envPath := FlareFn.GetWorkDirFile(".env")
envParsed.Port = 1234
envParsed.User = "123"
envParsed.UserIsGenerated = true
envParsed.Pass = "123"
envParsed.PassIsGenerated = true

// test .env auto correct
f, _ := os.Create(envPath)
defer os.Remove(envPath)
f.Write([]byte("FLARE_PORT=true\nFLARE_USER=\nFLARE_PASS=\nFLARE_GUIDE=1111"))
flags := FlareCMD.ParseEnvFile(envParsed)
assert.Equal(t, flags, envParsed)
}

func TestParseEnvFile_ParseOverwrite(t *testing.T) {
os.Setenv("FLARE_DEBUG", "true")
defer os.Unsetenv("FLARE_DEBUG")

envParsed := FlareCMD.ParseEnvVars()
envPath := FlareFn.GetWorkDirFile(".env")
envParsed.Port = 1234
envParsed.User = "123"
envParsed.UserIsGenerated = true
envParsed.Pass = "123"
envParsed.PassIsGenerated = true

// test .env auto correct
f, _ := os.Create(envPath)
defer os.Remove(envPath)
f.Write([]byte("FLARE_PORT=2345\nFLARE_USER=\nFLARE_PASS=\nFLARE_GUIDE=false"))
flags := FlareCMD.ParseEnvFile(envParsed)

envParsed.Port = 2345
envParsed.EnableGuide = false

assert.Equal(t, flags, envParsed)
}

func TestParseEnvFile_PortError(t *testing.T) {
os.Setenv("FLARE_DEBUG", "true")
defer os.Unsetenv("FLARE_DEBUG")

envParsed := FlareCMD.ParseEnvVars()
envPath := FlareFn.GetWorkDirFile(".env")
envParsed.Port = 1234
envParsed.User = "123"
envParsed.UserIsGenerated = true
envParsed.Pass = "123"
envParsed.PassIsGenerated = true

// test .env auto correct
f, _ := os.Create(envPath)
defer os.Remove(envPath)
f.Write([]byte("FLARE_PORT=9999999\nFLARE_USER=\nFLARE_PASS=\nFLARE_GUIDE=false"))
flags := FlareCMD.ParseEnvFile(envParsed)

envParsed.EnableGuide = false

assert.Equal(t, flags, envParsed)
}

func TestParseEnvFile_User(t *testing.T) {
os.Setenv("FLARE_DEBUG", "true")
defer os.Unsetenv("FLARE_DEBUG")

defaults := FlareDefine.GetDefaultEnvVars()

envParsed := FlareCMD.ParseEnvVars()
envPath := FlareFn.GetWorkDirFile(".env")
envParsed.User = defaults.User
envParsed.Pass = defaults.Pass
envParsed.UserIsGenerated = false
envParsed.PassIsGenerated = false

// test .env auto correct
f, _ := os.Create(envPath)
defer os.Remove(envPath)
f.Write([]byte("FLARE_PORT=5005\nFLARE_USER=flare\nFLARE_PASS=\n"))
flags := FlareCMD.ParseEnvFile(envParsed)

assert.Equal(t, flags, envParsed)
}
3 changes: 3 additions & 0 deletions config/define/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@ func GetDefaultEnvVars() FlareModel.Envs {
EnableEditor: DEFAULT_ENABLE_EDITOR,
Visibility: DEFAULT_VISIBILITY,
DisableCSP: DEFAULT_DISABLE_CSP,

User: DEFAULT_USER_NAME,
Pass: "",
}
}
15 changes: 15 additions & 0 deletions internal/fn/fn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package FlareFn

import (
"os"
"path"
)

func GetWorkDir() string {
workDir, _ := os.Getwd()
return workDir
}

func GetWorkDirFile(filename string) string {
return path.Join(GetWorkDir(), ".env")
}

0 comments on commit 7a43896

Please sign in to comment.