refactor: use nginx -s reload instead of systemd
- doc: add comment
This commit is contained in:
@@ -20,9 +20,14 @@ import (
|
||||
"yms-daemon/internal/transaction"
|
||||
)
|
||||
|
||||
// containerTestImage 容器更新测试使用的镜像引用,指向 harbor 仓库的一个具体 tag。
|
||||
const containerTestImage = "harbor.ymswell.asia/ymswell/glory-ymswell:20260813-184902-a37bf50d-v1.1.8.1"
|
||||
|
||||
// containerTestDigest 容器更新测试使用的镜像仓库摘要,用于与 containerTestImage 组合成不可变引用。
|
||||
const containerTestDigest = "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
|
||||
// TestContainerUpdaterPullsSwitchesAndStopsPreviousSlot 验证在已存在运行中的 backend-8080 容器时,
|
||||
// 更新镜像会切换到非活跃槽位 backend-8081、提交部署并停止旧容器 backend-8080。
|
||||
func TestContainerUpdaterPullsSwitchesAndStopsPreviousSlot(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
updater, store, engine, gateway := newContainerUpdaterFixture(t, map[string]containerengine.Container{
|
||||
@@ -48,6 +53,9 @@ func TestContainerUpdaterPullsSwitchesAndStopsPreviousSlot(t *testing.T) {
|
||||
assertCommittedContainerDeployment(t, store, record.ID, 8081, "backend-8081", "container-id-backend-8081")
|
||||
}
|
||||
|
||||
// TestContainerUpdaterFirstInstallCreatesInactiveSlotBeforeSwitch 验证全新安装场景:
|
||||
// 目标容器 backend-8081 必须先在非路由槽位创建并通过健康检查,之后才切换网关;
|
||||
// 整个过程不得进入旧容器排水流程,也不得停止任何旧容器。
|
||||
func TestContainerUpdaterFirstInstallCreatesInactiveSlotBeforeSwitch(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
@@ -92,6 +100,8 @@ func TestContainerUpdaterFirstInstallCreatesInactiveSlotBeforeSwitch(t *testing.
|
||||
assertCommittedContainerDeployment(t, store, record.ID, 8081, "backend-8081", "container-id-backend-8081")
|
||||
}
|
||||
|
||||
// TestContainerUpdaterRejectsMissingActiveWithPresentInactive 验证当活跃容器 backend-8080 缺失
|
||||
// 而非活跃容器 backend-8081 仍在运行时,更新会被拒绝并返回明确的错误信息。
|
||||
func TestContainerUpdaterRejectsMissingActiveWithPresentInactive(t *testing.T) {
|
||||
updater, _, _, _ := newContainerUpdaterFixture(t, map[string]containerengine.Container{
|
||||
"backend-8081": {
|
||||
@@ -105,6 +115,9 @@ func TestContainerUpdaterRejectsMissingActiveWithPresentInactive(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestContainerUpdaterRecoversFailedRollbackThenRetriesSameImage 验证更新失败进入回滚后的恢复链路:
|
||||
// 首次更新因网关切换失败而进入回滚并停止目标容器,再次调用恢复同一回滚直至完成,
|
||||
// 最后重试同一镜像能够成功切换并提交。
|
||||
func TestContainerUpdaterRecoversFailedRollbackThenRetriesSameImage(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
updater, _, engine, gateway := newContainerUpdaterFixture(t, map[string]containerengine.Container{}, 0)
|
||||
@@ -140,6 +153,8 @@ func TestContainerUpdaterRecoversFailedRollbackThenRetriesSameImage(t *testing.T
|
||||
}
|
||||
}
|
||||
|
||||
// TestContainerUpdaterRejectsMissingCommittedContainer 验证当已提交部署记录中的活跃容器 backend-8080 丢失时,
|
||||
// 更新会将其识别为部署漂移并拒绝继续。
|
||||
func TestContainerUpdaterRejectsMissingCommittedContainer(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
updater, store, _, _ := newContainerUpdaterFixture(t, map[string]containerengine.Container{}, 0)
|
||||
@@ -175,6 +190,8 @@ func TestContainerUpdaterRejectsMissingCommittedContainer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// newContainerUpdaterFixture 构造容器更新器的测试夹具,返回更新器、事务存储、假容器引擎和内存网关。
|
||||
// containers 指定引擎初始存在的容器;drain 指定旧容器停止前的排水等待时长。
|
||||
func newContainerUpdaterFixture(
|
||||
t *testing.T,
|
||||
containers map[string]containerengine.Container,
|
||||
@@ -242,6 +259,8 @@ func newContainerUpdaterFixture(
|
||||
return updater, store, engine, gateway
|
||||
}
|
||||
|
||||
// assertCreatedContainerSpec 校验传入容器引擎的创建规格,确认目标容器名称、镜像引用、运行时约束、
|
||||
// 环境变量和挂载点均符合容器更新契约。
|
||||
func assertCreatedContainerSpec(t *testing.T, request containerengine.ContainerSpec) {
|
||||
t.Helper()
|
||||
if request.Name != "backend-8081" || request.ImageReference != "harbor.ymswell.asia/ymswell/glory-ymswell@"+containerTestDigest {
|
||||
@@ -258,6 +277,8 @@ func assertCreatedContainerSpec(t *testing.T, request containerengine.ContainerS
|
||||
}
|
||||
}
|
||||
|
||||
// assertCommittedContainerDeployment 校验事务存储中已提交的后端容器部署记录,
|
||||
// 确认其活跃端口、容器名称、容器 ID、镜像摘要和事务 ID 均与预期一致。
|
||||
func assertCommittedContainerDeployment(
|
||||
t *testing.T,
|
||||
store *transaction.Store,
|
||||
@@ -276,6 +297,7 @@ func assertCommittedContainerDeployment(
|
||||
}
|
||||
}
|
||||
|
||||
// serverConfiguration8080 测试用的 host Nginx 配置片段,其活跃后端端口为 8080。
|
||||
const serverConfiguration8080 = `http {
|
||||
upstream yms-server {
|
||||
# yms-update managed upstream begin
|
||||
@@ -286,12 +308,17 @@ const serverConfiguration8080 = `http {
|
||||
}
|
||||
`
|
||||
|
||||
// containerUpdateRoundTripFunc 将普通函数适配为 http.RoundTripper,
|
||||
// 使测试可以用自定义逻辑响应后端的健康检查请求。
|
||||
type containerUpdateRoundTripFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
// RoundTrip 实现 http.RoundTripper 接口,直接委托给底层函数处理请求。
|
||||
func (function containerUpdateRoundTripFunc) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||
return function(request)
|
||||
}
|
||||
|
||||
// containerUpdateEngine 容器引擎的测试替身,在内存中模拟镜像与容器的生命周期,
|
||||
// 并记录停止、创建和健康检查等交互,供断言验证更新行为。
|
||||
type containerUpdateEngine struct {
|
||||
image containerengine.Image
|
||||
containers map[string]containerengine.Container
|
||||
@@ -300,12 +327,21 @@ type containerUpdateEngine struct {
|
||||
healthChecks int
|
||||
}
|
||||
|
||||
func (e *containerUpdateEngine) Ping(context.Context) error { return nil }
|
||||
func (e *containerUpdateEngine) PullImage(context.Context, string) error { return nil }
|
||||
// Ping 返回 nil,模拟引擎连通性检查始终成功。
|
||||
func (e *containerUpdateEngine) Ping(context.Context) error { return nil }
|
||||
|
||||
// PullImage 返回 nil,模拟镜像拉取始终成功。
|
||||
func (e *containerUpdateEngine) PullImage(context.Context, string) error { return nil }
|
||||
|
||||
// LoadImage 返回 nil,模拟从流加载镜像始终成功。
|
||||
func (e *containerUpdateEngine) LoadImage(context.Context, io.Reader) error { return nil }
|
||||
|
||||
// InspectImage 返回夹具预设的镜像信息,用于冻结镜像的平台与仓库摘要。
|
||||
func (e *containerUpdateEngine) InspectImage(context.Context, string) (containerengine.Image, error) {
|
||||
return e.image, nil
|
||||
}
|
||||
|
||||
// CreateContainer 依据规格在内存中登记一个新容器,记录最后一次创建规格并返回该容器。
|
||||
func (e *containerUpdateEngine) CreateContainer(_ context.Context, spec containerengine.ContainerSpec) (containerengine.Container, error) {
|
||||
e.lastCreateSpec = spec
|
||||
record := containerengine.Container{
|
||||
@@ -326,6 +362,8 @@ func (e *containerUpdateEngine) CreateContainer(_ context.Context, spec containe
|
||||
e.containers[spec.Name] = record
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// StartContainer 将指定容器标记为运行中;若容器不存在则返回 containerengine.ErrNotFound。
|
||||
func (e *containerUpdateEngine) StartContainer(_ context.Context, name string) error {
|
||||
record, found := e.containers[name]
|
||||
if !found {
|
||||
@@ -337,9 +375,12 @@ func (e *containerUpdateEngine) StartContainer(_ context.Context, name string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContainerLogs 返回空的日志流,模拟容器日志读取。
|
||||
func (e *containerUpdateEngine) ContainerLogs(context.Context, string) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
}
|
||||
|
||||
// StopContainer 记录被停止的容器名称并将该容器标记为已退出;若容器不存在则返回 containerengine.ErrNotFound。
|
||||
func (e *containerUpdateEngine) StopContainer(_ context.Context, name string) error {
|
||||
e.stopped = append(e.stopped, name)
|
||||
record, found := e.containers[name]
|
||||
@@ -351,6 +392,8 @@ func (e *containerUpdateEngine) StopContainer(_ context.Context, name string) er
|
||||
e.containers[name] = record
|
||||
return nil
|
||||
}
|
||||
|
||||
// InspectContainer 返回内存中的指定容器;若容器不存在则返回 containerengine.ErrNotFound。
|
||||
func (e *containerUpdateEngine) InspectContainer(_ context.Context, name string) (containerengine.Container, error) {
|
||||
record, found := e.containers[name]
|
||||
if !found {
|
||||
@@ -358,6 +401,8 @@ func (e *containerUpdateEngine) InspectContainer(_ context.Context, name string)
|
||||
}
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// RemoveContainer 从内存中删除指定容器;若容器不存在则返回 containerengine.ErrNotFound。
|
||||
func (e *containerUpdateEngine) RemoveContainer(_ context.Context, name string, _ bool) error {
|
||||
if _, found := e.containers[name]; !found {
|
||||
return containerengine.ErrNotFound
|
||||
@@ -365,6 +410,8 @@ func (e *containerUpdateEngine) RemoveContainer(_ context.Context, name string,
|
||||
delete(e.containers, name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 返回 nil,模拟引擎关闭无副作用。
|
||||
func (e *containerUpdateEngine) Close() error { return nil }
|
||||
|
||||
var _ containerengine.Engine = (*containerUpdateEngine)(nil)
|
||||
|
||||
Reference in New Issue
Block a user