Files
RSSHub/lib/index.test.ts
Tony 3bc1cc248d chore: bump to msw v3 (#23463)
* chore: bump to msw v3

* refactor: anti-slop

* test: use vi.stubEnv for REDIS_URL in redis error test

* refactor: move remote debugging registration into a conditional block

* chore: add code coverage upload for github
2026-10-03 06:36:19 +08:00

121 lines
4.3 KiB
TypeScript

import cluster from 'node:cluster';
import fs from 'node:fs';
import os from 'node:os';
import { afterEach, describe, expect, it, vi } from 'vitest';
const serve = vi.fn<(...args: any[]) => any>(() => ({ close: vi.fn() }));
const listen = vi.fn();
const createAdaptorServer = vi.fn<(...args: any[]) => any>(() => ({ listen, close: vi.fn() }));
const rmSync = vi.spyOn(fs, 'rmSync').mockImplementation(() => {});
const fork = vi.spyOn(cluster, 'fork').mockImplementation(() => new cluster.Worker());
const clusterState = { isPrimary: true };
vi.spyOn(cluster, 'isPrimary', 'get').mockImplementation(() => clusterState.isPrimary);
const availableParallelism = vi.spyOn(os, 'availableParallelism').mockReturnValue(2);
vi.mock('@hono/node-server', () => ({
serve,
createAdaptorServer,
}));
describe('index', () => {
afterEach(() => {
vi.resetModules();
vi.unstubAllEnvs();
serve.mockClear();
createAdaptorServer.mockClear();
listen.mockClear();
rmSync.mockClear();
fork.mockClear();
availableParallelism.mockClear();
clusterState.isPrimary = true;
});
it('starts a server when cluster is disabled', async () => {
vi.stubEnv('ENABLE_CLUSTER', '');
vi.stubEnv('LISTEN_INADDR_ANY', '');
vi.stubEnv('PORT', '12345');
const module = await import('@/index');
expect(module.default).toBeDefined();
expect(serve).toHaveBeenCalledTimes(1);
expect(serve.mock.calls[0][0]).toMatchObject({
hostname: '127.0.0.1',
port: 12345,
});
expect(createAdaptorServer).not.toHaveBeenCalled();
});
it('forks workers when cluster is enabled and primary', async () => {
clusterState.isPrimary = true;
vi.stubEnv('ENABLE_CLUSTER', 'true');
vi.stubEnv('LISTEN_INADDR_ANY', 'true');
vi.stubEnv('PORT', '12346');
availableParallelism.mockReturnValue(2);
await import('@/index');
expect(fork).toHaveBeenCalledTimes(2);
expect(serve).not.toHaveBeenCalled();
});
it('starts a worker server when cluster is enabled and not primary', async () => {
clusterState.isPrimary = false;
vi.stubEnv('ENABLE_CLUSTER', 'true');
vi.stubEnv('LISTEN_INADDR_ANY', '');
vi.stubEnv('PORT', '12347');
await import('@/index');
expect(serve).toHaveBeenCalledTimes(1);
expect(serve.mock.calls[0][0]).toMatchObject({
hostname: '127.0.0.1',
port: 12347,
});
});
it('listens on a unix socket instead of a port when SOCKET is set', async () => {
vi.stubEnv('ENABLE_CLUSTER', '');
vi.stubEnv('LISTEN_INADDR_ANY', '');
vi.stubEnv('SOCKET', '/tmp/rsshub-test.sock');
vi.stubEnv('PORT', 'null');
const module = await import('@/index');
expect(module.default).toBeDefined();
expect(rmSync).toHaveBeenCalledWith('/tmp/rsshub-test.sock', { force: true });
expect(createAdaptorServer).toHaveBeenCalledTimes(1);
expect(createAdaptorServer.mock.calls[0][0]).toMatchObject({
hostname: '127.0.0.1',
});
expect(listen).toHaveBeenCalledWith('/tmp/rsshub-test.sock');
expect(serve).not.toHaveBeenCalled();
});
it('cluster primary removes a stale unix socket before forking', async () => {
clusterState.isPrimary = true;
vi.stubEnv('ENABLE_CLUSTER', 'true');
vi.stubEnv('SOCKET', '/tmp/rsshub-test.sock');
availableParallelism.mockReturnValue(2);
await import('@/index');
expect(rmSync).toHaveBeenCalledWith('/tmp/rsshub-test.sock', { force: true });
expect(fork).toHaveBeenCalledTimes(2);
expect(createAdaptorServer).not.toHaveBeenCalled();
expect(serve).not.toHaveBeenCalled();
});
it('cluster worker listens on the unix socket without removing it', async () => {
clusterState.isPrimary = false;
vi.stubEnv('ENABLE_CLUSTER', 'true');
vi.stubEnv('SOCKET', '/tmp/rsshub-test.sock');
await import('@/index');
expect(rmSync).not.toHaveBeenCalled();
expect(createAdaptorServer).toHaveBeenCalledTimes(1);
expect(listen).toHaveBeenCalledWith('/tmp/rsshub-test.sock');
expect(serve).not.toHaveBeenCalled();
});
});