fix: 修复顺运宝分页总数误判 (#60)
This commit is contained in:
+17
-4
@@ -621,7 +621,7 @@ func RunSybSyncWithOptions(ctx context.Context, db *sql.DB, client *syb.Client,
|
||||
orderedIDs := make([]int64, 0, plan.total)
|
||||
for start := 0; start < plan.total; start += pageSize {
|
||||
pageIndex := start/pageSize + 1
|
||||
rows, responseTotal, listErr := client.ListPage(ctx, plan.date, plan.date, start, pageIndex, pageSize)
|
||||
rows, pageCount, listErr := client.ListPage(ctx, plan.date, plan.date, start, pageIndex, pageSize)
|
||||
if listErr != nil {
|
||||
report.Err = fmt.Errorf("拉取 %s 货运单列表第 %d 页失败(已获取 %d/%d 张,本次同步整体作废,"+
|
||||
"下次会从同一个起始日期重新拉,靠 upsert 幂等不会重复计数): %w",
|
||||
@@ -629,9 +629,10 @@ func RunSybSyncWithOptions(ctx context.Context, db *sql.DB, client *syb.Client,
|
||||
report.FinishedAt = time.Now().UTC()
|
||||
return report
|
||||
}
|
||||
if responseTotal != plan.total {
|
||||
report.Err = fmt.Errorf("%s 货运单总数在分页期间从 %d 变为 %d,"+
|
||||
"为防止 offset 分页漏单,本次同步停止且不推进游标", plan.date, plan.total, responseTotal)
|
||||
expectedPageCount := min(pageSize, plan.total-start)
|
||||
if pageCount != expectedPageCount || len(rows) != expectedPageCount {
|
||||
report.Err = fmt.Errorf("%s 货运单列表第 %d 页不完整:预期 %d 行,实际 %d 行,"+
|
||||
"本次同步停止且不推进游标", plan.date, pageIndex, expectedPageCount, len(rows))
|
||||
report.FinishedAt = time.Now().UTC()
|
||||
return report
|
||||
}
|
||||
@@ -643,6 +644,18 @@ func RunSybSyncWithOptions(ctx context.Context, db *sql.DB, client *syb.Client,
|
||||
orderedIDs = append(orderedIDs, row.ID)
|
||||
}
|
||||
}
|
||||
afterTotal, totalErr := client.ListTotal(ctx, plan.date, plan.date, pageSize)
|
||||
if totalErr != nil {
|
||||
report.Err = fmt.Errorf("分页后重新查询 %s 货运单总数失败: %w", plan.date, totalErr)
|
||||
report.FinishedAt = time.Now().UTC()
|
||||
return report
|
||||
}
|
||||
if afterTotal != plan.total {
|
||||
report.Err = fmt.Errorf("%s 货运单总数在分页期间从 %d 变为 %d,"+
|
||||
"为防止 offset 分页漏单,本次同步停止且不推进游标", plan.date, plan.total, afterTotal)
|
||||
report.FinishedAt = time.Now().UTC()
|
||||
return report
|
||||
}
|
||||
if len(orderedIDs) != plan.total {
|
||||
report.Err = fmt.Errorf("%s 货运单列表不完整:预期 %d 张,分页后只有 %d 个唯一 ID,"+
|
||||
"本次同步停止且不推进游标", plan.date, plan.total, len(orderedIDs))
|
||||
|
||||
+23
-10
@@ -250,7 +250,8 @@ func fakeSybServer(t *testing.T, stocks []fakeStock, failListPageIndex int) *htt
|
||||
})
|
||||
}
|
||||
}
|
||||
writeEnvelope(t, w, true, "ok", map[string]any{"list": list, "total": len(filtered)}, nil)
|
||||
// 真实 HAR 中 data.total 是当前页条数,不是筛选范围总数。
|
||||
writeEnvelope(t, w, true, "ok", map[string]any{"list": list, "total": len(list)}, nil)
|
||||
|
||||
case "/am/stock/detail/listByStock":
|
||||
var body struct {
|
||||
@@ -314,21 +315,29 @@ func filterFakeStocksByRequest(t *testing.T, stocks []fakeStock, body map[string
|
||||
}
|
||||
|
||||
type integrityServerData struct {
|
||||
total int
|
||||
responseTotal int
|
||||
list []map[string]any
|
||||
details []map[string]any
|
||||
total int
|
||||
afterTotal int
|
||||
totalChanges bool
|
||||
pageCount int
|
||||
list []map[string]any
|
||||
details []map[string]any
|
||||
}
|
||||
|
||||
func fakeIntegritySybServer(t *testing.T, data integrityServerData) *httptest.Server {
|
||||
t.Helper()
|
||||
totalCalls := 0
|
||||
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/am/stock/listTotal":
|
||||
writeEnvelope(t, w, true, "ok", data.total, nil)
|
||||
totalCalls++
|
||||
total := data.total
|
||||
if data.totalChanges && totalCalls > 1 {
|
||||
total = data.afterTotal
|
||||
}
|
||||
writeEnvelope(t, w, true, "ok", total, nil)
|
||||
case "/am/stock/list":
|
||||
writeEnvelope(t, w, true, "ok", map[string]any{
|
||||
"list": data.list, "total": data.responseTotal,
|
||||
"list": data.list, "total": data.pageCount,
|
||||
}, nil)
|
||||
case "/am/stock/detail/listByStock":
|
||||
writeEnvelope(t, w, true, "ok", map[string]any{"list": data.details}, nil)
|
||||
@@ -813,10 +822,14 @@ func TestRunSybSync_列表或明细不完整时不推进游标(t *testing.T) {
|
||||
data integrityServerData
|
||||
wantErr string
|
||||
}{
|
||||
{name: "分页期间总数变化", data: integrityServerData{total: 2, responseTotal: 3, list: completeList}, wantErr: "分页期间"},
|
||||
{name: "列表存在重复ID", data: integrityServerData{total: 2, responseTotal: 2,
|
||||
{name: "页内报告条数与实际列表不符", data: integrityServerData{total: 2, pageCount: 1, list: completeList}, wantErr: "当前页条数"},
|
||||
{name: "当前页短于预期", data: integrityServerData{total: 2, pageCount: 1,
|
||||
list: []map[string]any{{"id": 1, "code": "A"}}}, wantErr: "第 1 页不完整"},
|
||||
{name: "分页前后总数变化", data: integrityServerData{total: 2, afterTotal: 3, totalChanges: true,
|
||||
pageCount: 2, list: completeList}, wantErr: "分页期间"},
|
||||
{name: "列表存在重复ID", data: integrityServerData{total: 2, pageCount: 2,
|
||||
list: []map[string]any{{"id": 1, "code": "A"}, {"id": 1, "code": "A"}}}, wantErr: "列表不完整"},
|
||||
{name: "明细缺少货运单", data: integrityServerData{total: 2, responseTotal: 2,
|
||||
{name: "明细缺少货运单", data: integrityServerData{total: 2, pageCount: 2,
|
||||
list: completeList, details: completeDetails[:1]}, wantErr: "明细不完整"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
|
||||
Reference in New Issue
Block a user