fix: wait for complete Agenda discovery (Closes #735)
This commit is contained in:
1 parent
4ac5a0f499
commit
64ff5127d8
6 files changed
+139
-6
No files matched your search
@@ -40,6 +40,89 @@ COMMENT_ACTIONS = Path(__file__).parents[1] / "frontend" / "comment-actions.js"
|
||||
PICK_WORK = Path(__file__).parents[1] / "frontend" / "pick-work.js"
|
||||
WORK_ROUTE = Path(__file__).parents[1] / "frontend" / "work-route.js"
|
||||
UPDATE_OWNERSHIP = Path(__file__).parents[1] / "frontend" / "update-ownership.js"
|
||||
AGENDA_SESSION_LAUNCHER = Path(__file__).parents[1] / "frontend" / "agenda-session-launcher.js"
|
||||
|
||||
|
||||
def test_agenda_session_launch_waits_for_complete_single_flight_discovery():
|
||||
script = f"""
|
||||
const createLauncher = require({json.dumps(str(AGENDA_SESSION_LAUNCHER))});
|
||||
let finishDiscovery;
|
||||
let discoveries = 0;
|
||||
let opens = 0;
|
||||
let queue = 'agenda';
|
||||
const launcher = createLauncher({{
|
||||
selectAgenda: () => {{ queue = 'agenda'; }},
|
||||
discover: () => {{
|
||||
discoveries += 1;
|
||||
return new Promise(resolve => {{ finishDiscovery = resolve; }});
|
||||
}},
|
||||
isAgendaSelected: () => queue === 'agenda',
|
||||
hasMore: () => false,
|
||||
hasCheckpoint: () => true,
|
||||
resume: () => {{ opens += 1; return true; }},
|
||||
start: () => {{ throw new Error('must resume'); }},
|
||||
announce: () => {{}},
|
||||
}});
|
||||
const first = launcher.open();
|
||||
const second = launcher.open();
|
||||
Promise.resolve().then(() => {{
|
||||
const before = {{discoveries, opens, same:first === second}};
|
||||
finishDiscovery(true);
|
||||
return Promise.all([first, second]).then(results => {{
|
||||
process.stdout.write(JSON.stringify({{before, results, discoveries, opens}}));
|
||||
}});
|
||||
}});
|
||||
"""
|
||||
result = subprocess.run(["node", "-e", script], capture_output=True, text=True)
|
||||
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert json.loads(result.stdout) == {
|
||||
"before": {"discoveries": 1, "opens": 0, "same": True},
|
||||
"results": ["opened", "opened"],
|
||||
"discoveries": 1,
|
||||
"opens": 1,
|
||||
}
|
||||
|
||||
|
||||
def test_agenda_session_launch_preserves_progress_when_discovery_fails_or_queue_changes():
|
||||
script = f"""
|
||||
const createLauncher = require({json.dumps(str(AGENDA_SESSION_LAUNCHER))});
|
||||
async function scenario(mode) {{
|
||||
let queue = 'agenda';
|
||||
let opens = 0;
|
||||
const messages = [];
|
||||
const launcher = createLauncher({{
|
||||
selectAgenda: () => {{ queue = 'agenda'; }},
|
||||
discover: async () => {{
|
||||
if (mode === 'leave') queue = 'today';
|
||||
if (mode === 'throw') throw new Error('offline');
|
||||
return mode !== 'incomplete';
|
||||
}},
|
||||
isAgendaSelected: () => queue === 'agenda',
|
||||
hasMore: () => mode === 'incomplete',
|
||||
hasCheckpoint: () => true,
|
||||
resume: () => {{ opens += 1; return true; }},
|
||||
start: () => {{ opens += 1; return true; }},
|
||||
announce: message => messages.push(message),
|
||||
}});
|
||||
return {{result:await launcher.open(), opens, messages}};
|
||||
}}
|
||||
Promise.all(['incomplete', 'throw', 'leave'].map(scenario)).then(results =>
|
||||
process.stdout.write(JSON.stringify(results))
|
||||
);
|
||||
"""
|
||||
result = subprocess.run(["node", "-e", script], capture_output=True, text=True)
|
||||
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert json.loads(result.stdout) == [
|
||||
{"result": "incomplete", "opens": 0, "messages": [
|
||||
"Agenda check paused. Retry to check older assigned deadlines."
|
||||
]},
|
||||
{"result": "incomplete", "opens": 0, "messages": [
|
||||
"Agenda check paused. Retry to check older assigned deadlines."
|
||||
]},
|
||||
{"result": "cancelled", "opens": 0, "messages": []},
|
||||
]
|
||||
|
||||
|
||||
def test_protect_today_route_is_an_explicit_agenda_action():
|
||||
@@ -305,7 +388,11 @@ process.stdout.write(JSON.stringify({{
|
||||
async def test_mobile_agenda_launcher_starts_or_resumes_the_durable_agenda_session():
|
||||
html = await dashboard()
|
||||
|
||||
assert '<script src="static/agenda-session-launcher.js"></script>' in html
|
||||
assert "openAgenda: openAgendaSession" in html
|
||||
assert "const agendaSessionLauncher = createAgendaSessionLauncher({" in html
|
||||
assert "discover: completeAgendaIssues" in html
|
||||
assert "hasMore: () => Boolean(workPagination.issue?.has_more)" in html
|
||||
assert "key: 'stackchain.agenda-session.v1'" in html
|
||||
assert "checkpoint: () => selectedWorkFilter === 'agenda' ? agendaSessionCheckpoint : sessionCheckpoint" in html
|
||||
assert "checkpointEnabled: () => ['today', 'agenda'].includes(selectedWorkFilter)" in html
|
||||
|
||||
@@ -786,6 +786,7 @@ def test_install_precaches_complete_subpath_scoped_app_shell():
|
||||
"/dashboard/static/mobile-task-dock.js",
|
||||
"/dashboard/static/mobile-work-entry.js",
|
||||
"/dashboard/static/mobile-queue-launcher.js",
|
||||
"/dashboard/static/agenda-session-launcher.js",
|
||||
"/dashboard/static/mobile-launch.js",
|
||||
"/dashboard/static/install-app.js",
|
||||
"/dashboard/static/mobile-device-setup.js",
|
||||
|
||||
Reference in new issue
Block a user