fix: derive source build version from fork metadata
This commit is contained in:
1 parent
2a3d7200ef
commit
b3297a6ecc
6 files changed
+128
-123
No files matched your search
@@ -399,7 +399,7 @@ docker compose \
|
||||
docker exec sub2api /app/sub2api -version
|
||||
```
|
||||
|
||||
维护者发布新的源码版本时必须递增 `FORK_VERSION`,例如从 `0.1.177-overdraft.1` 改为 `0.1.177-overdraft.2`。同步到新的上游 Sub2API 版本时,使用 `0.1.178-overdraft.1` 这样的版本号。
|
||||
维护者发布新的源码版本时必须递增 `FORK_VERSION`,例如从 `0.1.177-overdraft.2` 改为 `0.1.177-overdraft.3`。同步到新的上游 Sub2API 版本时,使用 `0.1.178-overdraft.1` 这样的版本号。
|
||||
|
||||
## 合并 Sub2API 官方更新
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
源码 Docker 构建会读取根目录的 `FORK_VERSION`,并以 `BuildType=source` 写入二进制。后台更新服务通过 GitHub Contents API 读取 Fork 分支上的同名文件,使用语义化版本比较判断是否有新版本。Redis 缓存同时记录仓库和构建类型,因此旧的官方更新缓存不会继续生效。
|
||||
|
||||
源码构建仅显示 `git pull` 更新提示,`PerformUpdate`、指定版本回退和在线回退列表均被禁用,防止官方二进制覆盖透支功能。维护者每次发布 Fork 更新都必须递增 `FORK_VERSION`;普通补丁使用 `0.1.177-overdraft.2`,同步下一上游版本后使用 `0.1.178-overdraft.1`。
|
||||
源码构建仅显示 `git pull` 更新提示,`PerformUpdate`、指定版本回退和在线回退列表均被禁用,防止官方二进制覆盖透支功能。维护者每次发布 Fork 更新都必须递增 `FORK_VERSION`;当前版本为 `0.1.177-overdraft.3`,同步下一上游版本后使用 `0.1.178-overdraft.1`。
|
||||
|
||||
Sub2API `v0.1.177` 将原生 remote compaction v2 保留在 `/responses` 路径。本定制同时检查旧 Compact 路径和原生 v2 请求信号,二者都不会开启额度透支调度或注入透支请求形态。
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0.1.177-overdraft.2
|
||||
0.1.177-overdraft.3
|
||||
@@ -9,7 +9,9 @@ services:
|
||||
context: ..
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
VERSION: ${BUILD_VERSION:-}
|
||||
# Keep this empty so source builds always read the tracked FORK_VERSION.
|
||||
# This avoids unrelated host BUILD_VERSION values overriding the Fork version.
|
||||
VERSION: ""
|
||||
COMMIT: ${BUILD_COMMIT:-local}
|
||||
BUILD_TYPE: source
|
||||
environment:
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
- Sub2API 基础版本:`0.1.177`
|
||||
- Git 描述:`v0.1.177-1-gbaeac1f3d`
|
||||
- 基础提交:`baeac1f3de21d37b129405f092ef86c24b3f203d`
|
||||
- Patch 生成基准 Fork 提交:`9babce2dd30903f9b1d6590a202e94d932e555e5`
|
||||
- 目标 Git tree(不含 `patches/`):`0f0c2cc2cd65db4bd5ed4230f144d55319b56980`
|
||||
- SHA-256:`fb7d7686a8f90b1a0e6bc788740e240628a485c9ad7bf04d5c4fca84d42163c4`
|
||||
- 文件大小:236,992 字节
|
||||
- Patch 生成基准 Fork 提交:`2a3d7200ef78c18b8fea93916166048e75f2c5fa`
|
||||
- 目标 Git tree(不含 `patches/`):`9f9e51bfaeace5872f6fd467a7c4abc8a3f68c45`
|
||||
- SHA-256:`2242ef5be99144b1ab7067c8bf592b2df2dc0473bc9ddb0814fe07af945d87ca`
|
||||
- 文件大小:237,205 字节
|
||||
|
||||
该 Patch 包含 Codex 5h / 7d 额度透支后端、前端显示、配置、源码构建 Compose、品牌和公开部署文档,并额外包含以下修复:
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
- `failed` 状态、账号暂停和 scheduler outbox 在同一个数据库事务内提交,并对持久化失败进行有限重试和同周期幂等保护。
|
||||
- 更新检查跟踪 `DeanZFC/sub2api-overdraft` 的 `codex-overdraft` 分支和 `FORK_VERSION`,不再把官方 Release 误报为 Fork 更新。
|
||||
- 源码构建只提示 `git pull` 和重新构建,禁用可能覆盖 Fork 功能的二进制在线更新与回退。
|
||||
- 源码 Compose 构建固定从仓库 `FORK_VERSION` 读取版本,避免宿主机遗留的 `BUILD_VERSION` 把页面版本覆盖成分支名。
|
||||
- 兼容 Sub2API `v0.1.177` 的原生 remote compaction v2,旧 Compact 与原生 v2 均不会误启用透支调度。
|
||||
- 新增对应后端单元测试和故障排查日志。
|
||||
|
||||
@@ -65,10 +66,10 @@ git apply --3way /tmp/sub2api-overdraft.patch
|
||||
本 Patch 已在临时工作树中从基础提交执行 `git apply --check` 和三方应用。应用后写入的 Git tree 为:
|
||||
|
||||
```text
|
||||
0f0c2cc2cd65db4bd5ed4230f144d55319b56980
|
||||
9f9e51bfaeace5872f6fd467a7c4abc8a3f68c45
|
||||
```
|
||||
|
||||
它与生成 Patch 时本地源码快照排除 `patches/` 后的 Git tree 完全一致;该快照基于 Fork 提交 `9babce2dd30903f9b1d6590a202e94d932e555e5` 生成。
|
||||
它与生成 Patch 时本地源码快照排除 `patches/` 后的 Git tree 完全一致;该快照基于 Fork 提交 `2a3d7200ef78c18b8fea93916166048e75f2c5fa` 生成。
|
||||
|
||||
## 历史 Patch
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
diff --git a/CODEX_OVERDRAFT_DEPLOYMENT_CN.md b/CODEX_OVERDRAFT_DEPLOYMENT_CN.md
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b56121befe9bc0d66fc1a8c66723aa3f80f322cd
|
||||
index 0000000000000000000000000000000000000000..033045c921fdddf1542acc930169eb7b268fef4e
|
||||
--- /dev/null
|
||||
+++ b/CODEX_OVERDRAFT_DEPLOYMENT_CN.md
|
||||
@@ -0,0 +1,532 @@
|
||||
@@ -405,7 +405,7 @@ index 0000000000000000000000000000000000000000..b56121befe9bc0d66fc1a8c66723aa3f
|
||||
+docker exec sub2api /app/sub2api -version
|
||||
+```
|
||||
+
|
||||
+维护者发布新的源码版本时必须递增 `FORK_VERSION`,例如从 `0.1.177-overdraft.1` 改为 `0.1.177-overdraft.2`。同步到新的上游 Sub2API 版本时,使用 `0.1.178-overdraft.1` 这样的版本号。
|
||||
+维护者发布新的源码版本时必须递增 `FORK_VERSION`,例如从 `0.1.177-overdraft.2` 改为 `0.1.177-overdraft.3`。同步到新的上游 Sub2API 版本时,使用 `0.1.178-overdraft.1` 这样的版本号。
|
||||
+
|
||||
+## 合并 Sub2API 官方更新
|
||||
+
|
||||
@@ -538,7 +538,7 @@ index 0000000000000000000000000000000000000000..b56121befe9bc0d66fc1a8c66723aa3f
|
||||
+- 本项目不是 Sub2API 官方发行版,也不受 OpenAI 或其他上游服务商认可或支持。
|
||||
diff --git a/CODEX_QUOTA_OVERDRAFT_CUSTOMIZATION.md b/CODEX_QUOTA_OVERDRAFT_CUSTOMIZATION.md
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..cd63fe9772c27afb078a9f142f0f758213e6fee9
|
||||
index 0000000000000000000000000000000000000000..ef333abddeb14db8862f41e09ca652bf37077ce3
|
||||
--- /dev/null
|
||||
+++ b/CODEX_QUOTA_OVERDRAFT_CUSTOMIZATION.md
|
||||
@@ -0,0 +1,172 @@
|
||||
@@ -560,7 +560,7 @@ index 0000000000000000000000000000000000000000..cd63fe9772c27afb078a9f142f0f7582
|
||||
+
|
||||
+源码 Docker 构建会读取根目录的 `FORK_VERSION`,并以 `BuildType=source` 写入二进制。后台更新服务通过 GitHub Contents API 读取 Fork 分支上的同名文件,使用语义化版本比较判断是否有新版本。Redis 缓存同时记录仓库和构建类型,因此旧的官方更新缓存不会继续生效。
|
||||
+
|
||||
+源码构建仅显示 `git pull` 更新提示,`PerformUpdate`、指定版本回退和在线回退列表均被禁用,防止官方二进制覆盖透支功能。维护者每次发布 Fork 更新都必须递增 `FORK_VERSION`;普通补丁使用 `0.1.177-overdraft.2`,同步下一上游版本后使用 `0.1.178-overdraft.1`。
|
||||
+源码构建仅显示 `git pull` 更新提示,`PerformUpdate`、指定版本回退和在线回退列表均被禁用,防止官方二进制覆盖透支功能。维护者每次发布 Fork 更新都必须递增 `FORK_VERSION`;当前版本为 `0.1.177-overdraft.3`,同步下一上游版本后使用 `0.1.178-overdraft.1`。
|
||||
+
|
||||
+Sub2API `v0.1.177` 将原生 remote compaction v2 保留在 `/responses` 路径。本定制同时检查旧 Compact 路径和原生 v2 请求信号,二者都不会开启额度透支调度或注入透支请求形态。
|
||||
+
|
||||
@@ -768,11 +768,11 @@ index b2dfd7034f769abd7e8640090282e6b05a2af4a1..657985091514edeb8358800d4ac49ce7
|
||||
RUN apk add --no-cache \
|
||||
diff --git a/FORK_VERSION b/FORK_VERSION
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..115bae05560ec061ef244db4d0bef9d08ce386e0
|
||||
index 0000000000000000000000000000000000000000..1ae85b80e36aff6ac1d64baf355b2f82fc214bc9
|
||||
--- /dev/null
|
||||
+++ b/FORK_VERSION
|
||||
@@ -0,0 +1 @@
|
||||
+0.1.177-overdraft.2
|
||||
+0.1.177-overdraft.3
|
||||
diff --git a/README.md b/README.md
|
||||
index f4ad2fa6b028bdc70ac0b502104a345dd8d940c1..6be65ab56a9db6668cabc5ea86573b4e513816f7 100644
|
||||
--- a/README.md
|
||||
@@ -1447,6 +1447,110 @@ index 010442eb6bcf3b80d4e7d65c27d8b9dd966259d4..cc767ff48e0616b8c0772a969424f914
|
||||
})
|
||||
}
|
||||
|
||||
diff --git a/backend/internal/repository/account_repo_codex_overdraft_test.go b/backend/internal/repository/account_repo_codex_overdraft_test.go
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..7233698db0c0ecfcac47cda66d7144335e0176bd
|
||||
--- /dev/null
|
||||
+++ b/backend/internal/repository/account_repo_codex_overdraft_test.go
|
||||
@@ -0,0 +1,98 @@
|
||||
+package repository
|
||||
+
|
||||
+import (
|
||||
+ "context"
|
||||
+ "errors"
|
||||
+ "regexp"
|
||||
+ "testing"
|
||||
+ "time"
|
||||
+
|
||||
+ "github.com/DATA-DOG/go-sqlmock"
|
||||
+ "github.com/Wei-Shaw/sub2api/internal/service"
|
||||
+ "github.com/stretchr/testify/require"
|
||||
+)
|
||||
+
|
||||
+func TestFinalizeCodexQuotaOverdraftProbeFailedIsAtomic(t *testing.T) {
|
||||
+ db, mock, err := sqlmock.New()
|
||||
+ require.NoError(t, err)
|
||||
+ t.Cleanup(func() { _ = db.Close() })
|
||||
+
|
||||
+ now := time.Now().UTC()
|
||||
+ until := now.Add(5 * time.Hour)
|
||||
+ state := &service.CodexQuotaOverdraftProbeState{
|
||||
+ Status: "failed",
|
||||
+ CycleKey: "5h:quota-cycle",
|
||||
+ QuotaWindow: "5h",
|
||||
+ Attempts: 5,
|
||||
+ Limit: 5,
|
||||
+ StartedAt: now,
|
||||
+ RecoverAt: &until,
|
||||
+ }
|
||||
+ reason := service.BuildTempUnschedReasonPayload("codex_quota_overdraft", "quota exhausted")
|
||||
+
|
||||
+ mock.ExpectBegin()
|
||||
+ mock.ExpectExec(`(?s)UPDATE accounts.*temp_unschedulable_until.*codex_quota_overdraft_probe`).
|
||||
+ WithArgs(service.CodexQuotaOverdraftProbeExtraKey, sqlmock.AnyArg(), until, reason, int64(77), state.CycleKey).
|
||||
+ WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
+ mock.ExpectExec(regexp.QuoteMeta("INSERT INTO scheduler_outbox (event_type, account_id, group_id, payload, dedup_key)")).
|
||||
+ WithArgs(service.SchedulerOutboxEventAccountChanged, int64(77), nil, nil, sqlmock.AnyArg()).
|
||||
+ WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
+ mock.ExpectCommit()
|
||||
+
|
||||
+ repo := newAccountRepositoryWithSQL(nil, db, nil)
|
||||
+ finalized, err := repo.FinalizeCodexQuotaOverdraftProbeFailed(context.Background(), 77, state, until, reason)
|
||||
+
|
||||
+ require.NoError(t, err)
|
||||
+ require.True(t, finalized)
|
||||
+ require.NoError(t, mock.ExpectationsWereMet())
|
||||
+}
|
||||
+
|
||||
+func TestFinalizeCodexQuotaOverdraftProbeFailedRollsBackWhenOutboxFails(t *testing.T) {
|
||||
+ db, mock, err := sqlmock.New()
|
||||
+ require.NoError(t, err)
|
||||
+ t.Cleanup(func() { _ = db.Close() })
|
||||
+
|
||||
+ now := time.Now().UTC()
|
||||
+ until := now.Add(5 * time.Hour)
|
||||
+ state := &service.CodexQuotaOverdraftProbeState{
|
||||
+ Status: "failed",
|
||||
+ CycleKey: "5h:quota-cycle",
|
||||
+ QuotaWindow: "5h",
|
||||
+ Attempts: 5,
|
||||
+ Limit: 5,
|
||||
+ StartedAt: now,
|
||||
+ RecoverAt: &until,
|
||||
+ }
|
||||
+
|
||||
+ mock.ExpectBegin()
|
||||
+ mock.ExpectExec(`(?s)UPDATE accounts.*temp_unschedulable_until.*codex_quota_overdraft_probe`).
|
||||
+ WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
+ mock.ExpectExec(regexp.QuoteMeta("INSERT INTO scheduler_outbox (event_type, account_id, group_id, payload, dedup_key)")).
|
||||
+ WillReturnError(errors.New("outbox unavailable"))
|
||||
+ mock.ExpectRollback()
|
||||
+
|
||||
+ repo := newAccountRepositoryWithSQL(nil, db, nil)
|
||||
+ finalized, err := repo.FinalizeCodexQuotaOverdraftProbeFailed(context.Background(), 77, state, until, "quota exhausted")
|
||||
+
|
||||
+ require.ErrorContains(t, err, "outbox unavailable")
|
||||
+ require.False(t, finalized)
|
||||
+ require.NoError(t, mock.ExpectationsWereMet())
|
||||
+}
|
||||
+
|
||||
+func TestListDueCodexQuotaOverdraftProbesIncludesInconclusiveAndStalePending(t *testing.T) {
|
||||
+ db, mock, err := sqlmock.New()
|
||||
+ require.NoError(t, err)
|
||||
+ t.Cleanup(func() { _ = db.Close() })
|
||||
+
|
||||
+ now := time.Now().UTC()
|
||||
+ mock.ExpectQuery(`(?s)SELECT id.*status}' = 'inconclusive'.*retry_count.*status}' = 'pending'.*INTERVAL '2 minutes'`).
|
||||
+ WithArgs(service.PlatformOpenAI, service.AccountTypeOAuth, service.StatusActive, now, 3, 100).
|
||||
+ WillReturnRows(sqlmock.NewRows([]string{"id"}))
|
||||
+
|
||||
+ repo := newAccountRepositoryWithSQL(nil, db, nil)
|
||||
+ accounts, err := repo.ListDueCodexQuotaOverdraftProbes(context.Background(), now, 100)
|
||||
+
|
||||
+ require.NoError(t, err)
|
||||
+ require.Empty(t, accounts)
|
||||
+ require.NoError(t, mock.ExpectationsWereMet())
|
||||
+}
|
||||
diff --git a/backend/internal/repository/account_repo_schedulable_projection_test.go b/backend/internal/repository/account_repo_schedulable_projection_test.go
|
||||
index 76d7e0bdc5fe272bbb4aa1cf24e543ec9acb4a43..328e9f2853005aa9d9287f0de6bca64dbf5f1e2c 100644
|
||||
--- a/backend/internal/repository/account_repo_schedulable_projection_test.go
|
||||
@@ -4936,10 +5040,10 @@ index 095c550993527ea2b53871088f58b02e4082fc63..cd71e4a3d60fd8d9e5db3c8e8b96d28b
|
||||
#
|
||||
diff --git a/deploy/docker-compose.overdraft.yml b/deploy/docker-compose.overdraft.yml
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..eeb8525db74c458ecc7a213f0732d871799b5300
|
||||
index 0000000000000000000000000000000000000000..0ba503eda086a93e2e2fe4e9c3c612644e2c38cf
|
||||
--- /dev/null
|
||||
+++ b/deploy/docker-compose.overdraft.yml
|
||||
@@ -0,0 +1,16 @@
|
||||
@@ -0,0 +1,18 @@
|
||||
+# sub2api-overdraft source-build overlay.
|
||||
+# Use together with docker-compose.local.yml from this directory:
|
||||
+# docker compose -f docker-compose.local.yml -f docker-compose.overdraft.yml up -d --build
|
||||
@@ -4951,7 +5055,9 @@ index 0000000000000000000000000000000000000000..eeb8525db74c458ecc7a213f0732d871
|
||||
+ context: ..
|
||||
+ dockerfile: Dockerfile
|
||||
+ args:
|
||||
+ VERSION: ${BUILD_VERSION:-}
|
||||
+ # Keep this empty so source builds always read the tracked FORK_VERSION.
|
||||
+ # This avoids unrelated host BUILD_VERSION values overriding the Fork version.
|
||||
+ VERSION: ""
|
||||
+ COMMIT: ${BUILD_COMMIT:-local}
|
||||
+ BUILD_TYPE: source
|
||||
+ environment:
|
||||
@@ -5489,107 +5595,3 @@ index 19ef541bc61fe6cc69fbc27f36c3258111536220..b04c81ccbcb64b9ecce2511fbd443b96
|
||||
seven_day_sonnet: UsageProgress | null
|
||||
seven_day_fable?: UsageProgress | null
|
||||
thirty_day?: UsageProgress | null
|
||||
diff --git a/backend/internal/repository/account_repo_codex_overdraft_test.go b/backend/internal/repository/account_repo_codex_overdraft_test.go
|
||||
new file mode 100644
|
||||
index 000000000..7233698db
|
||||
--- /dev/null
|
||||
+++ b/backend/internal/repository/account_repo_codex_overdraft_test.go
|
||||
@@ -0,0 +1,98 @@
|
||||
+package repository
|
||||
+
|
||||
+import (
|
||||
+ "context"
|
||||
+ "errors"
|
||||
+ "regexp"
|
||||
+ "testing"
|
||||
+ "time"
|
||||
+
|
||||
+ "github.com/DATA-DOG/go-sqlmock"
|
||||
+ "github.com/Wei-Shaw/sub2api/internal/service"
|
||||
+ "github.com/stretchr/testify/require"
|
||||
+)
|
||||
+
|
||||
+func TestFinalizeCodexQuotaOverdraftProbeFailedIsAtomic(t *testing.T) {
|
||||
+ db, mock, err := sqlmock.New()
|
||||
+ require.NoError(t, err)
|
||||
+ t.Cleanup(func() { _ = db.Close() })
|
||||
+
|
||||
+ now := time.Now().UTC()
|
||||
+ until := now.Add(5 * time.Hour)
|
||||
+ state := &service.CodexQuotaOverdraftProbeState{
|
||||
+ Status: "failed",
|
||||
+ CycleKey: "5h:quota-cycle",
|
||||
+ QuotaWindow: "5h",
|
||||
+ Attempts: 5,
|
||||
+ Limit: 5,
|
||||
+ StartedAt: now,
|
||||
+ RecoverAt: &until,
|
||||
+ }
|
||||
+ reason := service.BuildTempUnschedReasonPayload("codex_quota_overdraft", "quota exhausted")
|
||||
+
|
||||
+ mock.ExpectBegin()
|
||||
+ mock.ExpectExec(`(?s)UPDATE accounts.*temp_unschedulable_until.*codex_quota_overdraft_probe`).
|
||||
+ WithArgs(service.CodexQuotaOverdraftProbeExtraKey, sqlmock.AnyArg(), until, reason, int64(77), state.CycleKey).
|
||||
+ WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
+ mock.ExpectExec(regexp.QuoteMeta("INSERT INTO scheduler_outbox (event_type, account_id, group_id, payload, dedup_key)")).
|
||||
+ WithArgs(service.SchedulerOutboxEventAccountChanged, int64(77), nil, nil, sqlmock.AnyArg()).
|
||||
+ WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
+ mock.ExpectCommit()
|
||||
+
|
||||
+ repo := newAccountRepositoryWithSQL(nil, db, nil)
|
||||
+ finalized, err := repo.FinalizeCodexQuotaOverdraftProbeFailed(context.Background(), 77, state, until, reason)
|
||||
+
|
||||
+ require.NoError(t, err)
|
||||
+ require.True(t, finalized)
|
||||
+ require.NoError(t, mock.ExpectationsWereMet())
|
||||
+}
|
||||
+
|
||||
+func TestFinalizeCodexQuotaOverdraftProbeFailedRollsBackWhenOutboxFails(t *testing.T) {
|
||||
+ db, mock, err := sqlmock.New()
|
||||
+ require.NoError(t, err)
|
||||
+ t.Cleanup(func() { _ = db.Close() })
|
||||
+
|
||||
+ now := time.Now().UTC()
|
||||
+ until := now.Add(5 * time.Hour)
|
||||
+ state := &service.CodexQuotaOverdraftProbeState{
|
||||
+ Status: "failed",
|
||||
+ CycleKey: "5h:quota-cycle",
|
||||
+ QuotaWindow: "5h",
|
||||
+ Attempts: 5,
|
||||
+ Limit: 5,
|
||||
+ StartedAt: now,
|
||||
+ RecoverAt: &until,
|
||||
+ }
|
||||
+
|
||||
+ mock.ExpectBegin()
|
||||
+ mock.ExpectExec(`(?s)UPDATE accounts.*temp_unschedulable_until.*codex_quota_overdraft_probe`).
|
||||
+ WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
+ mock.ExpectExec(regexp.QuoteMeta("INSERT INTO scheduler_outbox (event_type, account_id, group_id, payload, dedup_key)")).
|
||||
+ WillReturnError(errors.New("outbox unavailable"))
|
||||
+ mock.ExpectRollback()
|
||||
+
|
||||
+ repo := newAccountRepositoryWithSQL(nil, db, nil)
|
||||
+ finalized, err := repo.FinalizeCodexQuotaOverdraftProbeFailed(context.Background(), 77, state, until, "quota exhausted")
|
||||
+
|
||||
+ require.ErrorContains(t, err, "outbox unavailable")
|
||||
+ require.False(t, finalized)
|
||||
+ require.NoError(t, mock.ExpectationsWereMet())
|
||||
+}
|
||||
+
|
||||
+func TestListDueCodexQuotaOverdraftProbesIncludesInconclusiveAndStalePending(t *testing.T) {
|
||||
+ db, mock, err := sqlmock.New()
|
||||
+ require.NoError(t, err)
|
||||
+ t.Cleanup(func() { _ = db.Close() })
|
||||
+
|
||||
+ now := time.Now().UTC()
|
||||
+ mock.ExpectQuery(`(?s)SELECT id.*status}' = 'inconclusive'.*retry_count.*status}' = 'pending'.*INTERVAL '2 minutes'`).
|
||||
+ WithArgs(service.PlatformOpenAI, service.AccountTypeOAuth, service.StatusActive, now, 3, 100).
|
||||
+ WillReturnRows(sqlmock.NewRows([]string{"id"}))
|
||||
+
|
||||
+ repo := newAccountRepositoryWithSQL(nil, db, nil)
|
||||
+ accounts, err := repo.ListDueCodexQuotaOverdraftProbes(context.Background(), now, 100)
|
||||
+
|
||||
+ require.NoError(t, err)
|
||||
+ require.Empty(t, accounts)
|
||||
+ require.NoError(t, mock.ExpectationsWereMet())
|
||||
+}
|
||||
Reference in new issue
Block a user