auto-run-timer-session-guard.test.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. const test = require('node:test');
  2. const assert = require('node:assert/strict');
  3. const fs = require('node:fs');
  4. const helperSource = fs.readFileSync('background.js', 'utf8');
  5. function extractFunction(source, name) {
  6. const markers = [`async function ${name}(`, `function ${name}(`];
  7. const start = markers
  8. .map((marker) => source.indexOf(marker))
  9. .find((index) => index >= 0);
  10. if (start < 0) {
  11. throw new Error(`missing function ${name}`);
  12. }
  13. let parenDepth = 0;
  14. let signatureEnded = false;
  15. let braceStart = -1;
  16. for (let i = start; i < source.length; i += 1) {
  17. const ch = source[i];
  18. if (ch === '(') {
  19. parenDepth += 1;
  20. } else if (ch === ')') {
  21. parenDepth -= 1;
  22. if (parenDepth === 0) {
  23. signatureEnded = true;
  24. }
  25. } else if (ch === '{' && signatureEnded) {
  26. braceStart = i;
  27. break;
  28. }
  29. }
  30. if (braceStart < 0) {
  31. throw new Error(`missing body for function ${name}`);
  32. }
  33. let depth = 0;
  34. let end = braceStart;
  35. for (; end < source.length; end += 1) {
  36. const ch = source[end];
  37. if (ch === '{') depth += 1;
  38. if (ch === '}') {
  39. depth -= 1;
  40. if (depth === 0) {
  41. end += 1;
  42. break;
  43. }
  44. }
  45. }
  46. return source.slice(start, end);
  47. }
  48. const helperBundle = [
  49. extractFunction(helperSource, 'normalizeRunCount'),
  50. extractFunction(helperSource, 'normalizeAutoRunTimerKind'),
  51. extractFunction(helperSource, 'normalizeAutoRunSessionId'),
  52. extractFunction(helperSource, 'isCurrentAutoRunSessionId'),
  53. extractFunction(helperSource, 'normalizeAutoRunTimerPlan'),
  54. extractFunction(helperSource, 'getAutoRunTimerResumeOptions'),
  55. extractFunction(helperSource, 'launchAutoRunTimerPlan'),
  56. ].join('\n');
  57. test('launchAutoRunTimerPlan ignores stale timer plans after stop invalidates the session', async () => {
  58. const api = new Function(`
  59. const AUTO_RUN_TIMER_KIND_SCHEDULED_START = 'scheduled_start';
  60. const AUTO_RUN_TIMER_KIND_BETWEEN_ROUNDS = 'between_rounds';
  61. const AUTO_RUN_TIMER_KIND_BEFORE_RETRY = 'before_retry';
  62. const AUTO_RUN_MAX_RETRIES_PER_ROUND = 3;
  63. let autoRunTimerLaunching = false;
  64. let autoRunActive = false;
  65. let autoRunCurrentRun = 0;
  66. let autoRunTotalRuns = 1;
  67. let autoRunAttemptRun = 0;
  68. let autoRunSessionId = 0;
  69. const state = {
  70. autoRunDelayEnabled: false,
  71. autoRunTimerPlan: {
  72. kind: AUTO_RUN_TIMER_KIND_SCHEDULED_START,
  73. fireAt: Date.now() + 60_000,
  74. totalRuns: 2,
  75. autoRunSkipFailures: false,
  76. autoRunSessionId: 42,
  77. countdownTitle: '已计划自动运行',
  78. countdownNote: '等待启动',
  79. },
  80. };
  81. let startCalls = 0;
  82. let clearStopCalls = 0;
  83. let clearAlarmCalls = 0;
  84. async function getState() {
  85. return { ...state };
  86. }
  87. function getPendingAutoRunTimerPlan() {
  88. return state.autoRunTimerPlan;
  89. }
  90. async function clearAutoRunTimerAlarm() {
  91. clearAlarmCalls += 1;
  92. }
  93. async function broadcastAutoRunStatus() {}
  94. async function addLog() {}
  95. async function setAutoRunDelayEnabledState() {}
  96. function serializeAutoRunRoundSummaries(totalRuns, summaries = []) {
  97. return Array.isArray(summaries) ? summaries : [];
  98. }
  99. function clearStopRequest() {
  100. clearStopCalls += 1;
  101. }
  102. function startAutoRunLoop() {
  103. startCalls += 1;
  104. }
  105. ${helperBundle}
  106. return {
  107. launchAutoRunTimerPlan,
  108. snapshot() {
  109. return {
  110. startCalls,
  111. clearStopCalls,
  112. clearAlarmCalls,
  113. autoRunCurrentRun,
  114. autoRunTotalRuns,
  115. autoRunAttemptRun,
  116. };
  117. },
  118. };
  119. `)();
  120. const started = await api.launchAutoRunTimerPlan('alarm');
  121. const snapshot = api.snapshot();
  122. assert.equal(started, false);
  123. assert.equal(snapshot.startCalls, 0, 'stale timer plan should not restart auto-run');
  124. assert.equal(snapshot.clearStopCalls, 0, 'stale timer plan should not clear the stop flag for a cancelled run');
  125. assert.equal(snapshot.clearAlarmCalls, 0, 'stale timer plan should not clear a potentially newer alarm');
  126. assert.equal(snapshot.autoRunCurrentRun, 0);
  127. assert.equal(snapshot.autoRunTotalRuns, 1);
  128. assert.equal(snapshot.autoRunAttemptRun, 0);
  129. });