mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-07 20:16:46 +03:00
- Add comprehensive error logging in mirror-repo API endpoint - Enhance HTTP client error handling with detailed response information - Improve concurrency utility error reporting with context - Add specific detection and guidance for JSON parsing errors - Include troubleshooting information in error responses - Update tests to accommodate enhanced logging This will help users diagnose issues like 'JSON Parse error: Unexpected EOF' by providing detailed information about what responses are being received from the Gitea API and what might be causing the failures.
168 lines
5.1 KiB
TypeScript
168 lines
5.1 KiB
TypeScript
import { describe, test, expect, mock } from "bun:test";
|
|
import { processInParallel, processWithRetry } from "./concurrency";
|
|
|
|
describe("processInParallel", () => {
|
|
test("processes items in parallel with concurrency control", async () => {
|
|
// Create an array of numbers to process
|
|
const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
|
|
// Create a mock function to track execution
|
|
const processItem = mock(async (item: number) => {
|
|
// Simulate async work
|
|
await new Promise(resolve => setTimeout(resolve, 10));
|
|
return item * 2;
|
|
});
|
|
|
|
// Create a mock progress callback
|
|
const onProgress = mock((completed: number, total: number, result?: number) => {
|
|
// Progress tracking
|
|
});
|
|
|
|
// Process the items with a concurrency limit of 3
|
|
const results = await processInParallel(
|
|
items,
|
|
processItem,
|
|
3,
|
|
onProgress
|
|
);
|
|
|
|
// Verify results
|
|
expect(results).toEqual([2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
|
|
|
|
// Verify that processItem was called for each item
|
|
expect(processItem).toHaveBeenCalledTimes(10);
|
|
|
|
// Verify that onProgress was called for each item
|
|
expect(onProgress).toHaveBeenCalledTimes(10);
|
|
|
|
// Verify the last call to onProgress had the correct completed/total values
|
|
expect(onProgress.mock.calls[9][0]).toBe(10); // completed
|
|
expect(onProgress.mock.calls[9][1]).toBe(10); // total
|
|
});
|
|
|
|
test("handles errors in processing", async () => {
|
|
// Create an array of numbers to process
|
|
const items = [1, 2, 3, 4, 5];
|
|
|
|
// Create a mock function that throws an error for item 3
|
|
const processItem = mock(async (item: number) => {
|
|
if (item === 3) {
|
|
throw new Error("Test error");
|
|
}
|
|
return item * 2;
|
|
});
|
|
|
|
// Create a spy for console.error
|
|
const originalConsoleError = console.error;
|
|
const consoleErrorMock = mock(() => {});
|
|
console.error = consoleErrorMock;
|
|
|
|
try {
|
|
// Process the items
|
|
const results = await processInParallel(items, processItem);
|
|
|
|
// Verify results (should have 4 items, missing the one that errored)
|
|
expect(results).toEqual([2, 4, 8, 10]);
|
|
|
|
// Verify that processItem was called for each item
|
|
expect(processItem).toHaveBeenCalledTimes(5);
|
|
|
|
// Verify that console.error was called (enhanced logging calls it multiple times)
|
|
expect(consoleErrorMock).toHaveBeenCalled();
|
|
} finally {
|
|
// Restore console.error
|
|
console.error = originalConsoleError;
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("processWithRetry", () => {
|
|
test("retries failed operations", async () => {
|
|
// Create an array of numbers to process
|
|
const items = [1, 2, 3];
|
|
|
|
// Create a counter to track retry attempts
|
|
const attemptCounts: Record<number, number> = { 1: 0, 2: 0, 3: 0 };
|
|
|
|
// Create a mock function that fails on first attempt for item 2
|
|
const processItem = mock(async (item: number) => {
|
|
attemptCounts[item]++;
|
|
|
|
if (item === 2 && attemptCounts[item] === 1) {
|
|
throw new Error("Temporary error");
|
|
}
|
|
|
|
return item * 2;
|
|
});
|
|
|
|
// Create a mock for the onRetry callback
|
|
const onRetry = mock((item: number, error: Error, attempt: number) => {
|
|
// Retry tracking
|
|
});
|
|
|
|
// Process the items with retry
|
|
const results = await processWithRetry(items, processItem, {
|
|
maxRetries: 2,
|
|
retryDelay: 10,
|
|
onRetry,
|
|
});
|
|
|
|
// Verify results
|
|
expect(results).toEqual([2, 4, 6]);
|
|
|
|
// Verify that item 2 was retried once
|
|
expect(attemptCounts[1]).toBe(1); // No retries
|
|
expect(attemptCounts[2]).toBe(2); // One retry
|
|
expect(attemptCounts[3]).toBe(1); // No retries
|
|
|
|
// Verify that onRetry was called once
|
|
expect(onRetry).toHaveBeenCalledTimes(1);
|
|
expect(onRetry.mock.calls[0][0]).toBe(2); // item
|
|
expect(onRetry.mock.calls[0][2]).toBe(1); // attempt
|
|
});
|
|
|
|
test("gives up after max retries", async () => {
|
|
// Create an array of numbers to process
|
|
const items = [1, 2];
|
|
|
|
// Create a mock function that always fails for item 2
|
|
const processItem = mock(async (item: number) => {
|
|
if (item === 2) {
|
|
throw new Error("Persistent error");
|
|
}
|
|
return item * 2;
|
|
});
|
|
|
|
// Create a mock for the onRetry callback
|
|
const onRetry = mock((item: number, error: Error, attempt: number) => {
|
|
// Retry tracking
|
|
});
|
|
|
|
// Create a spy for console.error
|
|
const originalConsoleError = console.error;
|
|
const consoleErrorMock = mock(() => {});
|
|
console.error = consoleErrorMock;
|
|
|
|
try {
|
|
// Process the items with retry
|
|
const results = await processWithRetry(items, processItem, {
|
|
maxRetries: 2,
|
|
retryDelay: 10,
|
|
onRetry,
|
|
});
|
|
|
|
// Verify results (should have 1 item, missing the one that errored)
|
|
expect(results).toEqual([2]);
|
|
|
|
// Verify that onRetry was called twice (for 2 retry attempts)
|
|
expect(onRetry).toHaveBeenCalledTimes(2);
|
|
|
|
// Verify that console.error was called (enhanced logging calls it multiple times)
|
|
expect(consoleErrorMock).toHaveBeenCalled();
|
|
} finally {
|
|
// Restore console.error
|
|
console.error = originalConsoleError;
|
|
}
|
|
});
|
|
});
|