chore: 初始开源发布
iotlcm-worker-svr:异步执行中枢(RabbitMQ 消费者 + 全量同步编排)。 - Go module:iotlcm-worker-svr → git.5iot.com/iotlcm-public/iotlcm-worker-svr(214 文件) - 凭据与内部标识脱敏:MySQL/Redis 凭据、私网与生产 IP、内网域名、 库名 xiujie_admin → iotlcm、哨兵名占位 - 159 处真实手机号 → 合法 11 位编造号(保留号段与后 4 位,维持互异, 不破坏「校验 MSISDN 格式」等测试断言) - 移除内部资产:CI 触发器、Jenkins 触发测试文档、预演门禁与镜像 digest 记录 - Dockerfile 改用公共基础镜像(golang:1.25-alpine → alpine:3.23), 移除写死的 git 凭据 - README 重写(架构/全量同步模型/配置/已知失败),补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 已知:3 个测试包在源仓同一提交上同样失败(client/upstream、 service/allocate、service/inbound),属既有缺陷,本仓未引入亦未修复。
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package contract_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/fullsync/contract"
|
||||
)
|
||||
|
||||
func TestRunAccounting(t *testing.T) {
|
||||
valid := contract.RunMeta{
|
||||
RunID: "run", Status: contract.RunRunning, CurrentRound: 1, MaxRound: 5,
|
||||
EnqueuedCount: 10, ActiveCount: 3, InflightCount: 2, NextRoundCount: 2,
|
||||
SuccessCount: 4, FailedCount: 1, PendingFailureCount: 1,
|
||||
}
|
||||
if err := valid.ValidateAccounting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for name, mutate := range map[string]func(*contract.RunMeta){
|
||||
"unbalanced": func(m *contract.RunMeta) { m.EnqueuedCount++ },
|
||||
"negative": func(m *contract.RunMeta) { m.BatchCount = -1 },
|
||||
"overflow": func(m *contract.RunMeta) {
|
||||
m.EnqueuedCount = math.MaxInt64
|
||||
m.SuccessCount = math.MaxInt64
|
||||
m.FailedCount = math.MaxInt64
|
||||
},
|
||||
"inflight double count": func(m *contract.RunMeta) { m.InflightCount = m.ActiveCount + 1 },
|
||||
"pending exceeds history": func(m *contract.RunMeta) { m.PendingFailureCount = 2 },
|
||||
"terminal with work": func(m *contract.RunMeta) { m.Status = contract.RunCompletedWithFailures; m.ProducerDone = true },
|
||||
"unknown status": func(m *contract.RunMeta) { m.Status = "succeeded" },
|
||||
"unknown sync type": func(m *contract.RunMeta) { m.SyncType = "manual" },
|
||||
"action status in archive": func(m *contract.RunMeta) { m.ArchiveStatus = "completed" },
|
||||
"action status in disposition": func(m *contract.RunMeta) { m.ReplayDisposition = "cleanup_pending" },
|
||||
"round out of range": func(m *contract.RunMeta) { m.CurrentRound = 6 },
|
||||
"replay without source": func(m *contract.RunMeta) { m.SyncType = contract.SyncReplay },
|
||||
"self replay": func(m *contract.RunMeta) {
|
||||
m.SyncType = contract.SyncReplay
|
||||
m.SourceRunID = m.RunID
|
||||
m.ReplayCycle = 1
|
||||
},
|
||||
"normal with provenance": func(m *contract.RunMeta) { m.SyncType = contract.SyncNormal; m.SourceRunID = "source" },
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
meta := valid
|
||||
mutate(&meta)
|
||||
if err := meta.ValidateAccounting(); !errors.Is(err, contract.ErrInvalidArgument) {
|
||||
t.Fatalf("invalid accounting returned %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
// Cleaned source failures never subtract from the historical failed total.
|
||||
completed := contract.RunMeta{RunID: "source", Status: contract.RunCompletedWithFailures, ProducerDone: true, EnqueuedCount: 5, SuccessCount: 3, FailedCount: 2, PendingFailureCount: 0}
|
||||
if err := completed.ValidateAccounting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
completed.ProducerDone = false
|
||||
if err := completed.ValidateAccounting(); err == nil {
|
||||
t.Fatal("accepted terminal run with unfinished producer")
|
||||
}
|
||||
if err := (contract.RunMeta{RunID: "old", Status: contract.RunRunning, SuccessCount: 42}).Validate(); err != nil {
|
||||
t.Fatalf("historical run without new counters rejected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundStatsValidation(t *testing.T) {
|
||||
valid := contract.RoundStats{RunID: "run", Round: 1, ErrorCounts: contract.ErrorCounts{"unrecognized": 1}}
|
||||
if err := valid.Validate(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, stats := range []contract.RoundStats{
|
||||
{RunID: "run", Round: 0}, {RunID: "run", Round: 1, BatchCount: -1},
|
||||
{RunID: "run", Round: 1, ErrorCounts: contract.ErrorCounts{contract.ErrorOther: -1}},
|
||||
} {
|
||||
if err := stats.Validate(); !errors.Is(err, contract.ErrInvalidArgument) {
|
||||
t.Fatalf("invalid round stats returned %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPageLimitsAndOpaqueCursor(t *testing.T) {
|
||||
for _, limit := range []int{0, 1, 100, 500} {
|
||||
request, err := (contract.PageRequest{Limit: limit, Cursor: "opaque+/=:%?next"}).Normalized()
|
||||
if err != nil || request.Cursor != "opaque+/=:%?next" || request.Limit < 1 || request.Limit > contract.MaxPageLimit {
|
||||
t.Fatalf("unexpected page: %+v, %v", request, err)
|
||||
}
|
||||
if limit == 0 && request.Limit != 100 {
|
||||
t.Fatal("default limit changed")
|
||||
}
|
||||
}
|
||||
for _, limit := range []int{-1, 501, math.MaxInt} {
|
||||
if _, err := (contract.PageRequest{Limit: limit}).Normalized(); !errors.Is(err, contract.ErrInvalidArgument) {
|
||||
t.Fatalf("limit %d returned %v", limit, err)
|
||||
}
|
||||
}
|
||||
page := contract.FailurePage{Items: []contract.Failure{}, NextCursor: "continue"}
|
||||
if got := string(mustJSON(t, page)); got != `{"items":[],"nextCursor":"continue"}` {
|
||||
t.Fatalf("empty scan page lost its continuation: %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusVocabulary(t *testing.T) {
|
||||
for _, status := range []contract.ActionStatus{"accepted", "processing", "cleanup_pending", "receipt_pending", "completed", "needs_attention"} {
|
||||
if !status.Valid() || status.Terminal() != (status == "completed" || status == "needs_attention") {
|
||||
t.Errorf("invalid action status %q", status)
|
||||
}
|
||||
}
|
||||
for _, status := range []contract.ArchiveStatus{"disabled", "pending", "processing", "succeeded", "failed"} {
|
||||
if !status.Valid() {
|
||||
t.Errorf("invalid archive status %q", status)
|
||||
}
|
||||
}
|
||||
for _, status := range []contract.ReplayDisposition{"none", "pending", "processing", "completed", "needs_attention"} {
|
||||
if !status.Valid() {
|
||||
t.Errorf("invalid disposition %q", status)
|
||||
}
|
||||
}
|
||||
if contract.ActionStatus("succeeded").Valid() || contract.ArchiveStatus("completed").Valid() || contract.ReplayDisposition("receipt_pending").Valid() {
|
||||
t.Fatal("status domains were conflated")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user