refactor: use nginx -s reload instead of systemd
- doc: add comment
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
// Package deploymentconfig loads the daemon's explicit local deployment configuration.
|
||||
// It never infers deployment type, executable paths, unit names, slot paths, or endpoints.
|
||||
// Package deploymentconfig 负责加载并严格校验 daemon 显式给出的本地部署配置。
|
||||
// 该包绝不推断部署类型、可执行文件路径、systemd 单元名称、槽位路径或健康端点,
|
||||
// 上述部署契约必须全部由配置文件显式提供,缺失或与内置契约不符都会返回错误。
|
||||
package deploymentconfig
|
||||
|
||||
import (
|
||||
@@ -16,77 +17,118 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultPath is the only default location used by the daemon entrypoint.
|
||||
// DefaultPath daemon 入口唯一使用的默认配置路径。
|
||||
DefaultPath = "/etc/yms-daemon/yms-daemon.toml"
|
||||
|
||||
EnvironmentDev = "dev"
|
||||
// EnvironmentDev 表示开发环境。
|
||||
EnvironmentDev = "dev"
|
||||
// EnvironmentProd 表示生产环境。
|
||||
EnvironmentProd = "prod"
|
||||
|
||||
BackendTypeNative = "native"
|
||||
// BackendTypeNative 表示原生后端运行时(systemd 单元 + JAR 文件)。
|
||||
BackendTypeNative = "native"
|
||||
// BackendTypeContainer 表示容器后端运行时。
|
||||
BackendTypeContainer = "container"
|
||||
|
||||
// BackendPort8080 蓝绿发布中 8080 槽位的端口号。
|
||||
BackendPort8080 = 8080
|
||||
// BackendPort8081 蓝绿发布中 8081 槽位的端口号。
|
||||
BackendPort8081 = 8081
|
||||
)
|
||||
|
||||
const (
|
||||
nativeReleaseDir = "/home/yms/lib/releases"
|
||||
nativeActiveJAR = "/home/yms/lib/glory-soft-yms.jar"
|
||||
nativeUnit8080 = "yms-backend@8080.service"
|
||||
nativeUnit8081 = "yms-backend@8081.service"
|
||||
nativeSlotJAR8080 = "/home/yms/lib/glory-soft-yms-8080.jar"
|
||||
nativeSlotJAR8081 = "/home/yms/lib/glory-soft-yms-8081.jar"
|
||||
// nativeReleaseDir 原生后端发布包(JAR)的固定存放目录。
|
||||
nativeReleaseDir = "/home/yms/lib/releases"
|
||||
// nativeActiveJAR 原生后端当前生效的主 JAR 路径。
|
||||
nativeActiveJAR = "/home/yms/lib/glory-soft-yms.jar"
|
||||
// nativeUnit8080 8080 槽位对应的 systemd 服务单元名称。
|
||||
nativeUnit8080 = "yms-backend@8080.service"
|
||||
// nativeUnit8081 8081 槽位对应的 systemd 服务单元名称。
|
||||
nativeUnit8081 = "yms-backend@8081.service"
|
||||
// nativeSlotJAR8080 8080 槽位对应的 JAR 文件路径。
|
||||
nativeSlotJAR8080 = "/home/yms/lib/glory-soft-yms-8080.jar"
|
||||
// nativeSlotJAR8081 8081 槽位对应的 JAR 文件路径。
|
||||
nativeSlotJAR8081 = "/home/yms/lib/glory-soft-yms-8081.jar"
|
||||
// nativeHealthURL8080 8080 槽位的健康检查端点地址。
|
||||
nativeHealthURL8080 = "http://127.0.0.1:8080/yms/actuator/health"
|
||||
// nativeHealthURL8081 8081 槽位的健康检查端点地址。
|
||||
nativeHealthURL8081 = "http://127.0.0.1:8081/yms/actuator/health"
|
||||
containerName8080 = "backend-8080"
|
||||
containerName8081 = "backend-8081"
|
||||
// containerName8080 容器后端 8080 槽位的容器名称。
|
||||
containerName8080 = "backend-8080"
|
||||
// containerName8081 容器后端 8081 槽位的容器名称。
|
||||
containerName8081 = "backend-8081"
|
||||
)
|
||||
|
||||
const (
|
||||
ContainerConfigSource = "/home/yms/conf/yms.yaml"
|
||||
ContainerConfigTarget = "/app/config/yms.yaml"
|
||||
ContainerTmpSource = "/home/yms/tmp"
|
||||
ContainerTmpTarget = "/home/yms/tmp"
|
||||
ContainerPortEnvironment = "SERVER_PORT"
|
||||
// ContainerConfigSource 容器后端配置在宿主侧的源路径。
|
||||
ContainerConfigSource = "/home/yms/conf/yms.yaml"
|
||||
// ContainerConfigTarget 容器后端配置在容器内的目标路径。
|
||||
ContainerConfigTarget = "/app/config/yms.yaml"
|
||||
// ContainerTmpSource 容器后端临时目录在宿主侧的源路径。
|
||||
ContainerTmpSource = "/home/yms/tmp"
|
||||
// ContainerTmpTarget 容器后端临时目录在容器内的目标路径。
|
||||
ContainerTmpTarget = "/home/yms/tmp"
|
||||
// ContainerPortEnvironment 用于向容器传递后端端口的环境变量名。
|
||||
ContainerPortEnvironment = "SERVER_PORT"
|
||||
// ContainerConfigEnvironment 用于向容器传递 Spring 配置位置的环境变量名。
|
||||
ContainerConfigEnvironment = "SPRING_CONFIG_LOCATION"
|
||||
ContainerConfigLocation = "file:/app/config/yms.yaml"
|
||||
// ContainerConfigLocation 容器内 Spring 配置文件的 file: 地址。
|
||||
ContainerConfigLocation = "file:/app/config/yms.yaml"
|
||||
)
|
||||
|
||||
// Config is the complete local deployment configuration currently understood by the daemon.
|
||||
// Config daemon 当前能够理解的完整本地部署配置。
|
||||
// 其结构与 TOML 文件中的 daemon、backend 两张顶层表一一对应,加载时做严格解码与校验。
|
||||
type Config struct {
|
||||
Daemon Daemon `toml:"daemon"`
|
||||
// Daemon 记录与环境相关、与具体运行时无关的机器级配置。
|
||||
Daemon Daemon `toml:"daemon"`
|
||||
// Backend 记录显式选定的后端运行时及其蓝绿槽位。
|
||||
Backend Backend `toml:"backend"`
|
||||
}
|
||||
|
||||
// Daemon contains machine-wide behavior that is independent of a component runtime.
|
||||
// Daemon 描述与具体组件运行时无关的机器级行为。
|
||||
type Daemon struct {
|
||||
// Environment 必须是 EnvironmentDev 或 EnvironmentProd 之一。
|
||||
Environment string `toml:"environment"`
|
||||
}
|
||||
|
||||
// Backend describes the explicitly selected backend runtime and its blue/green slots.
|
||||
// Backend 描述显式选定的后端运行时类型及其蓝绿槽位。
|
||||
type Backend struct {
|
||||
Type string `toml:"type"`
|
||||
ReleaseDir string `toml:"release_dir"`
|
||||
ActiveJAR string `toml:"active_jar"`
|
||||
SystemctlPath string `toml:"systemctl_path"`
|
||||
Slot BackendSlots `toml:"slot"`
|
||||
// Type 必须是 BackendTypeNative 或 BackendTypeContainer 之一。
|
||||
Type string `toml:"type"`
|
||||
// ReleaseDir 仅原生后端使用,必须是 nativeReleaseDir 对应的绝对路径。
|
||||
ReleaseDir string `toml:"release_dir"`
|
||||
// ActiveJAR 仅原生后端使用,必须是 nativeActiveJAR 对应的绝对路径。
|
||||
ActiveJAR string `toml:"active_jar"`
|
||||
// SystemctlPath systemctl 可执行文件的绝对路径。
|
||||
SystemctlPath string `toml:"systemctl_path"`
|
||||
// Slot 包含 8080、8081 两个受支持槽位的精确取值。
|
||||
Slot BackendSlots `toml:"slot"`
|
||||
}
|
||||
|
||||
// BackendSlots lists the only backend ports supported by the current deployment contract.
|
||||
// BackendSlots 列出当前部署契约唯一支持的两个后端端口槽位。
|
||||
type BackendSlots struct {
|
||||
// Port8080 8080 端口的槽位配置。
|
||||
Port8080 BackendSlot `toml:"8080"`
|
||||
// Port8081 8081 端口的槽位配置。
|
||||
Port8081 BackendSlot `toml:"8081"`
|
||||
}
|
||||
|
||||
// BackendSlot contains exact values for one native or container backend slot.
|
||||
// BackendSlot 包含一个原生或容器后端槽位的精确取值。
|
||||
// 不同运行时类型下使用的字段不同:原生后端使用 Unit、JAR,容器后端使用 ContainerName。
|
||||
type BackendSlot struct {
|
||||
Unit string `toml:"unit"`
|
||||
JAR string `toml:"jar"`
|
||||
ContainerName string `toml:"container_name"`
|
||||
// Unit 原生后端槽位对应的 systemd 服务单元名称。
|
||||
Unit string `toml:"unit"`
|
||||
// JAR 原生后端槽位对应的 JAR 文件绝对路径。
|
||||
JAR string `toml:"jar"`
|
||||
// ContainerName 容器后端槽位对应的容器名称。
|
||||
ContainerName string `toml:"container_name"`
|
||||
// HealthEndpoint 槽位健康检查的 URL 地址。
|
||||
HealthEndpoint string `toml:"health_endpoint"`
|
||||
}
|
||||
|
||||
// Load opens path, performs strict TOML decoding, and validates the selected backend contract.
|
||||
// Load 打开 path 指向的部署配置文件,进行严格的 TOML 解码与契约校验,返回解析后的 Config。
|
||||
// 它要求 path 是绝对路径且为普通文件,解码时禁用未知字段(任何大小写、拼写或层级不一致的
|
||||
// 键都会被拒绝),解码后调用 Validate 精确校验取值。任一步失败都会返回带上下文的 error。
|
||||
func Load(path string) (Config, error) {
|
||||
if err := validateAbsolutePath("deployment configuration", path); err != nil {
|
||||
return Config{}, err
|
||||
@@ -124,6 +166,8 @@ func Load(path string) (Config, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// validateExactDocumentKeys 对原始 TOML 文档做逐层键名校验,确保 daemon、backend 及
|
||||
// backend.slot 下每一张表都只包含契约允许的确切字段,任何未知字段(大小写、拼写或层级不符)都会被拒绝。
|
||||
func validateExactDocumentKeys(document []byte) error {
|
||||
var root map[string]any
|
||||
if err := toml.Unmarshal(document, &root); err != nil {
|
||||
@@ -165,6 +209,8 @@ func validateExactDocumentKeys(document []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// exactTable 从 table 中取出名为 key 的子表并返回;若 key 不存在或对应值不是 TOML 表,
|
||||
// 则返回错误。parent 用于拼出带前缀的完整字段名,以生成可读的错误信息。
|
||||
func exactTable(table map[string]any, parent string, key string) (map[string]any, error) {
|
||||
value, found := table[key]
|
||||
field := key
|
||||
@@ -181,6 +227,8 @@ func exactTable(table map[string]any, parent string, key string) (map[string]any
|
||||
return nested, nil
|
||||
}
|
||||
|
||||
// rejectUnknownKeys 检查 table 是否只包含 allowed 中列出的键;存在其他键时,按字典序
|
||||
// 返回第一个未知键的拒绝错误。parent 用于拼出带前缀的完整字段名。
|
||||
func rejectUnknownKeys(table map[string]any, parent string, allowed ...string) error {
|
||||
known := make(map[string]struct{}, len(allowed))
|
||||
for _, key := range allowed {
|
||||
@@ -204,7 +252,9 @@ func rejectUnknownKeys(table map[string]any, parent string, allowed ...string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate rejects incomplete or altered local deployment identifiers.
|
||||
// Validate 拒绝不完整或与内置部署契约不一致的本地部署标识符。
|
||||
// 它依次校验 daemon.environment、backend.systemctl_path 的绝对路径约束,再按 backend.type
|
||||
// 分支精确校验原生或容器槽位的 unit、jar、container_name、health_endpoint 等字段。
|
||||
func (c Config) Validate() error {
|
||||
switch c.Daemon.Environment {
|
||||
case EnvironmentDev, EnvironmentProd:
|
||||
@@ -250,7 +300,8 @@ func (c Config) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Slot returns the exact configuration for one supported backend port.
|
||||
// SlotForPort 返回 port 对应的后端槽位配置,仅支持 BackendPort8080 或 BackendPort8081,
|
||||
// 其他端口返回带端口号的错误。
|
||||
func (b Backend) SlotForPort(port int) (BackendSlot, error) {
|
||||
switch port {
|
||||
case BackendPort8080:
|
||||
@@ -262,6 +313,8 @@ func (b Backend) SlotForPort(port int) (BackendSlot, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// validateNativeSlot 校验原生槽位 slot 的 Unit、JAR、HealthEndpoint 是否分别等于
|
||||
// unit、jar、endpoint,任一不符即返回带 field 前缀的错误。
|
||||
func validateNativeSlot(field string, slot BackendSlot, unit string, jar string, endpoint string) error {
|
||||
if slot.Unit != unit {
|
||||
return fmt.Errorf("%s.unit must be %q", field, unit)
|
||||
@@ -275,6 +328,8 @@ func validateNativeSlot(field string, slot BackendSlot, unit string, jar string,
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateContainerSlot 校验容器槽位 slot 的 ContainerName、HealthEndpoint 是否分别等于
|
||||
// containerName、endpoint,任一不符即返回带 field 前缀的错误。
|
||||
func validateContainerSlot(field string, slot BackendSlot, containerName string, endpoint string) error {
|
||||
if slot.ContainerName != containerName {
|
||||
return fmt.Errorf("%s.container_name must be %q", field, containerName)
|
||||
@@ -285,6 +340,8 @@ func validateContainerSlot(field string, slot BackendSlot, containerName string,
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateAbsolutePath 校验 value 是一个非空、无首尾空白、经过 Clean 且不含 NUL 字节的绝对路径,
|
||||
// 用于保证配置中的路径标识符不会被意外篡改。field 用于拼出错误信息。
|
||||
func validateAbsolutePath(field string, value string) error {
|
||||
if value == "" {
|
||||
return fmt.Errorf("%s is required", field)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// validNativeConfig 一份满足原生后端部署契约的示例 TOML 配置,供各测试用例共享。
|
||||
const validNativeConfig = `[daemon]
|
||||
environment = "dev"
|
||||
|
||||
@@ -27,6 +28,7 @@ jar = "/home/yms/lib/glory-soft-yms-8081.jar"
|
||||
health_endpoint = "http://127.0.0.1:8081/yms/actuator/health"
|
||||
`
|
||||
|
||||
// validContainerConfig 一份满足容器后端部署契约的示例 TOML 配置,供各测试用例共享。
|
||||
const validContainerConfig = `[daemon]
|
||||
environment = "dev"
|
||||
|
||||
@@ -43,6 +45,8 @@ container_name = "backend-8081"
|
||||
health_endpoint = "http://127.0.0.1:8081/yms/actuator/health"
|
||||
`
|
||||
|
||||
// TestLoadValidNativeConfiguration 验证合法原生配置能被完整加载,
|
||||
// 且解析出的 daemon、backend 与 8080/8081 槽位取值都与契约常量精确一致。
|
||||
func TestLoadValidNativeConfiguration(t *testing.T) {
|
||||
path := writeConfig(t, validNativeConfig)
|
||||
|
||||
@@ -72,6 +76,8 @@ func TestLoadValidNativeConfiguration(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadValidContainerConfiguration 验证合法容器配置能被加载,
|
||||
// 且两个槽位的 container_name 取值与契约精确一致。
|
||||
func TestLoadValidContainerConfiguration(t *testing.T) {
|
||||
config, err := Load(writeConfig(t, validContainerConfig))
|
||||
if err != nil {
|
||||
@@ -85,6 +91,8 @@ func TestLoadValidContainerConfiguration(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsChangedContainerName 验证容器槽位的 container_name 被篡改时会被拒绝,
|
||||
// 且错误信息精确指向 backend.slot.8081.container_name 字段。
|
||||
func TestLoadRejectsChangedContainerName(t *testing.T) {
|
||||
content := strings.Replace(validContainerConfig, `container_name = "backend-8081"`, `container_name = "backend"`, 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -93,6 +101,8 @@ func TestLoadRejectsChangedContainerName(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPackagedNativeConfigurationMatchesContract 验证随发行包打包的原生部署配置
|
||||
// 与代码内置契约一致,确保打包产物不会被意外改坏。
|
||||
func TestPackagedNativeConfigurationMatchesContract(t *testing.T) {
|
||||
path, err := filepath.Abs(filepath.Join("..", "..", "packaging", "etc", "yms-daemon", "yms-daemon.toml"))
|
||||
if err != nil {
|
||||
@@ -103,6 +113,8 @@ func TestPackagedNativeConfigurationMatchesContract(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsUnknownField 验证配置中出现的未知字段(大小写不一致)会被拒绝,
|
||||
// 且错误信息精确包含该字段名 SystemctlPath。
|
||||
func TestLoadRejectsUnknownField(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, "systemctl_path = \"/bin/systemctl\"", "systemctl_path = \"/bin/systemctl\"\nSystemctlPath = \"/usr/bin/systemctl\"", 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -111,6 +123,8 @@ func TestLoadRejectsUnknownField(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadAcceptsProductionEnvironment 验证 environment 取值为 prod 时能被接受,
|
||||
// 并正确解析到 EnvironmentProd。
|
||||
func TestLoadAcceptsProductionEnvironment(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, `environment = "dev"`, `environment = "prod"`, 1)
|
||||
config, err := Load(writeConfig(t, content))
|
||||
@@ -122,6 +136,8 @@ func TestLoadAcceptsProductionEnvironment(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsMissingDaemonTable 验证缺失 daemon 顶层表时会被拒绝,
|
||||
// 且错误信息提示 daemon 表是必需的。
|
||||
func TestLoadRejectsMissingDaemonTable(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, "[daemon]\nenvironment = \"dev\"\n\n", "", 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -130,6 +146,8 @@ func TestLoadRejectsMissingDaemonTable(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsChangedEnvironment 验证 environment 被篡改为非法取值时会被拒绝,
|
||||
// 且错误信息精确指向 daemon.environment 字段。
|
||||
func TestLoadRejectsChangedEnvironment(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, `environment = "dev"`, `environment = "development"`, 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -138,6 +156,8 @@ func TestLoadRejectsChangedEnvironment(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsUnknownDaemonField 验证 daemon 表中出现的未知字段(大小写不一致)
|
||||
// 会被拒绝,且错误信息精确包含该字段名 daemon.Environment。
|
||||
func TestLoadRejectsUnknownDaemonField(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, `environment = "dev"`, "environment = \"dev\"\nEnvironment = \"dev\"", 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -146,6 +166,8 @@ func TestLoadRejectsUnknownDaemonField(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsWrongTableCase 验证表名大小写不一致([Backend])时会被拒绝,
|
||||
// 且错误信息精确包含该表名 Backend。
|
||||
func TestLoadRejectsWrongTableCase(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, "[backend]", "[Backend]", 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -154,6 +176,8 @@ func TestLoadRejectsWrongTableCase(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsMissingNativeField 验证原生配置缺失 active_jar 字段时会被拒绝,
|
||||
// 且错误信息精确指向 backend.active_jar 字段。
|
||||
func TestLoadRejectsMissingNativeField(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, "active_jar = \"/home/yms/lib/glory-soft-yms.jar\"\n", "", 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -162,6 +186,8 @@ func TestLoadRejectsMissingNativeField(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsUnknownSlot 验证配置中出现未受支持的槽位(9090)时会被拒绝,
|
||||
// 且错误信息精确包含该端口号 9090。
|
||||
func TestLoadRejectsUnknownSlot(t *testing.T) {
|
||||
content := validNativeConfig + `
|
||||
[backend.slot.9090]
|
||||
@@ -175,6 +201,8 @@ health_endpoint = "http://127.0.0.1:9090/yms/actuator/health"
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsChangedSlotEndpoint 验证槽位健康端点被篡改时会被拒绝,
|
||||
// 且错误信息精确指向 backend.slot.8080.health_endpoint 字段。
|
||||
func TestLoadRejectsChangedSlotEndpoint(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, nativeHealthURL8080, nativeHealthURL8081, 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -183,6 +211,8 @@ func TestLoadRejectsChangedSlotEndpoint(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadAcceptsExplicitUsrBinSystemctlPath 验证显式指定的 /usr/bin/systemctl 路径
|
||||
// 能被接受并原样解析,说明 systemctl_path 只要求绝对路径而不绑定单一取值。
|
||||
func TestLoadAcceptsExplicitUsrBinSystemctlPath(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, "/bin/systemctl", "/usr/bin/systemctl", 1)
|
||||
config, err := Load(writeConfig(t, content))
|
||||
@@ -194,6 +224,8 @@ func TestLoadAcceptsExplicitUsrBinSystemctlPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsChangedBackendTypeCase 验证 backend.type 大小写不一致(Native)时会被拒绝,
|
||||
// 且错误信息精确指向 backend.type 字段。
|
||||
func TestLoadRejectsChangedBackendTypeCase(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, `type = "native"`, `type = "Native"`, 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -202,6 +234,8 @@ func TestLoadRejectsChangedBackendTypeCase(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRejectsDuplicateField 验证 TOML 中重复出现的字段会被拒绝,
|
||||
// 确保配置没有歧义。
|
||||
func TestLoadRejectsDuplicateField(t *testing.T) {
|
||||
content := strings.Replace(validNativeConfig, "type = \"native\"", "type = \"native\"\ntype = \"native\"", 1)
|
||||
_, err := Load(writeConfig(t, content))
|
||||
@@ -210,6 +244,8 @@ func TestLoadRejectsDuplicateField(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRequiresAbsoluteConfigurationPath 验证 Load 要求传入绝对路径,
|
||||
// 相对路径会被拒绝且错误信息提示 absolute path。
|
||||
func TestLoadRequiresAbsoluteConfigurationPath(t *testing.T) {
|
||||
_, err := Load("yms-daemon.toml")
|
||||
if err == nil || !strings.Contains(err.Error(), "absolute path") {
|
||||
@@ -217,6 +253,7 @@ func TestLoadRequiresAbsoluteConfigurationPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSlotForPortRejectsUnsupportedPort 验证 SlotForPort 对未受支持端口返回错误。
|
||||
func TestSlotForPortRejectsUnsupportedPort(t *testing.T) {
|
||||
config, err := Load(writeConfig(t, validNativeConfig))
|
||||
if err != nil {
|
||||
@@ -227,6 +264,8 @@ func TestSlotForPortRejectsUnsupportedPort(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// writeConfig 将 content 写入临时目录下的 yms-daemon.toml 并返回其绝对路径,
|
||||
// 供 Load 测试使用。写入失败会直接终止测试。
|
||||
func writeConfig(t *testing.T, content string) string {
|
||||
t.Helper()
|
||||
path := filepath.Join(t.TempDir(), "yms-daemon.toml")
|
||||
|
||||
Reference in New Issue
Block a user