Files
NeoTachyon/fe-app-tachyon/src/tachyon/methods/shell/tests/subscriptionUpdate.test.ts
T

259 lines
6.7 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const mocks = vi.hoisted(() => ({
executeShellCommand: vi.fn(),
}));
vi.mock('../../../../helpers', () => ({
executeShellCommand: mocks.executeShellCommand,
}));
import { TachyonShellMethods } from '../index';
describe('TachyonShellMethods.subscriptionUpdate', () => {
beforeEach(() => {
vi.useFakeTimers();
mocks.executeShellCommand.mockReset();
});
afterEach(() => {
vi.useRealTimers();
});
it('starts a targeted background subscription update and waits for its state', async () => {
mocks.executeShellCommand.mockImplementation(({ args }) => {
if (args[0] === 'subscription_update_async') {
return Promise.resolve({
stdout: JSON.stringify({
success: true,
job_id: 'job-1',
message: 'Subscription update started',
}),
stderr: '',
code: 0,
});
}
if (args[0] === 'subscription_update_status') {
return Promise.resolve({
stdout: JSON.stringify({
success: true,
running: false,
message: 'Subscription update completed',
exit_code: 0,
}),
stderr: '',
code: 0,
});
}
return Promise.resolve({
stdout: '',
stderr: 'Unexpected command',
code: 1,
});
});
await expect(
TachyonShellMethods.subscriptionUpdateStart('main'),
).resolves.toEqual({
success: true,
data: {
success: true,
job_id: 'job-1',
message: 'Subscription update started',
},
});
const responsePromise =
TachyonShellMethods.waitSubscriptionUpdateJob('job-1');
await vi.advanceTimersByTimeAsync(1500);
await expect(responsePromise).resolves.toEqual({
success: true,
data: {
success: true,
running: false,
message: 'Subscription update completed',
exit_code: 0,
},
});
expect(mocks.executeShellCommand).toHaveBeenNthCalledWith(1, {
command: '/usr/bin/tachyon',
args: ['subscription_update_async', 'main'],
timeout: 15000,
});
expect(mocks.executeShellCommand).toHaveBeenNthCalledWith(2, {
command: '/usr/bin/tachyon',
args: ['subscription_update_status', 'job-1'],
timeout: 15000,
});
});
it('returns the backend subscription start error message', async () => {
mocks.executeShellCommand.mockResolvedValue({
stdout: JSON.stringify({
success: false,
message: 'Subscription update is already running',
}),
stderr: '',
code: 1,
});
await expect(
TachyonShellMethods.subscriptionUpdateStart('main'),
).resolves.toEqual({
success: false,
error: 'Subscription update is already running',
});
});
it('returns failed finished job state from the low-level waiter for UI restoration', async () => {
mocks.executeShellCommand.mockImplementation(({ args }) => {
if (args[0] === 'subscription_update_status') {
return Promise.resolve({
stdout: JSON.stringify({
success: false,
running: false,
message: 'Failed to download subscriptions',
section: 'main',
source_index: '',
exit_code: 1,
}),
stderr: '',
code: 0,
});
}
return Promise.resolve({
stdout: '',
stderr: 'Unexpected command',
code: 1,
});
});
const responsePromise =
TachyonShellMethods.waitSubscriptionUpdateJob('job-1');
await vi.advanceTimersByTimeAsync(1500);
await expect(responsePromise).resolves.toEqual({
success: true,
data: {
success: false,
running: false,
message: 'Failed to download subscriptions',
section: 'main',
source_index: '',
exit_code: 1,
},
});
});
it('keeps following a subscription job after the former browser-side wait timeout while the backend reports it running', async () => {
let statusCalls = 0;
mocks.executeShellCommand.mockImplementation(({ args }) => {
if (args[0] === 'subscription_update_status') {
return Promise.resolve({
stdout: JSON.stringify(
statusCalls++ < 401
? {
success: true,
running: true,
message: 'Subscription update is running',
section: 'main',
source_index: '',
exit_code: null,
}
: {
success: true,
running: false,
message: 'Subscription update completed',
section: 'main',
source_index: '',
exit_code: 0,
},
),
stderr: '',
code: 0,
});
}
return Promise.resolve({
stdout: '',
stderr: 'Unexpected command',
code: 1,
});
});
const responsePromise =
TachyonShellMethods.waitSubscriptionUpdateJob('job-1');
await vi.advanceTimersByTimeAsync(10 * 60 * 1000 + 3000);
await expect(responsePromise).resolves.toEqual({
success: true,
data: {
success: true,
running: false,
message: 'Subscription update completed',
section: 'main',
source_index: '',
exit_code: 0,
},
});
});
it('keeps waiting through a transient RPC reply loss', async () => {
mocks.executeShellCommand.mockImplementation(({ args }) => {
if (args[0] === 'subscription_update_status') {
if (mocks.executeShellCommand.mock.calls.length === 1) {
return Promise.resolve({
stdout: '',
stderr: 'No related RPC reply',
code: 1,
});
}
return Promise.resolve({
stdout: JSON.stringify({
success: true,
running: false,
message: 'Subscription update completed',
section: 'main',
source_index: '',
exit_code: 0,
}),
stderr: '',
code: 0,
});
}
return Promise.resolve({
stdout: '',
stderr: 'Unexpected command',
code: 1,
});
});
const responsePromise =
TachyonShellMethods.waitSubscriptionUpdateJob('job-1');
await vi.advanceTimersByTimeAsync(3000);
await expect(responsePromise).resolves.toEqual({
success: true,
data: {
success: true,
running: false,
message: 'Subscription update completed',
section: 'main',
source_index: '',
exit_code: 0,
},
});
});
});