test(generate): add unit tests for service and timer generation
- Introduces tests to validate service and timer unit generation - Covers description, dependencies, environment variables, and logging - Ensures generated units meet expected configurations
This commit is contained in:
55
src/templates/__tests__/generate.test.ts
Normal file
55
src/templates/__tests__/generate.test.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
assertStringIncludes,
|
||||||
|
} from 'https://deno.land/std@0.224.0/assert/mod.ts';
|
||||||
|
import { TimerOptions } from '../../types/mod.ts';
|
||||||
|
import { generateUnits } from '../unit-generator.ts';
|
||||||
|
|
||||||
|
Deno.test('generateUnits erzeugt Basis-Service und Timer korrekt', () => {
|
||||||
|
const opts: TimerOptions = {
|
||||||
|
exec: '/usr/bin/my-script',
|
||||||
|
calendar: 'daily',
|
||||||
|
};
|
||||||
|
const { serviceUnit, timerUnit } = generateUnits('myjob', opts);
|
||||||
|
|
||||||
|
assertStringIncludes(serviceUnit, 'ExecStart=/usr/bin/my-script');
|
||||||
|
assertStringIncludes(timerUnit, 'OnCalendar=daily');
|
||||||
|
assertStringIncludes(timerUnit, '[Install]');
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test('generateUnits setzt Beschreibung aus Option', () => {
|
||||||
|
const opts: TimerOptions = {
|
||||||
|
exec: '/bin/true',
|
||||||
|
calendar: 'daily',
|
||||||
|
description: 'Meine Unit',
|
||||||
|
};
|
||||||
|
const { serviceUnit } = generateUnits('job', opts);
|
||||||
|
|
||||||
|
assertStringIncludes(serviceUnit, 'Description=Meine Unit');
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test('generateUnits berücksichtigt after=', () => {
|
||||||
|
const opts: TimerOptions = {
|
||||||
|
exec: '/bin/true',
|
||||||
|
calendar: 'daily',
|
||||||
|
after: ['network-online.target', 'docker.service'],
|
||||||
|
};
|
||||||
|
const { serviceUnit } = generateUnits('job', opts);
|
||||||
|
|
||||||
|
assertStringIncludes(serviceUnit, 'After=network-online.target');
|
||||||
|
assertStringIncludes(serviceUnit, 'After=docker.service');
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test('generateUnits berücksichtigt environment und logfile', () => {
|
||||||
|
const opts: TimerOptions = {
|
||||||
|
exec: '/bin/true',
|
||||||
|
calendar: 'daily',
|
||||||
|
environment: ['FOO=bar', 'DEBUG=1'],
|
||||||
|
logfile: '/var/log/job.log',
|
||||||
|
};
|
||||||
|
const { serviceUnit } = generateUnits('job', opts);
|
||||||
|
|
||||||
|
assertStringIncludes(serviceUnit, 'Environment=FOO=bar');
|
||||||
|
assertStringIncludes(serviceUnit, 'Environment=DEBUG=1');
|
||||||
|
assertStringIncludes(serviceUnit, 'StandardOutput=append:/var/log/job.log');
|
||||||
|
assertStringIncludes(serviceUnit, 'StandardError=append:/var/log/job.log');
|
||||||
|
});
|
63
src/templates/unit-generator.ts
Normal file
63
src/templates/unit-generator.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { TimerOptions } from '../types/mod.ts';
|
||||||
|
import { deriveNameFromExec, writeUnitFiles } from '../utils/mod.ts';
|
||||||
|
|
||||||
|
export async function generateUnitFiles(options: TimerOptions): Promise<void> {
|
||||||
|
const name = options.name || deriveNameFromExec(options.exec);
|
||||||
|
|
||||||
|
const { serviceUnit, timerUnit } = generateUnits(name, options);
|
||||||
|
|
||||||
|
if (options.dryRun) {
|
||||||
|
console.log(`===== ${name}.service =====`);
|
||||||
|
console.log(serviceUnit);
|
||||||
|
console.log(`\n===== ${name}.timer =====`);
|
||||||
|
console.log(timerUnit);
|
||||||
|
} else {
|
||||||
|
const { servicePath, timerPath } = await writeUnitFiles(
|
||||||
|
name,
|
||||||
|
serviceUnit,
|
||||||
|
timerUnit,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
console.log(`Service unit written to: ${servicePath}`);
|
||||||
|
console.log(`Timer unit written to: ${timerPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateUnits(name: string, options: TimerOptions): {
|
||||||
|
serviceUnit: string;
|
||||||
|
timerUnit: string;
|
||||||
|
} {
|
||||||
|
const unitParts = [
|
||||||
|
`[Unit]`,
|
||||||
|
`Description=${options.description ?? name}`,
|
||||||
|
...(options.after?.map((a) => `After=${a}`) ?? []),
|
||||||
|
``,
|
||||||
|
`[Service]`,
|
||||||
|
`Type=oneshot`,
|
||||||
|
`ExecStart=${options.exec}`,
|
||||||
|
...(options.environment?.map((e) => `Environment=${e}`) ?? []),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (options.logfile) {
|
||||||
|
unitParts.push(`StandardOutput=append:${options.logfile}`);
|
||||||
|
unitParts.push(`StandardError=append:${options.logfile}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceUnit = unitParts.join('\n');
|
||||||
|
|
||||||
|
const timerParts = [
|
||||||
|
`[Unit]`,
|
||||||
|
`Description=Timer for ${name}`,
|
||||||
|
``,
|
||||||
|
`[Timer]`,
|
||||||
|
`OnCalendar=${options.calendar}`,
|
||||||
|
`Persistent=true`,
|
||||||
|
``,
|
||||||
|
`[Install]`,
|
||||||
|
`WantedBy=timers.target`,
|
||||||
|
];
|
||||||
|
|
||||||
|
const timerUnit = timerParts.join('\n');
|
||||||
|
|
||||||
|
return { serviceUnit, timerUnit };
|
||||||
|
}
|
Reference in New Issue
Block a user