Files
pn-new-crm/tests/unit/services/backup-destinations-service.test.ts

87 lines
2.8 KiB
TypeScript
Raw Permalink Normal View History

/**
* Unit tests for the pure helpers of the backup-destinations service:
* schedule-due logic + secret config (serialize encrypt at rest
* decrypt for use, mask for API). DB-backed CRUD is covered by the e2e
* verification, not here.
*/
import { describe, expect, it } from 'vitest';
import {
decryptConfig,
isScheduleDue,
maskConfig,
serializeConfig,
} from '@/lib/services/backup-destinations.service';
describe('isScheduleDue', () => {
// 2026-06-07 is a Sunday; 2026-06-08 a Monday.
const sunday = new Date('2026-06-07T02:00:00Z');
const monday = new Date('2026-06-08T02:00:00Z');
it('off is never due', () => {
expect(isScheduleDue('off', sunday)).toBe(false);
expect(isScheduleDue('off', monday)).toBe(false);
});
it('daily is always due', () => {
expect(isScheduleDue('daily', sunday)).toBe(true);
expect(isScheduleDue('daily', monday)).toBe(true);
});
it('weekly is due only on Sunday', () => {
expect(isScheduleDue('weekly', sunday)).toBe(true);
expect(isScheduleDue('weekly', monday)).toBe(false);
});
});
describe('secret config handling', () => {
it('serialize encrypts secrets, decrypt restores them, mask hides them', () => {
const incoming = {
host: 'box.example.com',
username: 'crm',
password: 'hunter2',
remoteDir: '/backups',
};
const stored = serializeConfig('sftp', incoming);
// Stored password must not be the plaintext.
expect(stored.password).not.toBe('hunter2');
expect(stored.host).toBe('box.example.com');
// Decrypt restores the plaintext for transport use.
expect(decryptConfig('sftp', stored)).toMatchObject({
host: 'box.example.com',
username: 'crm',
password: 'hunter2',
remoteDir: '/backups',
});
// Mask hides the secret and exposes only a *IsSet marker.
const masked = maskConfig('sftp', stored);
expect(masked.password).toBeUndefined();
expect(masked.passwordIsSet).toBe(true);
expect(masked.host).toBe('box.example.com');
});
it('update with a blank secret keeps the existing encrypted value', () => {
const original = serializeConfig('s3', {
endpoint: 'https://s3.example.com',
bucket: 'b',
accessKey: 'AK',
secretKey: 'SUPERSECRET',
});
// Admin edits the bucket but leaves the secret key blank (unchanged).
const updated = serializeConfig(
's3',
{ endpoint: 'https://s3.example.com', bucket: 'b2', accessKey: 'AK', secretKey: '' },
original,
);
expect(updated.bucket).toBe('b2');
expect(decryptConfig('s3', updated).secretKey).toBe('SUPERSECRET');
});
it('filesystem has no secrets to mask', () => {
const stored = serializeConfig('filesystem', { directory: '/mnt/nas/backups' });
expect(maskConfig('filesystem', stored)).toEqual({ directory: '/mnt/nas/backups' });
});
});