refactor: use nginx -s reload instead of systemd
- doc: add comment
This commit is contained in:
@@ -19,11 +19,16 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
testDigest = "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
testRepository = "harbor.ymswell.asia/ymswell/glory-ymswell"
|
||||
// testDigest 测试中使用的固定镜像清单摘要。
|
||||
testDigest = "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
// testRepository 测试中使用的镜像仓库前缀。
|
||||
testRepository = "harbor.ymswell.asia/ymswell/glory-ymswell"
|
||||
// healthyResponse 测试中健康检查端点返回的固定 UP 响应体。
|
||||
healthyResponse = `{"status":"UP","components":{"db":{"status":"UP"},"diskSpace":{"status":"UP"},"ping":{"status":"UP"},"redis":{"status":"UP"}}}`
|
||||
)
|
||||
|
||||
// TestExecutorPreservesOpaqueImageTagsAndReachesSwitching 验证执行器对不透明镜像标签保持原样传递,
|
||||
// 并能使事务推进到 StateSwitching;同时验证在 StateSwitching 状态重复执行不会产生额外引擎调用。
|
||||
func TestExecutorPreservesOpaqueImageTagsAndReachesSwitching(t *testing.T) {
|
||||
tags := []string{
|
||||
"20260814-093609-d7ed70f0-v1.1.8.1",
|
||||
@@ -80,6 +85,8 @@ func TestExecutorPreservesOpaqueImageTagsAndReachesSwitching(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestExecutorRecoversRecordedCreateIntentWithoutRepeatingCreate 验证在 crash 窗口内已记录创建步骤意图后,
|
||||
// 恢复执行不会重复创建容器,而是直接复用已完成的创建步骤并最终进入 StateSwitching。
|
||||
func TestExecutorRecoversRecordedCreateIntentWithoutRepeatingCreate(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
store, coordinator := testTransactionKernel(t)
|
||||
@@ -125,6 +132,7 @@ func TestExecutorRecoversRecordedCreateIntentWithoutRepeatingCreate(t *testing.T
|
||||
}
|
||||
}
|
||||
|
||||
// TestExecutorMarksValidationFailureTerminal 验证请求校验失败时事务被置为 StateFailed 终态。
|
||||
func TestExecutorMarksValidationFailureTerminal(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
store, coordinator := testTransactionKernel(t)
|
||||
@@ -143,6 +151,8 @@ func TestExecutorMarksValidationFailureTerminal(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestExecutorReplacesInactiveContainerWithConflictingImage 验证当存在镜像标识冲突的非活动容器时,
|
||||
// 执行器会移除该容器并重新创建,最终进入 StateSwitching。
|
||||
func TestExecutorReplacesInactiveContainerWithConflictingImage(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
store, coordinator := testTransactionKernel(t)
|
||||
@@ -170,6 +180,8 @@ func TestExecutorReplacesInactiveContainerWithConflictingImage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestExecutorRejectsChangedRecoveryRequestWithoutChangingState 验证恢复执行时若请求参数被改动,
|
||||
// 执行器会因持久化意图冲突而拒绝,且不改变事务的 StateStarting 状态。
|
||||
func TestExecutorRejectsChangedRecoveryRequestWithoutChangingState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
store, coordinator := testTransactionKernel(t)
|
||||
@@ -198,6 +210,8 @@ func TestExecutorRejectsChangedRecoveryRequestWithoutChangingState(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
// TestImageMatchesRequiresDigestEvidenceAndExactPlatform 验证镜像匹配逻辑要求存在摘要证据且平台完全一致,
|
||||
// 镜像 ID 单独存在不足以满足清单摘要匹配,平台不一致时不得判定匹配。
|
||||
func TestImageMatchesRequiresDigestEvidenceAndExactPlatform(t *testing.T) {
|
||||
t.Parallel()
|
||||
platform := containerengine.Platform{OS: "linux", Architecture: "arm64"}
|
||||
@@ -222,6 +236,7 @@ func TestImageMatchesRequiresDigestEvidenceAndExactPlatform(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// testRequest 构造一个合法的测试请求,并在临时目录中写入镜像归档与后端配置文件。
|
||||
func testRequest(t *testing.T, imageReference string) Request {
|
||||
t.Helper()
|
||||
directory := t.TempDir()
|
||||
@@ -253,6 +268,7 @@ func testRequest(t *testing.T, imageReference string) Request {
|
||||
}
|
||||
}
|
||||
|
||||
// testTransactionKernel 创建测试用的事务存储与协调器,并在测试结束时自动关闭存储。
|
||||
func testTransactionKernel(t *testing.T) (*transaction.Store, *transaction.Coordinator) {
|
||||
t.Helper()
|
||||
store, err := transaction.OpenStore(context.Background(), filepath.Join(t.TempDir(), "transactions.db"))
|
||||
@@ -267,6 +283,7 @@ func testTransactionKernel(t *testing.T) (*transaction.Store, *transaction.Coord
|
||||
return store, coordinator
|
||||
}
|
||||
|
||||
// testExecutor 使用固定响应体构造健康检查 HTTP 客户端并创建后端执行器。
|
||||
func testExecutor(t *testing.T, store *transaction.Store, coordinator *transaction.Coordinator, engine containerengine.Engine, body string) *Executor {
|
||||
t.Helper()
|
||||
client := &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
|
||||
@@ -279,6 +296,7 @@ func testExecutor(t *testing.T, store *transaction.Store, coordinator *transacti
|
||||
return executor
|
||||
}
|
||||
|
||||
// createTransaction 以给定后缀创建一个新的后端测试事务并返回其记录。
|
||||
func createTransaction(t *testing.T, store *transaction.Store, suffix string) transaction.Transaction {
|
||||
t.Helper()
|
||||
record, _, err := store.CreateTransaction(context.Background(), transaction.CreateRequest{
|
||||
@@ -293,6 +311,7 @@ func createTransaction(t *testing.T, store *transaction.Store, suffix string) tr
|
||||
return record
|
||||
}
|
||||
|
||||
// transitionToPrepared 将指定事务依次推进到 StateValidating 与 StatePrepared 状态。
|
||||
func transitionToPrepared(t *testing.T, store *transaction.Store, transactionID string) {
|
||||
t.Helper()
|
||||
ctx := context.Background()
|
||||
@@ -304,12 +323,15 @@ func transitionToPrepared(t *testing.T, store *transaction.Store, transactionID
|
||||
}
|
||||
}
|
||||
|
||||
// roundTripFunc http.RoundTripper 的函数式适配器,用于在测试中固定 HTTP 响应。
|
||||
type roundTripFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
// RoundTrip 实现 http.RoundTripper 接口,直接调用底层函数。
|
||||
func (f roundTripFunc) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||
return f(request)
|
||||
}
|
||||
|
||||
// engineCalls 记录 fakeEngine 各方法被调用的次数,用于断言执行路径。
|
||||
type engineCalls struct {
|
||||
ping int
|
||||
load int
|
||||
@@ -319,12 +341,19 @@ type engineCalls struct {
|
||||
remove int
|
||||
}
|
||||
|
||||
// fakeEngine containerengine.Engine 的内存实现,用于测试中模拟容器引擎行为。
|
||||
type fakeEngine struct {
|
||||
mu sync.Mutex
|
||||
request Request
|
||||
loadedImage containerengine.Image
|
||||
// mu 保护下方字段的并发访问。
|
||||
mu sync.Mutex
|
||||
// request 构造该引擎时使用的请求参数。
|
||||
request Request
|
||||
// loadedImage 引擎加载后提供的镜像。
|
||||
loadedImage containerengine.Image
|
||||
// imageAvailable 表示镜像当前是否可用。
|
||||
imageAvailable bool
|
||||
containers map[string]containerengine.Container
|
||||
// containers 引擎维护的容器表,键为容器名称。
|
||||
containers map[string]containerengine.Container
|
||||
// lastCreateSpec 记录最近一次创建容器所用的规格。
|
||||
lastCreateSpec containerengine.ContainerSpec
|
||||
pingCalls int
|
||||
loadCalls int
|
||||
@@ -334,6 +363,7 @@ type fakeEngine struct {
|
||||
removeCalls int
|
||||
}
|
||||
|
||||
// newFakeEngine 构造一个已按请求平台预置镜像的 fakeEngine。
|
||||
func newFakeEngine(request Request) *fakeEngine {
|
||||
return &fakeEngine{
|
||||
request: request,
|
||||
@@ -346,6 +376,7 @@ func newFakeEngine(request Request) *fakeEngine {
|
||||
}
|
||||
}
|
||||
|
||||
// Ping 实现容器引擎的 Ping,记录调用次数并始终返回成功。
|
||||
func (e *fakeEngine) Ping(context.Context) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
@@ -353,6 +384,7 @@ func (e *fakeEngine) Ping(context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadImage 实现容器引擎的 LoadImage,读取输入流后标记镜像可用并记录调用次数。
|
||||
func (e *fakeEngine) LoadImage(_ context.Context, input io.Reader) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
@@ -364,6 +396,7 @@ func (e *fakeEngine) LoadImage(_ context.Context, input io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PullImage 实现容器引擎的 PullImage,标记镜像可用并记录调用次数。
|
||||
func (e *fakeEngine) PullImage(context.Context, string) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
@@ -372,6 +405,7 @@ func (e *fakeEngine) PullImage(context.Context, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InspectImage 实现容器引擎的 InspectImage,镜像不可用时返回 ErrNotFound,否则返回已加载镜像。
|
||||
func (e *fakeEngine) InspectImage(context.Context, string) (containerengine.Image, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
@@ -382,6 +416,7 @@ func (e *fakeEngine) InspectImage(context.Context, string) (containerengine.Imag
|
||||
return e.loadedImage, nil
|
||||
}
|
||||
|
||||
// CreateContainer 实现容器引擎的 CreateContainer,记录规格并创建容器,同名时返回错误。
|
||||
func (e *fakeEngine) CreateContainer(_ context.Context, spec containerengine.ContainerSpec) (containerengine.Container, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
@@ -395,6 +430,7 @@ func (e *fakeEngine) CreateContainer(_ context.Context, spec containerengine.Con
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// StartContainer 实现容器引擎的 StartContainer,将指定容器标记为运行状态,不存在时返回 ErrNotFound。
|
||||
func (e *fakeEngine) StartContainer(_ context.Context, name string) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
@@ -409,10 +445,12 @@ func (e *fakeEngine) StartContainer(_ context.Context, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContainerLogs 实现容器引擎的 ContainerLogs,返回空的日志读取器。
|
||||
func (e *fakeEngine) ContainerLogs(context.Context, string) (io.ReadCloser, error) {
|
||||
return io.NopCloser(strings.NewReader("")), nil
|
||||
}
|
||||
|
||||
// StopContainer 实现容器引擎的 StopContainer,将指定容器标记为已退出状态,不存在时返回 ErrNotFound。
|
||||
func (e *fakeEngine) StopContainer(_ context.Context, name string) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
@@ -426,6 +464,7 @@ func (e *fakeEngine) StopContainer(_ context.Context, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InspectContainer 实现容器引擎的 InspectContainer,返回容器记录,不存在时返回 ErrNotFound。
|
||||
func (e *fakeEngine) InspectContainer(_ context.Context, name string) (containerengine.Container, error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
@@ -436,6 +475,7 @@ func (e *fakeEngine) InspectContainer(_ context.Context, name string) (container
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// RemoveContainer 实现容器引擎的 RemoveContainer,删除指定容器并记录调用次数,不存在时返回 ErrNotFound。
|
||||
func (e *fakeEngine) RemoveContainer(_ context.Context, name string, _ bool) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
@@ -447,8 +487,10 @@ func (e *fakeEngine) RemoveContainer(_ context.Context, name string, _ bool) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close 实现容器引擎的 Close,不做任何清理并返回 nil。
|
||||
func (e *fakeEngine) Close() error { return nil }
|
||||
|
||||
// containerFromSpec 根据容器规格构造一条容器记录,running 指定其初始运行状态。
|
||||
func (e *fakeEngine) containerFromSpec(spec containerengine.ContainerSpec, running bool) containerengine.Container {
|
||||
return containerengine.Container{
|
||||
ID: "container-id-" + spec.Name,
|
||||
@@ -467,6 +509,7 @@ func (e *fakeEngine) containerFromSpec(spec containerengine.ContainerSpec, runni
|
||||
}
|
||||
}
|
||||
|
||||
// callCounts 返回 fakeEngine 各方法当前的调用次数快照。
|
||||
func (e *fakeEngine) callCounts() engineCalls {
|
||||
return engineCalls{
|
||||
ping: e.pingCalls,
|
||||
@@ -478,4 +521,5 @@ func (e *fakeEngine) callCounts() engineCalls {
|
||||
}
|
||||
}
|
||||
|
||||
// 编译期断言确保 fakeEngine 实现 containerengine.Engine 接口。
|
||||
var _ containerengine.Engine = (*fakeEngine)(nil)
|
||||
|
||||
Reference in New Issue
Block a user