Skip to content

Commit a7d295e

Browse files
committed
fix: preserve Codex rows on refresh errors
1 parent 9996958 commit a7d295e

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

menubar.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,9 +816,13 @@ def _refresh_in_background(self) -> None:
816816
except Exception as exc:
817817
if os.environ.get("USAGE_DEBUG") == "1":
818818
logger.warning("refresh failed", exc_info=True)
819+
codex_rows = codex_result["codex_rows"]
819820
codex_5h_pct = codex_result["codex_5h_pct"]
820821
codex_model = codex_result.get("codex_model", "unknown")
821822
state = _error_state(type(exc).__name__, self.mock, self.language)
823+
state.codex_session = codex_rows[0]
824+
state.codex_weekly = codex_rows[1]
825+
state.codex_stale = codex_result.get("codex_stale")
822826

823827
result = {"state": state, "codex_5h_pct": codex_5h_pct, "codex_model": codex_model}
824828
self.performSelectorOnMainThread_withObject_waitUntilDone_(

tests/test_menubar.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,57 @@ def button(self) -> FakeButton:
12181218
assert button.titles[-1].endswith("18.5%")
12191219

12201220

1221+
def test_refresh_error_preserves_codex_quota() -> None:
1222+
captured: dict[str, object] = {}
1223+
session = menubar_state.QuotaRowState(
1224+
title="Session",
1225+
percent=1.0,
1226+
percent_text="1% used",
1227+
reset_text="Resets in 4h",
1228+
color=menubar.CODEX_COLOR,
1229+
)
1230+
weekly = menubar_state.QuotaRowState(
1231+
title="Weekly",
1232+
percent=37.0,
1233+
percent_text="37% used",
1234+
reset_text="Resets in 5d",
1235+
color=menubar.CODEX_COLOR,
1236+
)
1237+
1238+
class Delegate:
1239+
mock = False
1240+
language = "en"
1241+
1242+
def _load_codex_refresh_result(self) -> dict[str, object]:
1243+
return {
1244+
"codex_rows": (session, weekly),
1245+
"codex_5h_pct": 1.0,
1246+
"codex_model": "gpt-test",
1247+
"codex_stale": None,
1248+
}
1249+
1250+
def performSelectorOnMainThread_withObject_waitUntilDone_(
1251+
self, selector: str, result: dict[str, object], wait: bool
1252+
) -> None:
1253+
captured["selector"] = selector
1254+
captured["result"] = result
1255+
captured["wait"] = wait
1256+
1257+
async def _fetch(self) -> PollOutcome:
1258+
raise RuntimeError("fetch failed")
1259+
1260+
menubar.AppDelegate._refresh_in_background(cast(Any, Delegate()))
1261+
1262+
result = captured["result"]
1263+
assert isinstance(result, dict)
1264+
state = result["state"]
1265+
assert isinstance(state, menubar_state.PopoverState)
1266+
assert state.codex_session == session
1267+
assert state.codex_weekly == weekly
1268+
assert result["codex_5h_pct"] == 1.0
1269+
assert result["codex_model"] == "gpt-test"
1270+
1271+
12211272
def test_refresh_now_queues_when_refresh_is_busy() -> None:
12221273
delegate = menubar.AppDelegate.alloc().initWithMock_interval_(True, 60)
12231274
delegate._refresh_in_flight = True

0 commit comments

Comments
 (0)