mirror of
https://github.com/immich-app/immich.git
synced 2025-01-01 08:31:59 +00:00
267 lines
7.6 KiB
TypeScript
267 lines
7.6 KiB
TypeScript
import { ImmichTelemetry } from 'src/enum';
|
|
import { clearEnvCache, ConfigRepository } from 'src/repositories/config.repository';
|
|
|
|
const getEnv = () => {
|
|
clearEnvCache();
|
|
return new ConfigRepository().getEnv();
|
|
};
|
|
|
|
const resetEnv = () => {
|
|
for (const env of [
|
|
'IMMICH_ENV',
|
|
'IMMICH_WORKERS_INCLUDE',
|
|
'IMMICH_WORKERS_EXCLUDE',
|
|
'IMMICH_TRUSTED_PROXIES',
|
|
'IMMICH_API_METRICS_PORT',
|
|
'IMMICH_MICROSERVICES_METRICS_PORT',
|
|
'IMMICH_TELEMETRY_INCLUDE',
|
|
'IMMICH_TELEMETRY_EXCLUDE',
|
|
|
|
'DB_URL',
|
|
'DB_HOSTNAME',
|
|
'DB_PORT',
|
|
'DB_USERNAME',
|
|
'DB_PASSWORD',
|
|
'DB_DATABASE_NAME',
|
|
'DB_SKIP_MIGRATIONS',
|
|
'DB_VECTOR_EXTENSION',
|
|
|
|
'REDIS_HOSTNAME',
|
|
'REDIS_PORT',
|
|
'REDIS_DBINDEX',
|
|
'REDIS_USERNAME',
|
|
'REDIS_PASSWORD',
|
|
'REDIS_SOCKET',
|
|
'REDIS_URL',
|
|
|
|
'NO_COLOR',
|
|
]) {
|
|
delete process.env[env];
|
|
}
|
|
};
|
|
|
|
const sentinelConfig = {
|
|
sentinels: [
|
|
{
|
|
host: 'redis-sentinel-node-0',
|
|
port: 26_379,
|
|
},
|
|
{
|
|
host: 'redis-sentinel-node-1',
|
|
port: 26_379,
|
|
},
|
|
{
|
|
host: 'redis-sentinel-node-2',
|
|
port: 26_379,
|
|
},
|
|
],
|
|
name: 'redis-sentinel',
|
|
};
|
|
|
|
describe('getEnv', () => {
|
|
beforeEach(() => {
|
|
resetEnv();
|
|
});
|
|
|
|
it('should use defaults', () => {
|
|
const config = getEnv();
|
|
|
|
expect(config).toMatchObject({
|
|
host: undefined,
|
|
port: 2283,
|
|
environment: 'production',
|
|
configFile: undefined,
|
|
logLevel: undefined,
|
|
});
|
|
});
|
|
|
|
describe('database', () => {
|
|
it('should use defaults', () => {
|
|
const { database } = getEnv();
|
|
expect(database).toEqual({
|
|
config: expect.objectContaining({
|
|
type: 'postgres',
|
|
host: 'database',
|
|
port: 5432,
|
|
database: 'immich',
|
|
username: 'postgres',
|
|
password: 'postgres',
|
|
}),
|
|
skipMigrations: false,
|
|
vectorExtension: 'vectors',
|
|
});
|
|
});
|
|
|
|
it('should allow skipping migrations', () => {
|
|
process.env.DB_SKIP_MIGRATIONS = 'true';
|
|
const { database } = getEnv();
|
|
expect(database).toMatchObject({ skipMigrations: true });
|
|
});
|
|
});
|
|
|
|
describe('redis', () => {
|
|
it('should use defaults', () => {
|
|
const { redis } = getEnv();
|
|
expect(redis).toEqual({
|
|
host: 'redis',
|
|
port: 6379,
|
|
db: 0,
|
|
username: undefined,
|
|
password: undefined,
|
|
path: undefined,
|
|
});
|
|
});
|
|
|
|
it('should parse base64 encoded config, ignore other env', () => {
|
|
process.env.REDIS_URL = `ioredis://${Buffer.from(JSON.stringify(sentinelConfig)).toString('base64')}`;
|
|
process.env.REDIS_HOSTNAME = 'redis-host';
|
|
process.env.REDIS_USERNAME = 'redis-user';
|
|
process.env.REDIS_PASSWORD = 'redis-password';
|
|
const { redis } = getEnv();
|
|
expect(redis).toEqual(sentinelConfig);
|
|
});
|
|
|
|
it('should reject invalid json', () => {
|
|
process.env.REDIS_URL = `ioredis://${Buffer.from('{ "invalid json"').toString('base64')}`;
|
|
expect(() => getEnv()).toThrowError('Failed to decode redis options');
|
|
});
|
|
});
|
|
|
|
describe('noColor', () => {
|
|
beforeEach(() => {
|
|
delete process.env.NO_COLOR;
|
|
});
|
|
|
|
it('should default noColor to false', () => {
|
|
const { noColor } = getEnv();
|
|
expect(noColor).toBe(false);
|
|
});
|
|
|
|
it('should map NO_COLOR=1 to true', () => {
|
|
process.env.NO_COLOR = '1';
|
|
const { noColor } = getEnv();
|
|
expect(noColor).toBe(true);
|
|
});
|
|
|
|
it('should map NO_COLOR=true to true', () => {
|
|
process.env.NO_COLOR = 'true';
|
|
const { noColor } = getEnv();
|
|
expect(noColor).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('workers', () => {
|
|
it('should return default workers', () => {
|
|
const { workers } = getEnv();
|
|
expect(workers).toEqual(['api', 'microservices']);
|
|
});
|
|
|
|
it('should return included workers', () => {
|
|
process.env.IMMICH_WORKERS_INCLUDE = 'api';
|
|
const { workers } = getEnv();
|
|
expect(workers).toEqual(['api']);
|
|
});
|
|
|
|
it('should excluded workers from defaults', () => {
|
|
process.env.IMMICH_WORKERS_EXCLUDE = 'api';
|
|
const { workers } = getEnv();
|
|
expect(workers).toEqual(['microservices']);
|
|
});
|
|
|
|
it('should exclude workers from include list', () => {
|
|
process.env.IMMICH_WORKERS_INCLUDE = 'api,microservices,randomservice';
|
|
process.env.IMMICH_WORKERS_EXCLUDE = 'randomservice,microservices';
|
|
const { workers } = getEnv();
|
|
expect(workers).toEqual(['api']);
|
|
});
|
|
|
|
it('should remove whitespace from included workers before parsing', () => {
|
|
process.env.IMMICH_WORKERS_INCLUDE = 'api, microservices';
|
|
const { workers } = getEnv();
|
|
expect(workers).toEqual(['api', 'microservices']);
|
|
});
|
|
|
|
it('should remove whitespace from excluded workers before parsing', () => {
|
|
process.env.IMMICH_WORKERS_EXCLUDE = 'api, microservices';
|
|
const { workers } = getEnv();
|
|
expect(workers).toEqual([]);
|
|
});
|
|
|
|
it('should remove whitespace from included and excluded workers before parsing', () => {
|
|
process.env.IMMICH_WORKERS_INCLUDE = 'api, microservices, randomservice,randomservice2';
|
|
process.env.IMMICH_WORKERS_EXCLUDE = 'randomservice,microservices, randomservice2';
|
|
const { workers } = getEnv();
|
|
expect(workers).toEqual(['api']);
|
|
});
|
|
|
|
it('should throw error for invalid workers', () => {
|
|
process.env.IMMICH_WORKERS_INCLUDE = 'api,microservices,randomservice';
|
|
expect(getEnv).toThrowError('Invalid worker(s) found: api,microservices,randomservice');
|
|
});
|
|
});
|
|
|
|
describe('network', () => {
|
|
it('should return default network options', () => {
|
|
const { network } = getEnv();
|
|
expect(network).toEqual({
|
|
trustedProxies: [],
|
|
});
|
|
});
|
|
|
|
it('should parse trusted proxies', () => {
|
|
process.env.IMMICH_TRUSTED_PROXIES = '10.1.0.0,10.2.0.0, 169.254.0.0/16';
|
|
const { network } = getEnv();
|
|
expect(network).toEqual({
|
|
trustedProxies: ['10.1.0.0', '10.2.0.0', '169.254.0.0/16'],
|
|
});
|
|
});
|
|
|
|
it('should reject invalid trusted proxies', () => {
|
|
process.env.IMMICH_TRUSTED_PROXIES = '10.1';
|
|
expect(() => getEnv()).toThrowError('Invalid environment variables: IMMICH_TRUSTED_PROXIES');
|
|
});
|
|
});
|
|
|
|
describe('telemetry', () => {
|
|
it('should have default values', () => {
|
|
const { telemetry } = getEnv();
|
|
expect(telemetry).toEqual({
|
|
apiPort: 8081,
|
|
microservicesPort: 8082,
|
|
metrics: new Set([]),
|
|
});
|
|
});
|
|
|
|
it('should parse custom ports', () => {
|
|
process.env.IMMICH_API_METRICS_PORT = '2001';
|
|
process.env.IMMICH_MICROSERVICES_METRICS_PORT = '2002';
|
|
const { telemetry } = getEnv();
|
|
expect(telemetry).toMatchObject({
|
|
apiPort: 2001,
|
|
microservicesPort: 2002,
|
|
metrics: expect.any(Set),
|
|
});
|
|
});
|
|
|
|
it('should run with telemetry enabled', () => {
|
|
process.env.IMMICH_TELEMETRY_INCLUDE = 'all';
|
|
const { telemetry } = getEnv();
|
|
expect(telemetry.metrics).toEqual(new Set(Object.values(ImmichTelemetry)));
|
|
});
|
|
|
|
it('should run with telemetry enabled and jobs disabled', () => {
|
|
process.env.IMMICH_TELEMETRY_INCLUDE = 'all';
|
|
process.env.IMMICH_TELEMETRY_EXCLUDE = 'job';
|
|
const { telemetry } = getEnv();
|
|
expect(telemetry.metrics).toEqual(
|
|
new Set([ImmichTelemetry.API, ImmichTelemetry.HOST, ImmichTelemetry.IO, ImmichTelemetry.REPO]),
|
|
);
|
|
});
|
|
|
|
it('should run with specific telemetry metrics', () => {
|
|
process.env.IMMICH_TELEMETRY_INCLUDE = 'io, host, api';
|
|
const { telemetry } = getEnv();
|
|
expect(telemetry.metrics).toEqual(new Set([ImmichTelemetry.API, ImmichTelemetry.HOST, ImmichTelemetry.IO]));
|
|
});
|
|
});
|
|
});
|