diff --git a/helpers/functions/isSshPubKeyDuplicate.ts b/helpers/functions/isSshPubKeyDuplicate.ts index f33c60e..5d2e26c 100644 --- a/helpers/functions/isSshPubKeyDuplicate.ts +++ b/helpers/functions/isSshPubKeyDuplicate.ts @@ -9,10 +9,10 @@ import { Repository } from '~/types/domain/config.types'; * @returns {boolean} - Returns true if the SSH public key is duplicated, otherwise false. * @throws {Error} - Throws an error if required parameters are missing or invalid. */ -export default function isSshPubKeyDuplicate( +export const isSshPubKeyDuplicate = ( pubKey: string, repoList: Array> -) { +): boolean => { if (!pubKey || !repoList || !Array.isArray(repoList)) { throw new Error('Missing or invalid parameters for duplicate SSH public key check.'); } @@ -25,4 +25,4 @@ export default function isSshPubKeyDuplicate( const repoSshKeyWithoutComment = repo?.sshPublicKey.split(' ').slice(0, 2).join(' '); return repoSshKeyWithoutComment === pubKeyWithoutComment; }); -} +}; diff --git a/helpers/functions/shell.utils.ts b/helpers/functions/shell.utils.ts index 2ab8e88..fd91380 100644 --- a/helpers/functions/shell.utils.ts +++ b/helpers/functions/shell.utils.ts @@ -5,19 +5,19 @@ import { LastSaveDTO, StorageUsedDTO } from '~/types/api/shell.types'; const exec = promisify(execCallback); -export const getLastSaveList = async (): Promise => { +export const getLastSaveListShell = async (): Promise => { const shellsDirectory = path.join(process.cwd(), '/helpers'); const { stdout } = await exec(`${shellsDirectory}/shells/getLastSave.sh`); return JSON.parse(stdout || '[]'); }; -export const getStorageUsed = async (): Promise => { +export const getStorageUsedShell = async (): Promise => { const shellsDirectory = path.join(process.cwd(), '/helpers'); const { stdout } = await exec(`${shellsDirectory}/shells/getStorageUsed.sh`); return JSON.parse(stdout || '[]'); }; -export const deleteRepo = async ( +export const deleteRepoShell = async ( repositoryName: string ): Promise<{ stdout: string; stderr: string }> => { const shellsDirectory = path.join(process.cwd(), '/helpers'); @@ -26,3 +26,16 @@ export const deleteRepo = async ( ); return { stdout, stderr }; }; + +export const updateRepoShell = async ( + repositoryName: string, + sshPublicKey: string, + storageSize: number, + appendOnlyMode: boolean +): Promise<{ stderr?: string }> => { + const shellsDirectory = path.join(process.cwd(), '/helpers'); + const { stderr } = await exec( + `${shellsDirectory}/shells/updateRepo.sh ${repositoryName} "${sshPublicKey}" ${storageSize} ${appendOnlyMode}` + ); + return { stderr }; +}; diff --git a/pages/api/cronjob/checkStatus.ts b/pages/api/cronjob/checkStatus.ts index 2b6804e..cedfefe 100644 --- a/pages/api/cronjob/checkStatus.ts +++ b/pages/api/cronjob/checkStatus.ts @@ -5,7 +5,7 @@ import { promisify } from 'util'; import ApiResponse from '~/helpers/functions/apiResponse'; import { getRepoList, getUsersList, updateRepoList } from '~/helpers/functions/fileHelpers'; import nodemailerSMTP from '~/helpers/functions/nodemailerSMTP'; -import { getLastSaveList } from '~/helpers/functions/shell.utils'; +import { getLastSaveListShell } from '~/helpers/functions/shell.utils'; import emailAlertStatus from '~/helpers/templates/emailAlertStatus'; import { BorgWarehouseApiResponse } from '~/types/api/error.types'; @@ -28,7 +28,7 @@ export default async function handler( try { const repoList = await getRepoList(); - const lastSaveList = await getLastSaveList(); + const lastSaveList = await getLastSaveListShell(); if (repoList.length === 0 || lastSaveList.length === 0) { return ApiResponse.success(res, 'Status cron executed. No repository to check.'); } diff --git a/pages/api/cronjob/getStorageUsed.ts b/pages/api/cronjob/getStorageUsed.ts index 148daa7..fb52419 100644 --- a/pages/api/cronjob/getStorageUsed.ts +++ b/pages/api/cronjob/getStorageUsed.ts @@ -1,7 +1,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { getRepoList, updateRepoList } from '~/helpers/functions'; import ApiResponse from '~/helpers/functions/apiResponse'; -import { getStorageUsed } from '~/helpers/functions/shell.utils'; +import { getStorageUsedShell } from '~/helpers/functions/shell.utils'; import { BorgWarehouseApiResponse } from '~/types/api/error.types'; export default async function handler( @@ -26,7 +26,7 @@ export default async function handler( return ApiResponse.success(res, 'Storage cron executed. No repository to check.'); } - const storageUsed = await getStorageUsed(); + const storageUsed = await getStorageUsedShell(); //Update the storageUsed value of each repository const updatedRepoList = repoList.map((repo) => { diff --git a/pages/api/repo/id/[slug]/delete.ts b/pages/api/repo/id/[slug]/delete.ts index 526ad7c..bff5b04 100644 --- a/pages/api/repo/id/[slug]/delete.ts +++ b/pages/api/repo/id/[slug]/delete.ts @@ -1,7 +1,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { getServerSession } from 'next-auth/next'; import { getRepoList, updateRepoList, tokenController } from '~/helpers/functions'; -import { deleteRepo } from '~/helpers/functions/shell.utils'; +import { deleteRepoShell } from '~/helpers/functions/shell.utils'; import ApiResponse from '~/helpers/functions/apiResponse'; import { BorgWarehouseApiResponse } from '~/types/api/error.types'; @@ -52,7 +52,7 @@ export default async function handler( return ApiResponse.notFound(res, 'Repository not found'); } - const { stderr } = await deleteRepo(repoList[indexToDelete].repositoryName); + const { stderr } = await deleteRepoShell(repoList[indexToDelete].repositoryName); if (stderr) { console.log('Delete repository error: ', stderr); diff --git a/pages/api/repo/id/[slug]/edit.js b/pages/api/repo/id/[slug]/edit.js deleted file mode 100644 index 0d8f9fa..0000000 --- a/pages/api/repo/id/[slug]/edit.js +++ /dev/null @@ -1,157 +0,0 @@ -import { promises as fs } from 'fs'; -import path from 'path'; -import { authOptions } from '../../../auth/[...nextauth]'; -import { getServerSession } from 'next-auth/next'; -import { alertOptions } from '../../../../../domain/constants'; -import repoHistory from '../../../../../helpers/functions/repoHistory'; -import tokenController from '../../../../../helpers/functions/tokenController'; -import isSshPubKeyDuplicate from '../../../../../helpers/functions/isSshPubKeyDuplicate'; -const util = require('node:util'); -const exec = util.promisify(require('node:child_process').exec); - -export default async function handler(req, res) { - if (req.method !== 'PATCH') { - return res.status(405).json({ status: 405, message: 'Method Not Allowed' }); - } - - // AUTHENTICATION - const FROM_IP = req.headers['x-forwarded-for'] || 'unknown'; - const session = await getServerSession(req, res, authOptions); - const { authorization } = req.headers; - - if (!(await isAuthenticated(session, authorization, FROM_IP))) { - res.status(401).json({ message: 'Invalid API key' }); - return; - } - - // DATA CONTROL - const { alias, sshPublicKey, storageSize, comment, alert, lanCommand, appendOnlyMode } = req.body; - - if (!isValidPatchData(req.body)) { - return res.status(422).json({ message: 'Unexpected data' }); - } - - try { - const repoList = await getRepoList(); - const repoId = parseInt(req.query.slug); - const filteredRepoList = repoList.filter((repo) => repo.id !== repoId); - - if (isSshKeyConflict(sshPublicKey, filteredRepoList)) { - return res.status(409).json({ - message: - 'The SSH key is already used in another repository. Please use another key or delete the key from the other repository.', - }); - } - - const repoIndex = repoList.findIndex((repo) => repo.id === repoId); - await updateRepoShell(repoList[repoIndex], sshPublicKey, storageSize, appendOnlyMode); - const newRepoList = updateRepoList(repoList, req.query.slug, { - alias, - sshPublicKey, - storageSize, - comment, - alert, - lanCommand, - appendOnlyMode, - }); - - await saveRepoList(newRepoList); - return res.status(200).json({ message: 'success' }); - } catch (error) { - handleError(error, res); - } -} - -// -------------- -// Functions -// -------------- -async function isAuthenticated(session, authorization, FROM_IP) { - if (session) return true; - - if (authorization) { - const API_KEY = authorization.split(' ')[1]; - const permissions = await tokenController(API_KEY, FROM_IP); - return permissions?.update; - } - return false; -} - -function isValidPatchData(body) { - const { alias, sshPublicKey, storageSize, comment, alert, lanCommand, appendOnlyMode } = body; - const expectedKeys = [ - 'alias', - 'sshPublicKey', - 'storageSize', - 'comment', - 'alert', - 'lanCommand', - 'appendOnlyMode', - ]; - const hasAtLeastOneKey = expectedKeys.some((key) => body.hasOwnProperty(key)); - const hasUnexpectedKeys = Object.keys(body).some((key) => !expectedKeys.includes(key)); - - return ( - hasAtLeastOneKey && - !hasUnexpectedKeys && - (typeof alias === 'undefined' || (typeof alias === 'string' && alias.trim() !== '')) && - (typeof sshPublicKey === 'undefined' || - (typeof sshPublicKey === 'string' && sshPublicKey.trim() !== '')) && - (typeof comment === 'undefined' || typeof comment === 'string') && - (typeof storageSize === 'undefined' || - (typeof storageSize === 'number' && Number.isInteger(storageSize) && storageSize > 0)) && - (typeof alert === 'undefined' || - (typeof alert === 'number' && alertOptions.some((option) => option.value === alert))) && - (typeof lanCommand === 'undefined' || typeof lanCommand === 'boolean') && - (typeof appendOnlyMode === 'undefined' || typeof appendOnlyMode === 'boolean') - ); -} - -async function getRepoList() { - const jsonDirectory = path.join(process.cwd(), '/config'); - const repoData = await fs.readFile(jsonDirectory + '/repo.json', 'utf8'); - return JSON.parse(repoData); -} - -function isSshKeyConflict(sshPublicKey, repoList) { - return typeof sshPublicKey === 'string' && isSshPubKeyDuplicate(sshPublicKey, repoList); -} - -async function updateRepoShell(repo, sshPublicKey, storageSize, appendOnlyMode) { - const shellsDirectory = path.join(process.cwd(), '/helpers'); - await exec( - `${shellsDirectory}/shells/updateRepo.sh ${repo.repositoryName} "${sshPublicKey ?? repo.sshPublicKey}" ${storageSize ?? repo.storageSize} ${appendOnlyMode ?? repo.appendOnlyMode}` - ); -} - -function updateRepoList(repoList, slug, updates) { - return repoList.map((repo) => - repo.id == slug - ? { - ...repo, - alias: updates.alias ?? repo.alias, - sshPublicKey: updates.sshPublicKey ?? repo.sshPublicKey, - storageSize: - updates.storageSize !== undefined ? Number(updates.storageSize) : repo.storageSize, - comment: updates.comment ?? repo.comment, - alert: updates.alert ?? repo.alert, - lanCommand: updates.lanCommand ?? repo.lanCommand, - appendOnlyMode: updates.appendOnlyMode ?? repo.appendOnlyMode, - } - : repo - ); -} - -async function saveRepoList(newRepoList) { - const jsonDirectory = path.join(process.cwd(), '/config'); - await repoHistory(newRepoList); - await fs.writeFile(jsonDirectory + '/repo.json', JSON.stringify(newRepoList)); -} - -function handleError(error, res) { - console.log(error); - if (error.code == 'ENOENT') { - res.status(500).json({ message: 'No such file or directory' }); - } else { - res.status(500).json({ message: error.stdout }); - } -} diff --git a/pages/api/repo/id/[slug]/edit.ts b/pages/api/repo/id/[slug]/edit.ts new file mode 100644 index 0000000..109f7f1 --- /dev/null +++ b/pages/api/repo/id/[slug]/edit.ts @@ -0,0 +1,127 @@ +import { promises as fs } from 'fs'; +import path from 'path'; +import { authOptions } from '../../../auth/[...nextauth]'; +import { getServerSession } from 'next-auth/next'; +import { alertOptions } from '~/types/domain/constants'; +import { + getRepoList, + updateRepoList, + tokenController, + isSshPubKeyDuplicate, +} from '~/helpers/functions'; +import { NextApiRequest, NextApiResponse } from 'next'; +import ApiResponse from '~/helpers/functions/apiResponse'; +import { Repository } from '~/types/domain/config.types'; +import { updateRepoShell } from '~/helpers/functions/shell.utils'; +const util = require('node:util'); +const exec = util.promisify(require('node:child_process').exec); + +export default async function handler( + req: NextApiRequest & { body: Partial }, + res: NextApiResponse +) { + if (req.method !== 'PATCH') { + return ApiResponse.methodNotAllowed(res); + } + + // AUTHENTICATION + const session = await getServerSession(req, res, authOptions); + const { authorization } = req.headers; + if (!session && !authorization) { + return ApiResponse.unauthorized(res); + } + + try { + if (!session && authorization) { + const permissions = await tokenController(req.headers); + if (!permissions) { + return ApiResponse.unauthorized(res, 'Invalid API key'); + } + if (!permissions.update) { + return ApiResponse.forbidden(res, 'Insufficient permissions'); + } + } + } catch (error) { + return ApiResponse.serverError(res); + } + + dataHandler(req, res); + + try { + const { alias, sshPublicKey, storageSize, comment, alert, lanCommand, appendOnlyMode } = + req.body; + const slug = req.query.slug; + const repoList = await getRepoList(); + const repoId = parseInt(slug as string, 10); + const repo = repoList.find((repo) => repo.id === repoId); + if (!repo) { + return ApiResponse.notFound(res, 'Repository not found'); + } + + const filteredRepoList = repoList.filter((repo) => repo.id !== repoId); + if (sshPublicKey && isSshPubKeyDuplicate(sshPublicKey, filteredRepoList)) { + return res.status(409).json({ + message: + 'The SSH key is already used in another repository. Please use another key or delete the key from the other repository.', + }); + } + + const updatedRepo: Repository = { + ...repo, + alias: alias ?? repo.alias, + sshPublicKey: sshPublicKey ?? repo.sshPublicKey, + storageSize: storageSize ?? repo.storageSize, + comment: comment ?? repo.comment, + alert: alert ?? repo.alert, + lanCommand: lanCommand ?? repo.lanCommand, + appendOnlyMode: appendOnlyMode ?? repo.appendOnlyMode, + }; + + const { stderr } = await updateRepoShell( + updatedRepo.repositoryName, + updatedRepo.sshPublicKey, + updatedRepo.storageSize, + updatedRepo.appendOnlyMode ?? false + ); + if (stderr) { + console.log('Update repository error: ', stderr); + return ApiResponse.serverError(res); + } + + const updatedRepoList = [...filteredRepoList, updatedRepo]; + await updateRepoList(updatedRepoList, true); + return res.status(200).json({ message: `Repository ${repo.repositoryName} has been edited` }); + } catch (error) { + console.error(error); + return ApiResponse.serverError(res); + } +} + +const dataHandler = (req: NextApiRequest, res: NextApiResponse) => { + const slug = req.query.slug; + if (!slug || Array.isArray(slug)) { + return ApiResponse.badRequest(res, 'Missing slug or slug is malformed'); + } + const { alias, sshPublicKey, storageSize, comment, alert, lanCommand, appendOnlyMode } = req.body; + if (alias !== undefined && typeof alias !== 'string') { + return ApiResponse.badRequest(res, 'Alias must be a string'); + } + if (sshPublicKey !== undefined && typeof sshPublicKey !== 'string') { + return ApiResponse.badRequest(res, 'SSH Public Key must be a string'); + } + if (storageSize !== undefined && typeof storageSize !== 'number') { + return ApiResponse.badRequest(res, 'Storage Size must be a number'); + } + if (comment !== undefined && typeof comment !== 'string') { + return ApiResponse.badRequest(res, 'Comment must be a string'); + } + if (alert !== undefined && typeof alert !== 'number') { + return ApiResponse.badRequest(res, 'Alert must be a number'); + } + if (lanCommand !== undefined && typeof lanCommand !== 'boolean') { + return ApiResponse.badRequest(res, 'Lan Command must be a boolean'); + } + if (appendOnlyMode !== undefined && typeof appendOnlyMode !== 'boolean') { + return ApiResponse.badRequest(res, 'Append Only Mode must be a boolean'); + } +}; diff --git a/tests/supertest/checkStatus.test.ts b/tests/supertest/checkStatus.test.ts index e3e77e5..c652dda 100644 --- a/tests/supertest/checkStatus.test.ts +++ b/tests/supertest/checkStatus.test.ts @@ -1,7 +1,7 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/cronjob/checkStatus'; import { getRepoList, getUsersList, updateRepoList } from '~/helpers/functions/fileHelpers'; -import { getLastSaveList } from '~/helpers/functions/shell.utils'; +import { getLastSaveListShell } from '~/helpers/functions/shell.utils'; import nodemailerSMTP from '~/helpers/functions/nodemailerSMTP'; jest.mock('~/helpers/functions/fileHelpers', () => ({ @@ -72,7 +72,9 @@ describe('Cronjob API Handler', () => { it('should return 200 with message if no repository to check (empty repoList)', async () => { (getRepoList as jest.Mock).mockResolvedValue([]); - (getLastSaveList as jest.Mock).mockResolvedValue([{ repositoryName: 'repo1', lastSave: 123 }]); + (getLastSaveListShell as jest.Mock).mockResolvedValue([ + { repositoryName: 'repo1', lastSave: 123 }, + ]); const { req, res } = createMocks({ method: 'POST', @@ -91,7 +93,7 @@ describe('Cronjob API Handler', () => { (getRepoList as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', alert: 100, alias: 'Repo1' }, ]); - (getLastSaveList as jest.Mock).mockResolvedValue([]); + (getLastSaveListShell as jest.Mock).mockResolvedValue([]); const { req, res } = createMocks({ method: 'POST', @@ -111,7 +113,7 @@ describe('Cronjob API Handler', () => { (getRepoList as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', alert: 1000, alias: 'Repo1', status: true }, ]); - (getLastSaveList as jest.Mock).mockResolvedValue([ + (getLastSaveListShell as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime }, ]); (updateRepoList as jest.Mock).mockResolvedValue(undefined); @@ -153,7 +155,7 @@ describe('Cronjob API Handler', () => { (getRepoList as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', alert: 100, alias: 'Repo1' }, ]); - (getLastSaveList as jest.Mock).mockResolvedValue([ + (getLastSaveListShell as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime - 200 }, ]); // User has disabled email alert but enabled Apprise alert @@ -183,7 +185,7 @@ describe('Cronjob API Handler', () => { (getRepoList as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', alert: 100, alias: 'Repo1' }, ]); - (getLastSaveList as jest.Mock).mockResolvedValue([ + (getLastSaveListShell as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime - 200 }, ]); // User has disabled Apprise alert but enabled email alert @@ -216,7 +218,7 @@ describe('Cronjob API Handler', () => { (getRepoList as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', alert: 0, alias: 'Repo1' }, ]); - (getLastSaveList as jest.Mock).mockResolvedValue([ + (getLastSaveListShell as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime - 1000 }, ]); (getUsersList as jest.Mock).mockResolvedValue([ @@ -252,7 +254,7 @@ describe('Cronjob API Handler', () => { (getRepoList as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', status: true, alert: 100 }, ]); - (getLastSaveList as jest.Mock).mockResolvedValue([ + (getLastSaveListShell as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', lastSave: Math.floor(Date.now() / 1000) }, ]); @@ -284,7 +286,7 @@ describe('Cronjob API Handler', () => { alert: 100, }, ]); - (getLastSaveList as jest.Mock).mockResolvedValue([ + (getLastSaveListShell as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime - 200 }, ]); (getUsersList as jest.Mock).mockResolvedValue([ @@ -322,7 +324,7 @@ describe('Cronjob API Handler', () => { lastStatusAlertSend: null, }, ]); - (getLastSaveList as jest.Mock).mockResolvedValue([ + (getLastSaveListShell as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime - 200 }, ]); @@ -358,7 +360,7 @@ describe('Cronjob API Handler', () => { lastStatusAlertSend: currentTime - 80000, }, ]); - (getLastSaveList as jest.Mock).mockResolvedValue([ + (getLastSaveListShell as jest.Mock).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime - 200 }, ]); (getUsersList as jest.Mock).mockResolvedValue([ diff --git a/tests/supertest/delete.test.ts b/tests/supertest/delete.test.ts index 8493019..2f717ed 100644 --- a/tests/supertest/delete.test.ts +++ b/tests/supertest/delete.test.ts @@ -2,7 +2,7 @@ import request from 'supertest'; import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/repo/id/[slug]/delete'; import { getServerSession } from 'next-auth/next'; -import { deleteRepo } from '~/helpers/functions/shell.utils'; +import { deleteRepoShell } from '~/helpers/functions/shell.utils'; import { getRepoList, tokenController, updateRepoList } from '~/helpers/functions'; jest.mock('next-auth', () => { @@ -106,7 +106,7 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { query: { slug: '123' }, }); (getRepoList as jest.Mock).mockResolvedValue([{ id: 123, repositoryName: 'test-repo' }]); - (deleteRepo as jest.Mock).mockResolvedValue({ stderr: 'Error' }); + (deleteRepoShell as jest.Mock).mockResolvedValue({ stderr: 'Error' }); await handler(req, res); expect(res._getStatusCode()).toBe(500); expect(res._getJSONData()).toEqual({ @@ -125,7 +125,7 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { query: { slug: '1234' }, }); (getRepoList as jest.Mock).mockResolvedValue([{ id: 1234, repositoryName: 'test-repo' }]); - (deleteRepo as jest.Mock).mockResolvedValue({ stderr: null }); + (deleteRepoShell as jest.Mock).mockResolvedValue({ stderr: null }); (updateRepoList as jest.Mock).mockResolvedValue(true); await handler(req, res); expect(res._getStatusCode()).toBe(200); @@ -147,7 +147,7 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { }, }); (getRepoList as jest.Mock).mockResolvedValue([{ id: 12345, repositoryName: 'test-repo2' }]); - (deleteRepo as jest.Mock).mockResolvedValue({ stderr: null }); + (deleteRepoShell as jest.Mock).mockResolvedValue({ stderr: null }); (updateRepoList as jest.Mock).mockResolvedValue(true); await handler(req, res); expect(res._getStatusCode()).toBe(200); diff --git a/tests/supertest/getStorageUsed.test.ts b/tests/supertest/getStorageUsed.test.ts index 4cbcff5..911ed4e 100644 --- a/tests/supertest/getStorageUsed.test.ts +++ b/tests/supertest/getStorageUsed.test.ts @@ -1,7 +1,7 @@ import handler from '~/pages/api/cronjob/getStorageUsed'; import { createMocks } from 'node-mocks-http'; import { getRepoList, updateRepoList } from '~/helpers/functions'; -import { getStorageUsed } from '~/helpers/functions/shell.utils'; +import { getStorageUsedShell } from '~/helpers/functions/shell.utils'; jest.mock('~/helpers/functions', () => ({ getRepoList: jest.fn(), @@ -66,7 +66,7 @@ describe('GET /api/cronjob/getStorageUsed', () => { ]; (getRepoList as jest.Mock).mockResolvedValue(mockRepoList); - (getStorageUsed as jest.Mock).mockResolvedValue(mockStorageUsed); + (getStorageUsedShell as jest.Mock).mockResolvedValue(mockStorageUsed); (updateRepoList as jest.Mock).mockResolvedValue(undefined); const { req, res } = createMocks({ @@ -109,7 +109,7 @@ describe('GET /api/cronjob/getStorageUsed', () => { const mockStorageUsed = [{ name: 'repo1', size: 100 }]; (getRepoList as jest.Mock).mockResolvedValue(mockRepoList); - (getStorageUsed as jest.Mock).mockResolvedValue(mockStorageUsed); + (getStorageUsedShell as jest.Mock).mockResolvedValue(mockStorageUsed); (updateRepoList as jest.Mock).mockResolvedValue(undefined); const { req, res } = createMocks({