From ae581e931144d4592a2b9aa79564f9591e6b5372 Mon Sep 17 00:00:00 2001 From: cxymds Date: Mon, 22 Jun 2026 17:13:45 +0800 Subject: [PATCH] fix: harden rebalance and decommission state --- lib/pool-operations.ts | 20 +++++++++++++++----- package.json | 2 +- tests/lib/pool-operations.test.js | 10 +++++----- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/pool-operations.ts b/lib/pool-operations.ts index 3935765..1df7038 100644 --- a/lib/pool-operations.ts +++ b/lib/pool-operations.ts @@ -205,13 +205,18 @@ function hasExplicitProgressPercent(record: JsonRecord): boolean { function deriveRebalanceProgressPercent(status: string, pools: PoolSummary[]): number { const state = normalizeState(status) - if (["completed", "complete", "success", "finished"].includes(state) && pools.every(isCompletedRebalancePool)) { + const rebalancePools = participatingRebalancePools(pools) + if ( + ["completed", "complete", "success", "finished"].includes(state) && + rebalancePools.length > 0 && + rebalancePools.every(isCompletedRebalancePool) + ) { return 100 } - if (pools.length === 0) return 0 + if (rebalancePools.length === 0) return 0 - const finishedPools = pools.filter(isCompletedRebalancePool).length - return Math.round((finishedPools / pools.length) * 100) + const finishedPools = rebalancePools.filter(isCompletedRebalancePool).length + return Math.round((finishedPools / rebalancePools.length) * 100) } function pickStatus(record: JsonRecord): string { @@ -357,6 +362,10 @@ function isCompletedRebalancePool(pool: PoolSummary): boolean { return ["completed", "complete", "success", "finished"].includes(normalizeState(pool.status)) } +function participatingRebalancePools(pools: PoolSummary[]): PoolSummary[] { + return pools.filter((pool) => !isIdleRebalancePool(pool) || hasProgress(pool.progress)) +} + function deriveStatusFromPools(pools: PoolSummary[]): string { if (pools.length === 0) return "" @@ -370,7 +379,8 @@ function deriveStatusFromPools(pools: PoolSummary[]): string { ) { return "running" } - if (pools.every(isCompletedRebalancePool)) { + const rebalancePools = participatingRebalancePools(pools) + if (rebalancePools.length > 0 && rebalancePools.every(isCompletedRebalancePool)) { return "completed" } if (pools.some(isCompletedRebalancePool) && pools.some(isIdleRebalancePool)) return "running" diff --git a/package.json b/package.json index 50cbce4..bd1f8f6 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ }, "packageManager": { "name": "pnpm", - "version": "^11.4.0", + "version": "11.5.0", "onFail": "error" } } diff --git a/tests/lib/pool-operations.test.js b/tests/lib/pool-operations.test.js index dc54eb3..7eb7217 100644 --- a/tests/lib/pool-operations.test.js +++ b/tests/lib/pool-operations.test.js @@ -139,7 +139,7 @@ test("normalizeRebalanceStatus reads progress and pool details", () => { assert.equal(status.pools[0]?.cleanupWarnings.lastBucket, "test-bucket") }) -test("normalizeRebalanceStatus does not complete mixed completed and idle pools", () => { +test("normalizeRebalanceStatus completes mixed completed and non-participating pools", () => { const status = normalizeRebalanceStatus({ id: "3be0831f-4315-4adb-9904-3bb0609b3bfc", pools: [ @@ -170,11 +170,11 @@ test("normalizeRebalanceStatus does not complete mixed completed and idle pools" stoppedAt: null, }) - assert.equal(status.status, "running") - assert.equal(status.progressPercent, 50) + assert.equal(status.status, "completed") + assert.equal(status.progressPercent, 100) assert.equal(status.pools[0]?.status, "Completed") assert.equal(status.pools[1]?.status, "None") - assert.equal(deriveRebalanceDisplayState(status, "supported"), "running") + assert.equal(deriveRebalanceDisplayState(status, "supported"), "completed") }) test("normalizeRebalanceStatus aggregates pool progress when totals are missing", () => { @@ -248,7 +248,7 @@ test("normalizeRebalanceStatus does not infer full progress from aggregated byte }) assert.equal(status.status, "failed") - assert.equal(status.progressPercent, 33) + assert.equal(status.progressPercent, 50) }) test("normalizeDecommissionInfo reads nested response", () => {