mirror of
https://github.com/Ravinou/borgwarehouse
synced 2026-03-14 14:25:46 +01:00
test: ✅ add repo API
This commit is contained in:
parent
49cfbf44e0
commit
e4dc585fe5
6 changed files with 230 additions and 11 deletions
|
|
@ -64,18 +64,18 @@ export default async function handler(
|
|||
|
||||
const newRepo: Repository = {
|
||||
id: repoList.length > 0 ? Math.max(...repoList.map((repo) => repo.id)) + 1 : 0,
|
||||
alias: alias!,
|
||||
alias: alias,
|
||||
repositoryName: '',
|
||||
status: false,
|
||||
lastSave: 0,
|
||||
lastStatusAlertSend: getUnixTime(new Date()),
|
||||
alert: alert!,
|
||||
storageSize: storageSize!,
|
||||
alert: alert ?? 0,
|
||||
storageSize: storageSize,
|
||||
storageUsed: 0,
|
||||
sshPublicKey: sshPublicKey!,
|
||||
comment: comment!,
|
||||
lanCommand: lanCommand!,
|
||||
appendOnlyMode: appendOnlyMode!,
|
||||
sshPublicKey: sshPublicKey,
|
||||
comment: comment ?? '',
|
||||
lanCommand: lanCommand ?? false,
|
||||
appendOnlyMode: appendOnlyMode ?? false,
|
||||
};
|
||||
|
||||
const { stdout, stderr } = await createRepoShell(
|
||||
|
|
@ -101,6 +101,7 @@ export default async function handler(
|
|||
|
||||
const validateRequestBody = (req: NextApiRequest) => {
|
||||
const { alias, sshPublicKey, storageSize, comment, alert, lanCommand, appendOnlyMode } = req.body;
|
||||
// Required fields
|
||||
if (!alias || typeof alias !== 'string') {
|
||||
throw new Error('Alias must be a non-empty string');
|
||||
}
|
||||
|
|
@ -110,16 +111,17 @@ const validateRequestBody = (req: NextApiRequest) => {
|
|||
if (typeof storageSize !== 'number' || storageSize <= 0 || !Number.isInteger(storageSize)) {
|
||||
throw new Error('Storage Size must be a positive integer');
|
||||
}
|
||||
if (typeof comment !== 'string') {
|
||||
// Optional fields
|
||||
if (comment != undefined && typeof comment !== 'string') {
|
||||
throw new Error('Comment must be a string');
|
||||
}
|
||||
if (typeof alert !== 'number') {
|
||||
if (alert != undefined && typeof alert !== 'number') {
|
||||
throw new Error('Alert must be a number');
|
||||
}
|
||||
if (typeof lanCommand !== 'boolean') {
|
||||
if (lanCommand != undefined && typeof lanCommand !== 'boolean') {
|
||||
throw new Error('Lan Command must be a boolean');
|
||||
}
|
||||
if (typeof appendOnlyMode !== 'boolean') {
|
||||
if (appendOnlyMode != undefined && typeof appendOnlyMode !== 'boolean') {
|
||||
throw new Error('Append Only Mode must be a boolean');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
201
tests/supertest/add.test.ts
Normal file
201
tests/supertest/add.test.ts
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
import { createMocks } from 'node-mocks-http';
|
||||
import handler from '~/pages/api/repo/add';
|
||||
import { getServerSession } from 'next-auth/next';
|
||||
import {
|
||||
getRepoList,
|
||||
updateRepoList,
|
||||
tokenController,
|
||||
isSshPubKeyDuplicate,
|
||||
} from '~/helpers/functions';
|
||||
import { createRepoShell } from '~/helpers/functions/shell.utils';
|
||||
|
||||
jest.mock('next-auth', () => {
|
||||
return jest.fn(() => {
|
||||
return {
|
||||
auth: { session: {} },
|
||||
GET: jest.fn(),
|
||||
POST: jest.fn(),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
jest.mock('next-auth/next', () => ({
|
||||
getServerSession: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('~/helpers/functions', () => ({
|
||||
getRepoList: jest.fn(),
|
||||
updateRepoList: jest.fn(),
|
||||
tokenController: jest.fn(),
|
||||
isSshPubKeyDuplicate: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('~/helpers/functions/shell.utils', () => ({
|
||||
createRepoShell: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('POST /api/repo/add', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.resetModules();
|
||||
jest.resetAllMocks();
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it('should return 405 if method is not POST', async () => {
|
||||
const { req, res } = createMocks({ method: 'GET' });
|
||||
await handler(req, res);
|
||||
expect(res._getStatusCode()).toBe(405);
|
||||
});
|
||||
|
||||
it('should return 401 if no session or authorization header is provided', async () => {
|
||||
const { req, res } = createMocks({ method: 'POST' });
|
||||
await handler(req, res);
|
||||
expect(res._getStatusCode()).toBe(401);
|
||||
});
|
||||
|
||||
it('should return 401 if API key is invalid', async () => {
|
||||
(getServerSession as jest.Mock).mockResolvedValue(null);
|
||||
(tokenController as jest.Mock).mockResolvedValue(null);
|
||||
const { req, res } = createMocks({
|
||||
method: 'POST',
|
||||
headers: { authorization: 'Bearer INVALID_API_KEY' },
|
||||
});
|
||||
await handler(req, res);
|
||||
expect(res._getStatusCode()).toBe(401);
|
||||
});
|
||||
|
||||
it('should return 403 if API key does not have create permissions', async () => {
|
||||
(getServerSession as jest.Mock).mockResolvedValue(null);
|
||||
(tokenController as jest.Mock).mockResolvedValue({ create: false });
|
||||
const { req, res } = createMocks({
|
||||
method: 'POST',
|
||||
headers: { authorization: 'Bearer API_KEY' },
|
||||
});
|
||||
await handler(req, res);
|
||||
expect(res._getStatusCode()).toBe(403);
|
||||
});
|
||||
|
||||
it('should return 409 if SSH key is duplicated', async () => {
|
||||
(getServerSession as jest.Mock).mockResolvedValue({ user: { name: 'USER' } });
|
||||
(getRepoList as jest.Mock).mockResolvedValue([{ id: 1, sshPublicKey: 'duplicate-key' }]);
|
||||
(isSshPubKeyDuplicate as jest.Mock).mockReturnValue(true);
|
||||
const { req, res } = createMocks({
|
||||
method: 'POST',
|
||||
body: { alias: 'repo1', sshPublicKey: 'duplicate-key', storageSize: 10 },
|
||||
});
|
||||
await handler(req, res);
|
||||
expect(res._getStatusCode()).toBe(409);
|
||||
});
|
||||
|
||||
it('should return 500 if createRepoShell fails', async () => {
|
||||
(getServerSession as jest.Mock).mockResolvedValue({ user: { name: 'USER' } });
|
||||
(getRepoList as jest.Mock).mockResolvedValue([]);
|
||||
(createRepoShell as jest.Mock).mockResolvedValue({ stderr: 'Error' });
|
||||
const { req, res } = createMocks({
|
||||
method: 'POST',
|
||||
body: { alias: 'repo1', sshPublicKey: 'valid-key', storageSize: 10 },
|
||||
});
|
||||
await handler(req, res);
|
||||
expect(res._getStatusCode()).toBe(500);
|
||||
});
|
||||
|
||||
it('should successfully create a repository with a session', async () => {
|
||||
(getServerSession as jest.Mock).mockResolvedValue({ user: { name: 'USER' } });
|
||||
(getRepoList as jest.Mock).mockResolvedValue([]);
|
||||
(createRepoShell as jest.Mock).mockResolvedValue({ stdout: 'new-repo' });
|
||||
(updateRepoList as jest.Mock).mockResolvedValue(true);
|
||||
const { req, res } = createMocks({
|
||||
method: 'POST',
|
||||
body: { alias: 'repo1', sshPublicKey: 'valid-key', storageSize: 10 },
|
||||
});
|
||||
await handler(req, res);
|
||||
expect(res._getStatusCode()).toBe(200);
|
||||
expect(res._getJSONData()).toEqual({ id: 0, repositoryName: 'new-repo' });
|
||||
});
|
||||
|
||||
it('should add missing optional properties with default values and update repo list correctly', async () => {
|
||||
(getServerSession as jest.Mock).mockResolvedValue({ user: { name: 'USER' } });
|
||||
(getRepoList as jest.Mock).mockResolvedValue([]);
|
||||
(createRepoShell as jest.Mock).mockResolvedValue({ stdout: 'new-repo' });
|
||||
(updateRepoList as jest.Mock).mockResolvedValue(true);
|
||||
|
||||
const { req, res } = createMocks({
|
||||
method: 'POST',
|
||||
body: { alias: 'repo1', sshPublicKey: 'valid-key', storageSize: 10 },
|
||||
});
|
||||
|
||||
await handler(req, res);
|
||||
|
||||
expect(res._getStatusCode()).toBe(200);
|
||||
expect(res._getJSONData()).toEqual({ id: 0, repositoryName: 'new-repo' });
|
||||
|
||||
expect(updateRepoList).toHaveBeenCalledWith(
|
||||
[
|
||||
{
|
||||
id: 0,
|
||||
alias: 'repo1',
|
||||
repositoryName: 'new-repo',
|
||||
status: false,
|
||||
lastSave: 0,
|
||||
lastStatusAlertSend: expect.any(Number),
|
||||
alert: 0,
|
||||
storageSize: 10,
|
||||
storageUsed: 0,
|
||||
sshPublicKey: 'valid-key',
|
||||
comment: '',
|
||||
lanCommand: false,
|
||||
appendOnlyMode: false,
|
||||
},
|
||||
],
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should assign the correct ID based on existing repositories', async () => {
|
||||
(getServerSession as jest.Mock).mockResolvedValue({ user: { name: 'USER' } });
|
||||
|
||||
(getRepoList as jest.Mock).mockResolvedValue([
|
||||
{ id: 0, alias: 'repo0', sshPublicKey: 'key0', storageSize: 10 },
|
||||
{ id: 1, alias: 'repo1', sshPublicKey: 'key1', storageSize: 20 },
|
||||
{ id: 3, alias: 'repo3', sshPublicKey: 'key3', storageSize: 30 },
|
||||
]);
|
||||
|
||||
(createRepoShell as jest.Mock).mockResolvedValue({ stdout: 'new-repo' });
|
||||
(updateRepoList as jest.Mock).mockResolvedValue(true);
|
||||
|
||||
const { req, res } = createMocks({
|
||||
method: 'POST',
|
||||
body: { alias: 'repo-new', sshPublicKey: 'new-key', storageSize: 50 },
|
||||
});
|
||||
|
||||
await handler(req, res);
|
||||
|
||||
expect(res._getStatusCode()).toBe(200);
|
||||
expect(res._getJSONData()).toEqual({ id: 4, repositoryName: 'new-repo' });
|
||||
|
||||
expect(updateRepoList).toHaveBeenCalledWith(
|
||||
[
|
||||
{ id: 0, alias: 'repo0', sshPublicKey: 'key0', storageSize: 10 },
|
||||
{ id: 1, alias: 'repo1', sshPublicKey: 'key1', storageSize: 20 },
|
||||
{ id: 3, alias: 'repo3', sshPublicKey: 'key3', storageSize: 30 },
|
||||
{
|
||||
id: 4,
|
||||
alias: 'repo-new',
|
||||
repositoryName: 'new-repo',
|
||||
status: false,
|
||||
lastSave: 0,
|
||||
lastStatusAlertSend: expect.any(Number),
|
||||
alert: 0,
|
||||
storageSize: 50,
|
||||
storageUsed: 0,
|
||||
sshPublicKey: 'new-key',
|
||||
comment: '',
|
||||
lanCommand: false,
|
||||
appendOnlyMode: false,
|
||||
},
|
||||
],
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -12,6 +12,10 @@ jest.mock('fs', () => ({
|
|||
}));
|
||||
|
||||
describe('Get Apprise Alert API', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it('should return 405 if the method is not GET', async () => {
|
||||
const { req, res } = createMocks({ method: 'POST' });
|
||||
await handler(req, res);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ jest.mock('fs', () => ({
|
|||
}));
|
||||
|
||||
describe('Get Apprise Mode API', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it('should return 405 if the method is not GET', async () => {
|
||||
const { req, res } = createMocks({ method: 'POST' });
|
||||
await handler(req, res);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ jest.mock('fs', () => ({
|
|||
}));
|
||||
|
||||
describe('Get Apprise Services API', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it('should return 405 if the method is not GET', async () => {
|
||||
const { req, res } = createMocks({ method: 'POST' });
|
||||
await handler(req, res);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ jest.mock('fs', () => ({
|
|||
}));
|
||||
|
||||
describe('Get Email Alert API', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it('should return 405 if the method is not GET', async () => {
|
||||
const { req, res } = createMocks({ method: 'POST' });
|
||||
await handler(req, res);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue