test: refactor with new paths

fix: make eslint happy
This commit is contained in:
Nicolas Meienberger 2024-03-08 09:49:46 +01:00 committed by Nicolas Meienberger
parent 8391874b90
commit d8934d7853
15 changed files with 59 additions and 75 deletions

View File

@ -46,7 +46,6 @@ ARG TIPI_VERSION
ENV SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN}
ENV SENTRY_DISABLE_AUTO_UPLOAD=${SENTRY_DISABLE_AUTO_UPLOAD}
ENV TIPI_VERSION=${TIPI_VERSION}
ENV NEXT_SHARP_PATH=/app/node_modules/sharp
RUN pnpm build
@ -93,6 +92,7 @@ ENV SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN}
ENV SENTRY_DISABLE_AUTO_UPLOAD=${SENTRY_DISABLE_AUTO_UPLOAD}
ENV TIPI_VERSION=${TIPI_VERSION}
RUN pnpm -r build --filter @runtipi/worker
# ---- RUNNER ----
@ -100,6 +100,7 @@ FROM runner_base AS app
ENV NODE_ENV=production
WORKDIR /worker
COPY --from=worker_builder /worker/packages/worker/dist .

View File

@ -8,22 +8,6 @@ const nextConfig = {
experimental: {
serverComponentsExternalPackages: ['bullmq', '@sentry/nextjs'],
},
serverRuntimeConfig: {
INTERNAL_IP: process.env.INTERNAL_IP,
TIPI_VERSION: process.env.TIPI_VERSION,
JWT_SECRET: process.env.JWT_SECRET,
POSTGRES_PASSWORD: process.env.POSTGRES_PASSWORD,
POSTGRES_USERNAME: process.env.POSTGRES_USERNAME,
POSTGRES_DBNAME: process.env.POSTGRES_DBNAME,
POSTGRES_HOST: process.env.POSTGRES_HOST,
APPS_REPO_ID: process.env.APPS_REPO_ID,
APPS_REPO_URL: process.env.APPS_REPO_URL,
DOMAIN: process.env.DOMAIN,
ARCHITECTURE: process.env.ARCHITECTURE,
NODE_ENV: process.env.NODE_ENV,
REDIS_HOST: process.env.REDIS_HOST,
ALLOW_ERROR_MONITORING: process.env.ALLOW_ERROR_MONITORING,
},
async rewrites() {
return [
{

View File

@ -1,5 +1,5 @@
import { DATA_DIR } from '@/config/constants';
import { FileLogger } from '@runtipi/shared/node';
import path from 'node:path';
import { DATA_DIR } from '@/config/constants';
export const logger = new FileLogger('worker', path.join(DATA_DIR, 'logs'), true);

View File

@ -245,7 +245,7 @@ export const generateTlsCertificates = async (data: { domain?: string }) => {
return;
}
const tlsFolder = path.join(ROOT_FOLDER, 'traefik', 'tls');
const tlsFolder = path.join(DATA_DIR, 'traefik', 'tls');
// If the certificate already exists, don't generate it again
if ((await pathExists(path.join(tlsFolder, `${data.domain}.txt`))) && (await pathExists(path.join(tlsFolder, 'cert.pem'))) && (await pathExists(path.join(tlsFolder, 'key.pem')))) {

View File

@ -7,7 +7,7 @@ import { AppExecutors } from '../app.executors';
import { createAppConfig } from '@/tests/apps.factory';
import * as dockerHelpers from '@/lib/docker';
import { getEnv } from '@/lib/environment';
import { ROOT_FOLDER, STORAGE_FOLDER } from '@/config/constants';
import { APP_DATA_DIR, DATA_DIR } from '@/config/constants';
const { appsRepoId } = getEnv();
@ -24,7 +24,7 @@ describe('test: app executors', () => {
const { message, success } = await appExecutors.installApp(config.id, config);
// assert
const envExists = await pathExists(path.join(STORAGE_FOLDER, 'app-data', config.id, 'app.env'));
const envExists = await pathExists(path.join(APP_DATA_DIR, config.id, 'app.env'));
expect(success).toBe(true);
expect(message).toBe(`App ${config.id} installed successfully`);
@ -53,14 +53,14 @@ describe('test: app executors', () => {
it('should delete existing app folder', async () => {
// arrange
const config = createAppConfig();
await fs.promises.mkdir(path.join(ROOT_FOLDER, 'apps', config.id), { recursive: true });
await fs.promises.writeFile(path.join(ROOT_FOLDER, 'apps', config.id, 'test.txt'), 'test');
await fs.promises.mkdir(path.join(DATA_DIR, 'apps', config.id), { recursive: true });
await fs.promises.writeFile(path.join(DATA_DIR, 'apps', config.id, 'test.txt'), 'test');
// act
await appExecutors.installApp(config.id, config);
// assert
const exists = await pathExists(path.join(STORAGE_FOLDER, 'apps', config.id, 'test.txt'));
const exists = await pathExists(path.join(DATA_DIR, 'apps', config.id, 'test.txt'));
expect(exists).toBe(false);
});
@ -69,13 +69,13 @@ describe('test: app executors', () => {
// arrange
const config = createAppConfig();
const filename = faker.system.fileName();
await fs.promises.writeFile(path.join(STORAGE_FOLDER, 'app-data', config.id, filename), 'test');
await fs.promises.writeFile(path.join(APP_DATA_DIR, config.id, filename), 'test');
// act
await appExecutors.installApp(config.id, config);
// assert
const exists = await pathExists(path.join(STORAGE_FOLDER, 'app-data', config.id, filename));
const exists = await pathExists(path.join(APP_DATA_DIR, config.id, filename));
expect(exists).toBe(true);
});
@ -84,15 +84,15 @@ describe('test: app executors', () => {
// arrange
const config = createAppConfig({}, false);
const filename = faker.system.fileName();
await fs.promises.mkdir(path.join(ROOT_FOLDER, 'repos', appsRepoId, 'apps', config.id, 'data'), { recursive: true });
await fs.promises.writeFile(path.join(ROOT_FOLDER, 'repos', appsRepoId, 'apps', config.id, 'data', filename), 'test');
await fs.promises.mkdir(path.join(DATA_DIR, 'repos', appsRepoId, 'apps', config.id, 'data'), { recursive: true });
await fs.promises.writeFile(path.join(DATA_DIR, 'repos', appsRepoId, 'apps', config.id, 'data', filename), 'test');
// act
await appExecutors.installApp(config.id, config);
// assert
const exists = await pathExists(path.join(STORAGE_FOLDER, 'app-data', config.id, 'data', filename));
const data = await fs.promises.readFile(path.join(STORAGE_FOLDER, 'app-data', config.id, 'data', filename), 'utf-8');
const exists = await pathExists(path.join(APP_DATA_DIR, config.id, 'data', filename));
const data = await fs.promises.readFile(path.join(APP_DATA_DIR, config.id, 'data', filename), 'utf-8');
expect(exists).toBe(true);
expect(data).toBe('test');
@ -102,16 +102,16 @@ describe('test: app executors', () => {
// arrange
const config = createAppConfig();
const filename = faker.system.fileName();
await fs.promises.writeFile(path.join(STORAGE_FOLDER, 'app-data', config.id, 'data', filename), 'test');
await fs.promises.mkdir(path.join(ROOT_FOLDER, 'repos', appsRepoId, 'apps', config.id, 'data'), { recursive: true });
await fs.promises.writeFile(path.join(ROOT_FOLDER, 'repos', appsRepoId, 'apps', config.id, 'data', filename), 'yeah');
await fs.promises.writeFile(path.join(APP_DATA_DIR, config.id, 'data', filename), 'test');
await fs.promises.mkdir(path.join(DATA_DIR, 'repos', appsRepoId, 'apps', config.id, 'data'), { recursive: true });
await fs.promises.writeFile(path.join(DATA_DIR, 'repos', appsRepoId, 'apps', config.id, 'data', filename), 'yeah');
// act
await appExecutors.installApp(config.id, config);
// assert
const exists = await pathExists(path.join(STORAGE_FOLDER, 'app-data', config.id, 'data', filename));
const data = await fs.promises.readFile(path.join(STORAGE_FOLDER, 'app-data', config.id, 'data', filename), 'utf-8');
const exists = await pathExists(path.join(APP_DATA_DIR, config.id, 'data', filename));
const data = await fs.promises.readFile(path.join(APP_DATA_DIR, config.id, 'data', filename), 'utf-8');
expect(exists).toBe(true);
expect(data).toBe('test');
@ -198,7 +198,7 @@ describe('test: app executors', () => {
it('should replace app directory with new one', async () => {
// arrange
const config = createAppConfig();
const oldFolder = path.join(ROOT_FOLDER, 'apps', config.id);
const oldFolder = path.join(DATA_DIR, 'apps', config.id);
await fs.promises.writeFile(path.join(oldFolder, 'docker-compose.yml'), 'test');

View File

@ -5,14 +5,14 @@ import { pathExists } from '@runtipi/shared/node';
import { copyDataDir, generateEnvFile } from '../app.helpers';
import { createAppConfig } from '@/tests/apps.factory';
import { getAppEnvMap } from '../env.helpers';
import { ROOT_FOLDER, STORAGE_FOLDER } from '@/config/constants';
import { APP_DATA_DIR, DATA_DIR } from '@/config/constants';
describe('app helpers', () => {
describe('Test: generateEnvFile()', () => {
it('should throw an error if the app has an invalid config.json file', async () => {
// arrange
const appConfig = createAppConfig();
await fs.promises.writeFile(`${ROOT_FOLDER}/apps/${appConfig.id}/config.json`, '{}');
await fs.promises.writeFile(`${DATA_DIR}/apps/${appConfig.id}/config.json`, '{}');
// act & assert
expect(generateEnvFile(appConfig.id, {})).rejects.toThrowError(`App ${appConfig.id} has invalid config.json file`);
@ -48,8 +48,8 @@ describe('app helpers', () => {
// arrange
const appConfig = createAppConfig({ form_fields: [{ env_variable: 'RANDOM_FIELD', type: 'random', label: 'test', min: 32, max: 32, required: true }] });
const randomField = faker.string.alphanumeric(32);
await fs.promises.mkdir(`${STORAGE_FOLDER}/app-data/${appConfig.id}`, { recursive: true });
await fs.promises.writeFile(`${STORAGE_FOLDER}/app-data/${appConfig.id}/app.env`, `RANDOM_FIELD=${randomField}`);
await fs.promises.mkdir(`${APP_DATA_DIR}/${appConfig.id}`, { recursive: true });
await fs.promises.writeFile(`${APP_DATA_DIR}/${appConfig.id}/app.env`, `RANDOM_FIELD=${randomField}`);
// act
await generateEnvFile(appConfig.id, {});
@ -115,7 +115,7 @@ describe('app helpers', () => {
it('Should not re-create app-data folder if it already exists', async () => {
// arrange
const appConfig = createAppConfig({});
await fs.promises.mkdir(`${ROOT_FOLDER}/app-data/${appConfig.id}`, { recursive: true });
await fs.promises.mkdir(`${DATA_DIR}/app-data/${appConfig.id}`, { recursive: true });
// act
await generateEnvFile(appConfig.id, {});
@ -159,8 +159,8 @@ describe('app helpers', () => {
const vapidPublicKey = faker.string.alphanumeric(32);
// act
await fs.promises.mkdir(`${STORAGE_FOLDER}/app-data/${appConfig.id}`, { recursive: true });
await fs.promises.writeFile(`${STORAGE_FOLDER}/app-data/${appConfig.id}/app.env`, `VAPID_PRIVATE_KEY=${vapidPrivateKey}\nVAPID_PUBLIC_KEY=${vapidPublicKey}`);
await fs.promises.mkdir(`${APP_DATA_DIR}/${appConfig.id}`, { recursive: true });
await fs.promises.writeFile(`${APP_DATA_DIR}/${appConfig.id}/app.env`, `VAPID_PRIVATE_KEY=${vapidPrivateKey}\nVAPID_PUBLIC_KEY=${vapidPublicKey}`);
await generateEnvFile(appConfig.id, {});
const envmap = await getAppEnvMap(appConfig.id);
@ -179,13 +179,13 @@ describe('app helpers', () => {
await copyDataDir(appConfig.id);
// assert
expect(await pathExists(`${ROOT_FOLDER}/apps/${appConfig.id}/data`)).toBe(false);
expect(await pathExists(`${DATA_DIR}/apps/${appConfig.id}/data`)).toBe(false);
});
it('should copy data dir to app-data folder', async () => {
// arrange
const appConfig = createAppConfig({});
const dataDir = `${ROOT_FOLDER}/apps/${appConfig.id}/data`;
const dataDir = `${DATA_DIR}/apps/${appConfig.id}/data`;
await fs.promises.mkdir(dataDir, { recursive: true });
await fs.promises.writeFile(`${dataDir}/test.txt`, 'test');
@ -194,14 +194,14 @@ describe('app helpers', () => {
await copyDataDir(appConfig.id);
// assert
const appDataDir = `${STORAGE_FOLDER}/app-data/${appConfig.id}`;
const appDataDir = `${APP_DATA_DIR}/${appConfig.id}`;
expect(await fs.promises.readFile(`${appDataDir}/data/test.txt`, 'utf8')).toBe('test');
});
it('should copy folders recursively', async () => {
// arrange
const appConfig = createAppConfig({});
const dataDir = `${ROOT_FOLDER}/apps/${appConfig.id}/data`;
const dataDir = `${DATA_DIR}/apps/${appConfig.id}/data`;
await fs.promises.mkdir(dataDir, { recursive: true });
@ -215,7 +215,7 @@ describe('app helpers', () => {
await copyDataDir(appConfig.id);
// assert
const appDataDir = `${STORAGE_FOLDER}/app-data/${appConfig.id}`;
const appDataDir = `${APP_DATA_DIR}/${appConfig.id}`;
expect(await fs.promises.readFile(`${appDataDir}/data/subdir/subsubdir/test.txt`, 'utf8')).toBe('test');
expect(await fs.promises.readFile(`${appDataDir}/data/test.txt`, 'utf8')).toBe('test');
});
@ -223,8 +223,8 @@ describe('app helpers', () => {
it('should replace the content of .template files with the content of the app.env file', async () => {
// arrange
const appConfig = createAppConfig({});
const dataDir = `${ROOT_FOLDER}/apps/${appConfig.id}/data`;
const appDataDir = `${STORAGE_FOLDER}/app-data/${appConfig.id}`;
const dataDir = `${DATA_DIR}/apps/${appConfig.id}/data`;
const appDataDir = `${APP_DATA_DIR}/${appConfig.id}`;
await fs.promises.mkdir(dataDir, { recursive: true });
await fs.promises.mkdir(appDataDir, { recursive: true });

View File

@ -1,7 +1,7 @@
import { faker } from '@faker-js/faker';
import fs from 'fs';
import { APP_CATEGORIES, AppInfo, appInfoSchema } from '@runtipi/shared';
import { ROOT_FOLDER, STORAGE_FOLDER } from '@/config/constants';
import { DATA_DIR, APP_DATA_DIR } from '@/config/constants';
export const createAppConfig = (props?: Partial<AppInfo>, isInstalled = true) => {
const appInfo = appInfoSchema.parse({
@ -19,16 +19,16 @@ export const createAppConfig = (props?: Partial<AppInfo>, isInstalled = true) =>
});
const mockFiles: Record<string, string | string[]> = {};
mockFiles[`${ROOT_FOLDER}/.env`] = 'TEST=test';
mockFiles[`${ROOT_FOLDER}/repos/repo-id/apps/${appInfo.id}/config.json`] = JSON.stringify(appInfoSchema.parse(appInfo));
mockFiles[`${ROOT_FOLDER}/repos/repo-id/apps/${appInfo.id}/docker-compose.yml`] = 'compose';
mockFiles[`${ROOT_FOLDER}/repos/repo-id/apps/${appInfo.id}/metadata/description.md`] = 'md desc';
mockFiles[`${DATA_DIR}/.env`] = 'TEST=test';
mockFiles[`${DATA_DIR}/repos/repo-id/apps/${appInfo.id}/config.json`] = JSON.stringify(appInfoSchema.parse(appInfo));
mockFiles[`${DATA_DIR}/repos/repo-id/apps/${appInfo.id}/docker-compose.yml`] = 'compose';
mockFiles[`${DATA_DIR}/repos/repo-id/apps/${appInfo.id}/metadata/description.md`] = 'md desc';
if (isInstalled) {
mockFiles[`${ROOT_FOLDER}/apps/${appInfo.id}/config.json`] = JSON.stringify(appInfoSchema.parse(appInfo));
mockFiles[`${ROOT_FOLDER}/apps/${appInfo.id}/docker-compose.yml`] = 'compose';
mockFiles[`${ROOT_FOLDER}/apps/${appInfo.id}/metadata/description.md`] = 'md desc';
mockFiles[`${STORAGE_FOLDER}/app-data/${appInfo.id}/data/test.txt`] = 'data';
mockFiles[`${DATA_DIR}/apps/${appInfo.id}/config.json`] = JSON.stringify(appInfoSchema.parse(appInfo));
mockFiles[`${DATA_DIR}/apps/${appInfo.id}/docker-compose.yml`] = 'compose';
mockFiles[`${DATA_DIR}/apps/${appInfo.id}/metadata/description.md`] = 'md desc';
mockFiles[`${APP_DATA_DIR}/app-data/${appInfo.id}/data/test.txt`] = 'data';
}
// @ts-expect-error - custom mock method

View File

@ -1,7 +1,7 @@
import fs from 'fs';
import path from 'path';
import { vi, beforeEach } from 'vitest';
import { ROOT_FOLDER } from '@/config/constants';
import { DATA_DIR } from '@/config/constants';
vi.mock('@runtipi/shared/node', async (importOriginal) => {
const mod = (await importOriginal()) as object;
@ -33,7 +33,7 @@ beforeEach(async () => {
// @ts-expect-error - custom mock method
fs.__resetAllMocks();
await fs.promises.mkdir(path.join(ROOT_FOLDER, 'state'), { recursive: true });
await fs.promises.writeFile(path.join(ROOT_FOLDER, 'state', 'seed'), 'seed');
await fs.promises.mkdir(path.join(ROOT_FOLDER, 'repos', 'repo-id', 'apps'), { recursive: true });
await fs.promises.mkdir(path.join(DATA_DIR, 'state'), { recursive: true });
await fs.promises.writeFile(path.join(DATA_DIR, 'state', 'seed'), 'seed');
await fs.promises.mkdir(path.join(DATA_DIR, 'repos', 'repo-id', 'apps'), { recursive: true });
});

View File

@ -1,9 +1,8 @@
import { z } from 'zod';
import { envSchema, envStringToMap, settingsSchema } from '@runtipi/shared';
import fs from 'fs-extra';
import nextConfig from 'next/config';
import * as Sentry from '@sentry/nextjs';
import { DATA_DIR } from 'src/config';
import { DATA_DIR } from '../../../config';
import { readJsonFile } from '../../common/fs.helpers';
import { Logger } from '../Logger';
@ -43,8 +42,8 @@ export class TipiConfigClass {
const envMap = envStringToMap(envFile.toString());
const conf = { ...process.env, ...Object.fromEntries(envMap), ...nextConfig().serverRuntimeConfig };
const envConfig: z.input<typeof envSchema> = {
const conf = { ...process.env, ...Object.fromEntries(envMap) } as Record<string, string>;
const envConfig = {
postgresHost: conf.POSTGRES_HOST,
postgresDatabase: conf.POSTGRES_DBNAME,
postgresUsername: conf.POSTGRES_USERNAME,

View File

@ -1,11 +1,11 @@
import { App } from '@/server/db/schema';
import { appInfoSchema } from '@runtipi/shared';
import { pathExists } from '@runtipi/shared/node';
import { DATA_DIR } from '../../../config';
import { fileExists, readdirSync, readFile, readJsonFile } from '../../common/fs.helpers';
import { TipiConfig } from '../../core/TipiConfig';
import { Logger } from '../../core/Logger';
import { notEmpty } from '../../common/typescript.helpers';
import { DATA_DIR } from 'src/config';
/**
* This function checks the requirements for the app with the provided name.

View File

@ -8,10 +8,10 @@ import { Locales, getLocaleFromString } from '@/shared/internationalization/loca
import { generateSessionId, setSession } from '@/server/common/session.helpers';
import { Database } from '@/server/db';
import { tipiCache } from '@/server/core/TipiCache/TipiCache';
import { DATA_DIR } from '../../../config';
import { TipiConfig } from '../../core/TipiConfig';
import { fileExists, unlinkFile } from '../../common/fs.helpers';
import { decrypt, encrypt } from '../../utils/encryption';
import { DATA_DIR } from 'src/config';
type UsernamePasswordInput = {
username: string;

View File

@ -1,10 +1,10 @@
import { promises } from 'fs';
import axios from 'redaxios';
import { tipiCache } from '@/server/core/TipiCache';
import { DATA_DIR } from '../../../config';
import { fileExists } from '../../common/fs.helpers';
import { Logger } from '../../core/Logger';
import { TipiConfig } from '../../core/TipiConfig';
import { DATA_DIR } from 'src/config';
export class SystemServiceClass {
/**

View File

@ -2,9 +2,9 @@ import fs from 'fs-extra';
import { faker } from '@faker-js/faker';
import { eq } from 'drizzle-orm';
import { AppInfo, Architecture, appInfoSchema, APP_CATEGORIES } from '@runtipi/shared';
import { APP_DATA_DIR, DATA_DIR } from '../../config';
import { TestDatabase } from './test-utils';
import { appTable, AppStatus, App, NewApp } from '../db/schema';
import { APP_DATA_DIR, DATA_DIR } from 'src/config';
interface IProps {
installed?: boolean;

View File

@ -5,7 +5,7 @@ pm2 start pnpm --name worker -- --filter @runtipi/worker -r dev
# Wait for http://localhost:5000/healthcheck to return OK
while true; do
if [[ "$(curl -s http://localhost:5000/worker-api/healthcheck)" == "OK" ]]; then
if [ "$(curl -s http://localhost:5000/worker-api/healthcheck)" = "OK" ]; then
break
fi
sleep 1

View File

@ -1,19 +1,19 @@
#!/bin/sh
# Start worker
cd worker/
cd worker/ || exit
pm2 start index.js --ignore-watch="/worker" --name worker -- start
# Wait for http://localhost:5000/healthcheck to return OK with a maximum of 5 retries
while true; do
if [[ "$(curl -s http://localhost:5000/worker-api/healthcheck)" == "OK" ]]; then
if [ "$(curl -s http://localhost:5000/worker-api/healthcheck)" = "OK" ]; then
break
fi
sleep 1
done
# Start apps
cd /dashboard
cd /dashboard || exit
pm2 start npm --ignore-watch="/dashboard" --name dashboard -- run start
# Log apps realtime