diff --git a/.husky/pre-commit b/.husky/pre-commit index 30892438..52ab21ca 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,5 +2,4 @@ . "$(dirname -- "$0")/_/husky.sh" pnpm test -pnpm -r test pnpm -r lint:fix diff --git a/packages/system-api/src/config/config.ts b/packages/system-api/src/config/config.ts index 269c3f76..0af6a43b 100644 --- a/packages/system-api/src/config/config.ts +++ b/packages/system-api/src/config/config.ts @@ -20,8 +20,6 @@ if (process.env.NODE_ENV !== 'production') { dotenv.config({ path: '.env' }); } -console.log('Production => ', process.env.NODE_ENV === 'production'); - const { LOGS_FOLDER = 'logs', LOGS_APP = 'app.log', diff --git a/packages/system-api/src/modules/apps/__tests__/apps.factory.ts b/packages/system-api/src/modules/apps/__tests__/apps.factory.ts index 86324ca3..8faa090d 100644 --- a/packages/system-api/src/modules/apps/__tests__/apps.factory.ts +++ b/packages/system-api/src/modules/apps/__tests__/apps.factory.ts @@ -3,7 +3,7 @@ import { AppCategoriesEnum, AppInfo, AppStatusEnum, FieldTypes } from '../apps.t import config from '../../../config'; import App from '../app.entity'; -const createApp = async (installed = false) => { +const createApp = async (installed = false, status = AppStatusEnum.RUNNING) => { const categories = Object.values(AppCategoriesEnum); const appInfo: AppInfo = { @@ -36,7 +36,7 @@ const createApp = async (installed = false) => { await App.create({ id: appInfo.id, config: { TEST_FIELD: 'test' }, - status: AppStatusEnum.RUNNING, + status, }).save(); MockFiles[`${config.ROOT_FOLDER}/app-data/${appInfo.id}`] = ''; diff --git a/packages/system-api/src/modules/apps/__tests__/apps.service.test.ts b/packages/system-api/src/modules/apps/__tests__/apps.service.test.ts index 9cf046a7..f9d7deff 100644 --- a/packages/system-api/src/modules/apps/__tests__/apps.service.test.ts +++ b/packages/system-api/src/modules/apps/__tests__/apps.service.test.ts @@ -21,6 +21,7 @@ beforeAll(async () => { beforeEach(async () => { jest.resetModules(); jest.resetAllMocks(); + jest.restoreAllMocks(); await App.clear(); }); @@ -193,6 +194,13 @@ describe('Start app', () => { expect(envFile.trim()).toBe(`TEST=test\nAPP_PORT=${app1.port}\nTEST_FIELD=test`); }); + + it('Should throw if start script fails', async () => { + const spy = jest.spyOn(childProcess, 'execFile'); + spy.mockImplementation(() => { + throw new Error('Test error'); + }); + }); }); describe('Stop app', () => { @@ -300,3 +308,56 @@ describe('List apps', () => { expect(apps[0].description).toBe('md desc'); }); }); + +describe('Start all apps', () => { + let app1: AppInfo; + let app2: AppInfo; + + beforeEach(async () => { + const app1create = await createApp(true); + const app2create = await createApp(true); + app1 = app1create.appInfo; + app2 = app2create.appInfo; + // @ts-ignore + fs.__createMockFiles(Object.assign(app1create.MockFiles, app2create.MockFiles)); + }); + + it('Should correctly start all apps', async () => { + const spy = jest.spyOn(childProcess, 'execFile'); + + await AppsService.startAllApps(); + + expect(spy.mock.calls.length).toBe(2); + expect(spy.mock.calls).toEqual([ + [`${config.ROOT_FOLDER}/scripts/app.sh`, ['start', app1.id, '/tipi'], {}, expect.any(Function)], + [`${config.ROOT_FOLDER}/scripts/app.sh`, ['start', app2.id, '/tipi'], {}, expect.any(Function)], + ]); + }); + + it('Should not start app which has not status RUNNING', async () => { + const spy = jest.spyOn(childProcess, 'execFile'); + await createApp(true, AppStatusEnum.STOPPED); + + await AppsService.startAllApps(); + const apps = await App.find(); + + expect(spy.mock.calls.length).toBe(2); + expect(apps.length).toBe(3); + }); + + it('Should put app status to STOPPED if start script fails', async () => { + const spy = jest.spyOn(childProcess, 'execFile'); + spy.mockImplementation(() => { + throw new Error('Test error'); + }); + + await AppsService.startAllApps(); + + const apps = await App.find(); + + expect(spy.mock.calls.length).toBe(2); + expect(apps.length).toBe(2); + expect(apps[0].status).toBe(AppStatusEnum.STOPPED); + expect(apps[1].status).toBe(AppStatusEnum.STOPPED); + }); +}); diff --git a/packages/system-api/src/modules/apps/apps.helpers.ts b/packages/system-api/src/modules/apps/apps.helpers.ts index ec86b407..49871ada 100644 --- a/packages/system-api/src/modules/apps/apps.helpers.ts +++ b/packages/system-api/src/modules/apps/apps.helpers.ts @@ -68,23 +68,6 @@ export const runAppScript = (params: string[]): Promise => { }); }; -export const ensureAppState = (appName: string, installed: boolean) => { - const state = readJsonFile('/state/apps.json'); - - if (installed) { - if (state.installed.indexOf(appName) === -1) { - state.installed += ` ${appName}`; - } - } else { - if (state.installed.indexOf(appName) !== -1) { - state.installed = state.installed.replace(`${appName}`, ''); - } - } - - state.installed = state.installed.replace(/\s+/g, ' ').trim(); - writeFile('/state/apps.json', JSON.stringify(state)); -}; - const getEntropy = (name: string, length: number) => { const hash = crypto.createHash('sha256'); hash.update(name); diff --git a/packages/system-api/src/modules/apps/apps.service.ts b/packages/system-api/src/modules/apps/apps.service.ts index 1d8f9cae..937e646a 100644 --- a/packages/system-api/src/modules/apps/apps.service.ts +++ b/packages/system-api/src/modules/apps/apps.service.ts @@ -2,6 +2,7 @@ import { createFolder, readFile, readJsonFile } from '../fs/fs.helpers'; import { checkAppRequirements, checkEnvFile, generateEnvFile, getAvailableApps, runAppScript } from './apps.helpers'; import { AppInfo, AppStatusEnum, ListAppsResonse } from './apps.types'; import App from './app.entity'; +import logger from '../../config/logger/logger'; const sortApps = (a: AppInfo, b: AppInfo) => a.name.localeCompare(b.name); @@ -21,7 +22,7 @@ const startAllApps = async (): Promise => { await App.update({ id: app.id }, { status: AppStatusEnum.RUNNING }); } catch (e) { await App.update({ id: app.id }, { status: AppStatusEnum.STOPPED }); - console.log(e); + logger.error(e); } }), );