session.test.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { describe, expect, mock, test } from 'bun:test';
  2. import {
  3. abortSessionWithTimeout,
  4. OperationTimeoutError,
  5. promptWithTimeout,
  6. withTimeout,
  7. } from './session';
  8. function never<T>(): Promise<T> {
  9. return new Promise<T>(() => {});
  10. }
  11. describe('session utilities', () => {
  12. test('withTimeout resolves without waiting for the timeout', async () => {
  13. const result = await withTimeout(Promise.resolve('ok'), 50, 'too slow');
  14. expect(result).toBe('ok');
  15. });
  16. test('withTimeout rejects with OperationTimeoutError when operation hangs', async () => {
  17. await expect(withTimeout(never(), 5, 'too slow')).rejects.toThrow(
  18. OperationTimeoutError,
  19. );
  20. });
  21. test('promptWithTimeout aborts a timed-out prompt before rejecting', async () => {
  22. const abort = mock(async () => ({}));
  23. const prompt = mock(() => never());
  24. const client = {
  25. session: {
  26. abort,
  27. prompt,
  28. },
  29. } as any;
  30. await expect(
  31. promptWithTimeout(client, { path: { id: 's1' }, body: { parts: [] } }, 5),
  32. ).rejects.toThrow('Prompt timed out after 5ms');
  33. expect(abort).toHaveBeenCalledWith({ path: { id: 's1' } });
  34. });
  35. test('promptWithTimeout preserves timeout error when abort fails', async () => {
  36. const abort = mock(async () => {
  37. throw new Error('abort failed');
  38. });
  39. const prompt = mock(() => never());
  40. const client = {
  41. session: {
  42. abort,
  43. prompt,
  44. },
  45. } as any;
  46. await expect(
  47. promptWithTimeout(client, { path: { id: 's1' }, body: { parts: [] } }, 5),
  48. ).rejects.toThrow('Prompt timed out after 5ms');
  49. });
  50. test('promptWithTimeout honors abort signal when timeout is disabled', async () => {
  51. const controller = new AbortController();
  52. const abort = mock(async () => ({}));
  53. const prompt = mock(() => never());
  54. const client = {
  55. session: {
  56. abort,
  57. prompt,
  58. },
  59. } as any;
  60. queueMicrotask(() => controller.abort());
  61. await expect(
  62. promptWithTimeout(
  63. client,
  64. { path: { id: 's1' }, body: { parts: [] } },
  65. 0,
  66. controller.signal,
  67. ),
  68. ).rejects.toThrow('Prompt cancelled');
  69. });
  70. test('promptWithTimeout returns when prompt resolves with no timeout', async () => {
  71. const abort = mock(async () => ({}));
  72. const prompt = mock(async () => ({}));
  73. const client = {
  74. session: {
  75. abort,
  76. prompt,
  77. },
  78. } as any;
  79. await expect(
  80. promptWithTimeout(client, { path: { id: 's1' }, body: { parts: [] } }, 0),
  81. ).resolves.toBeUndefined();
  82. });
  83. test('abortSessionWithTimeout rejects if abort hangs', async () => {
  84. const client = {
  85. session: {
  86. abort: mock(() => never()),
  87. },
  88. } as any;
  89. await expect(abortSessionWithTimeout(client, 's1', 5)).rejects.toThrow(
  90. 'Session abort timed out after 5ms',
  91. );
  92. });
  93. });