142 lines
4.1 KiB
Go
142 lines
4.1 KiB
Go
package config
|
||
|
||
import (
|
||
"bytes"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
|
||
"gopkg.in/yaml.v3"
|
||
)
|
||
|
||
// TestConfigFileCreatedNotWorldReadable 覆盖 SECURITY_TODO #11:
|
||
// 配置文件(内嵌会话密钥)不得被组/其他用户读取。
|
||
func TestConfigFileCreatedNotWorldReadable(t *testing.T) {
|
||
path := filepath.Join(t.TempDir(), "config.yaml")
|
||
LoadConfig(path)
|
||
|
||
st, err := os.Stat(path)
|
||
if err != nil {
|
||
t.Fatalf("config file not created: %v", err)
|
||
}
|
||
if perm := st.Mode().Perm(); perm != 0640 {
|
||
t.Fatalf("config perms = %v, want 0640", perm)
|
||
}
|
||
}
|
||
|
||
func TestMySQLDSN(t *testing.T) {
|
||
d := &DatabaseConfig{
|
||
DBName: "blog_go",
|
||
Username: "user",
|
||
Password: "pass:word",
|
||
Host: "127.0.0.1",
|
||
Port: "3306",
|
||
}
|
||
want := "user:pass:word@tcp(127.0.0.1:3306)/blog_go?charset=utf8mb4&parseTime=True&loc=Local"
|
||
if got := d.MySQLDSN(); got != want {
|
||
t.Fatalf("MySQLDSN() = %q, want %q", got, want)
|
||
}
|
||
}
|
||
|
||
// TestLoadConfigFillsMissingKeys 覆盖启动时补齐缺失配置项并回写文件:
|
||
// 旧格式配置(无 database 段)应被补全,且不覆盖已存在的 path。
|
||
func TestLoadConfigFillsMissingKeys(t *testing.T) {
|
||
path := filepath.Join(t.TempDir(), "config.yaml")
|
||
secret := strings.Repeat("a", 64)
|
||
old := "secret: " + secret + "\npath: ./data\n"
|
||
if err := os.WriteFile(path, []byte(old), 0640); err != nil {
|
||
t.Fatalf("write config: %v", err)
|
||
}
|
||
|
||
cfg := LoadConfig(path)
|
||
|
||
if cfg.Database.Type != "sqlite" || cfg.Database.DBName != mysqlExampleDBName ||
|
||
cfg.Database.Username != mysqlExampleUser || cfg.Database.Password != mysqlExamplePassword ||
|
||
cfg.Database.Host != mysqlExampleHost || cfg.Database.Port != mysqlExamplePort {
|
||
t.Fatalf("database defaults not filled: %+v", cfg.Database)
|
||
}
|
||
if cfg.Web.Port != defaultPort {
|
||
t.Fatalf("web port = %q, want %q", cfg.Web.Port, defaultPort)
|
||
}
|
||
if cfg.Path != "./data" {
|
||
t.Fatalf("path = %q, want ./data (must not be overwritten)", cfg.Path)
|
||
}
|
||
|
||
st, err := os.Stat(path)
|
||
if err != nil {
|
||
t.Fatalf("stat config: %v", err)
|
||
}
|
||
if perm := st.Mode().Perm(); perm != 0640 {
|
||
t.Fatalf("config perms = %v, want 0640", perm)
|
||
}
|
||
|
||
data, err := os.ReadFile(path)
|
||
if err != nil {
|
||
t.Fatalf("read config: %v", err)
|
||
}
|
||
back := &Config{}
|
||
if err := yaml.Unmarshal(data, back); err != nil {
|
||
t.Fatalf("reload config: %v", err)
|
||
}
|
||
if back.Database.DBName != mysqlExampleDBName {
|
||
t.Fatalf("rewritten file db_name = %q, want %q", back.Database.DBName, mysqlExampleDBName)
|
||
}
|
||
}
|
||
|
||
// TestLoadConfigKeepsCompleteFile 覆盖配置完整时不回写文件。
|
||
func TestLoadConfigKeepsCompleteFile(t *testing.T) {
|
||
path := filepath.Join(t.TempDir(), "config.yaml")
|
||
content := "database:\n" +
|
||
" type: mysql\n" +
|
||
" db_name: myblog\n" +
|
||
" username: root\n" +
|
||
" password: p@ss\n" +
|
||
" host: db.local\n" +
|
||
" port: \"3307\"\n" +
|
||
"web:\n" +
|
||
" port: \"8080\"\n" +
|
||
" socket: \"\"\n" +
|
||
" trusted_proxies:\n" +
|
||
" - 127.0.0.1\n" +
|
||
" - ::1\n" +
|
||
"path: ./data\n" +
|
||
"secret: " + strings.Repeat("a", 64) + "\n"
|
||
if err := os.WriteFile(path, []byte(content), 0640); err != nil {
|
||
t.Fatalf("write config: %v", err)
|
||
}
|
||
|
||
cfg := LoadConfig(path)
|
||
|
||
if cfg.Database.Password != "p@ss" {
|
||
t.Fatalf("password = %q, want p@ss (must not be overwritten)", cfg.Database.Password)
|
||
}
|
||
after, err := os.ReadFile(path)
|
||
if err != nil {
|
||
t.Fatalf("read config: %v", err)
|
||
}
|
||
if !bytes.Equal(after, []byte(content)) {
|
||
t.Fatalf("complete config file was rewritten:\n%s", after)
|
||
}
|
||
}
|
||
|
||
// TestLoadConfigMalformedNoRewrite 覆盖解析失败的配置文件不被回写。
|
||
func TestLoadConfigMalformedNoRewrite(t *testing.T) {
|
||
path := filepath.Join(t.TempDir(), "config.yaml")
|
||
// web.port 为序列不能解码到 string,yaml.Unmarshal 报错。
|
||
content := "secret: " + strings.Repeat("a", 64) + "\nweb:\n port: [8080]\n"
|
||
if err := os.WriteFile(path, []byte(content), 0640); err != nil {
|
||
t.Fatalf("write config: %v", err)
|
||
}
|
||
|
||
LoadConfig(path)
|
||
|
||
after, err := os.ReadFile(path)
|
||
if err != nil {
|
||
t.Fatalf("read config: %v", err)
|
||
}
|
||
if !bytes.Equal(after, []byte(content)) {
|
||
t.Fatalf("malformed config was rewritten:\n%s", after)
|
||
}
|
||
}
|