Zeitplan in der Oberflaeche einstellbar
Takt und Schalter der beiden Abgleiche standen in der Umgebung und liessen sich nur mit einem Neustart aendern. Jetzt stehen sie unter Verwaltung -> Zeitplan, je Lauf einzeln: ob er automatisch laeuft, in welchem Abstand, beim Kaeufe-Abgleich zusaetzlich der seltenere Takt fuer ruhende Konten und ab wann ein Konto als ruhend gilt, beim Forumslauf die Stunde, vor der nicht gelaufen wird. Die Abstaende stehen in Minuten - damit laesst sich alles ausdruecken -, und daneben steht, was das in Stunden bedeutet, damit niemand im Kopf rechnet. Unter einer Viertelstunde geht nicht: beide Abgleiche greifen auf Server zu, die der Community gehoeren. Aenderungen greifen sofort, ohne Neustart. Die Vorgaben sind die bisherigen Werte, sie stehen in der Migration. SCHEDULE_ENABLED und FORUM_SCAN_HOUR entfallen damit.
This commit is contained in:
@@ -21,7 +21,6 @@ before(async () => {
|
||||
process.env.DATABASE_URL = database.url;
|
||||
process.env.SESSION_SECRET = 'test-secret-that-is-long-enough-000000';
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.SCHEDULE_ENABLED = 'false';
|
||||
|
||||
db = await import('../src/db.js');
|
||||
backup = await import('../src/services/backup.js');
|
||||
|
||||
@@ -17,7 +17,6 @@ before(async () => {
|
||||
process.env.DATABASE_URL = database.url;
|
||||
process.env.SESSION_SECRET = 'test-secret-that-is-long-enough-000000';
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.SCHEDULE_ENABLED = 'false';
|
||||
|
||||
db = await import('../src/db.js');
|
||||
characters = await import('../src/services/characters.js');
|
||||
|
||||
@@ -21,8 +21,6 @@ before(async () => {
|
||||
process.env.DATABASE_URL = database.url;
|
||||
process.env.SESSION_SECRET = 'test-secret-that-is-long-enough-000000';
|
||||
process.env.NODE_ENV = 'test';
|
||||
// Der Zeitplan selbst darf im Test nicht anlaufen, nur seine Logik zählt.
|
||||
process.env.SCHEDULE_ENABLED = 'false';
|
||||
|
||||
db = await import('../src/db.js');
|
||||
schedule = await import('../src/services/schedule.js');
|
||||
@@ -139,37 +137,110 @@ describe('Wer wann auf neue Pakete geprüft wird', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Der nächtliche Forumslauf', () => {
|
||||
const nacht = 4;
|
||||
describe('Wann ein Lauf ansteht', () => {
|
||||
const taeglichNachts = { intervalMinutes: 1440, onlyAfterHour: 4 };
|
||||
const allezweiStunden = { intervalMinutes: 120, onlyAfterHour: null };
|
||||
|
||||
it('läuft nicht, bevor die Stunde erreicht ist', () => {
|
||||
const frueh = new Date('2026-09-21T02:30:00');
|
||||
assert.equal(schedule.forumLaufFaellig(null, frueh, nacht), false);
|
||||
it('wartet den eingestellten Abstand ab', () => {
|
||||
const jetzt = new Date('2026-09-21T12:00:00');
|
||||
const vorEinerStunde = new Date('2026-09-21T11:00:00');
|
||||
const vorDreiStunden = new Date('2026-09-21T09:00:00');
|
||||
|
||||
assert.equal(schedule.istFaellig(vorEinerStunde, jetzt, allezweiStunden), false);
|
||||
assert.equal(schedule.istFaellig(vorDreiStunden, jetzt, allezweiStunden), true);
|
||||
});
|
||||
|
||||
it('läuft, sobald die Stunde erreicht ist und heute noch nichts lief', () => {
|
||||
const morgens = new Date('2026-09-21T04:10:00');
|
||||
const gestern = new Date('2026-09-20T04:05:00');
|
||||
assert.equal(schedule.forumLaufFaellig(gestern, morgens, nacht), true);
|
||||
it('läuft beim ersten Mal sofort', () => {
|
||||
assert.equal(schedule.istFaellig(null, new Date('2026-09-21T12:00:00'), allezweiStunden), true);
|
||||
});
|
||||
|
||||
it('hält sich beim Forum an die Stunde', () => {
|
||||
const frueh = new Date('2026-09-21T02:30:00');
|
||||
assert.equal(schedule.istFaellig(null, frueh, taeglichNachts), false, 'vor vier Uhr nicht');
|
||||
|
||||
const nachVier = new Date('2026-09-21T04:10:00');
|
||||
assert.equal(schedule.istFaellig(null, nachVier, taeglichNachts), true);
|
||||
});
|
||||
|
||||
it('läuft an einem Tag nur einmal', () => {
|
||||
const morgens = new Date('2026-09-21T04:10:00');
|
||||
const abends = new Date('2026-09-21T22:00:00');
|
||||
assert.equal(schedule.forumLaufFaellig(morgens, abends, nacht), false);
|
||||
assert.equal(schedule.istFaellig(morgens, abends, taeglichNachts), false);
|
||||
});
|
||||
|
||||
it('holt einen ausgefallenen Lauf am selben Tag nach', () => {
|
||||
// Der Dienst stand nachts still und kommt erst mittags hoch.
|
||||
const mittags = new Date('2026-09-21T12:00:00');
|
||||
const vorgestern = new Date('2026-09-19T04:00:00');
|
||||
assert.equal(schedule.forumLaufFaellig(vorgestern, mittags, nacht), true);
|
||||
assert.equal(schedule.istFaellig(vorgestern, mittags, taeglichNachts), true);
|
||||
});
|
||||
|
||||
it('stößt nach einem Neustart nicht erneut an', () => {
|
||||
it('stösst nach einem Neustart nicht erneut an', () => {
|
||||
const nachStart = new Date('2026-09-21T06:00:00');
|
||||
const heuteFrueh = new Date('2026-09-21T04:02:00');
|
||||
assert.equal(schedule.forumLaufFaellig(heuteFrueh, nachStart, nacht), false);
|
||||
assert.equal(schedule.istFaellig(heuteFrueh, nachStart, taeglichNachts), false);
|
||||
});
|
||||
|
||||
it('ignoriert die Stunde, wenn der Takt kürzer als ein Tag ist', () => {
|
||||
// Ein sechsstündlicher Lauf ab acht Uhr soll auch um vierzehn Uhr laufen.
|
||||
const regel = { intervalMinutes: 360, onlyAfterHour: 8 };
|
||||
const mittags = new Date('2026-09-21T14:00:00');
|
||||
const morgens = new Date('2026-09-21T08:00:00');
|
||||
assert.equal(schedule.istFaellig(morgens, mittags, regel), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Einstellungen des Zeitplans', () => {
|
||||
it('liefert Vorgaben, solange nichts eingestellt wurde', async () => {
|
||||
const kaeufe = await schedule.getSetting('gextension');
|
||||
assert.equal(kaeufe.intervalMinutes, 120);
|
||||
assert.equal(kaeufe.idleIntervalMinutes, 360);
|
||||
assert.equal(kaeufe.idleAfterDays, 1095);
|
||||
|
||||
const forum = await schedule.getSetting('forum');
|
||||
assert.equal(forum.intervalMinutes, 1440);
|
||||
assert.equal(forum.onlyAfterHour, 4);
|
||||
});
|
||||
|
||||
it('nimmt eine Änderung an und wendet sie sofort an', async () => {
|
||||
const ctx = { actorId: null, actorName: 'Test' };
|
||||
await schedule.updateSetting('gextension', { intervalMinutes: 45, enabled: false }, ctx);
|
||||
|
||||
const danach = await schedule.getSetting('gextension');
|
||||
assert.equal(danach.intervalMinutes, 45);
|
||||
assert.equal(danach.enabled, false);
|
||||
assert.equal(danach.idleIntervalMinutes, 360, 'unberührte Felder bleiben');
|
||||
|
||||
await schedule.updateSetting('gextension', { intervalMinutes: 120, enabled: true }, ctx);
|
||||
});
|
||||
|
||||
it('weist unsinnige Abstände ab', async () => {
|
||||
const ctx = { actorId: null, actorName: 'Test' };
|
||||
|
||||
for (const minuten of [0, 5, 20000]) {
|
||||
await assert.rejects(
|
||||
() => schedule.updateSetting('forum', { intervalMinutes: minuten }, ctx),
|
||||
(error: Error & { code?: string }) => error.code === 'INVALID_INTERVAL',
|
||||
`${minuten} Minuten hätten abgewiesen werden müssen`,
|
||||
);
|
||||
}
|
||||
|
||||
await assert.rejects(
|
||||
() => schedule.updateSetting('forum', { onlyAfterHour: 25 }, ctx),
|
||||
(error: Error & { code?: string }) => error.code === 'INVALID_HOUR',
|
||||
);
|
||||
});
|
||||
|
||||
it('richtet sich beim Fälligsein nach der Einstellung', async () => {
|
||||
const ctx = { actorId: null, actorName: 'Test' };
|
||||
await schedule.updateSetting('gextension', { intervalMinutes: 30 }, ctx);
|
||||
|
||||
const regel = await schedule.getSetting('gextension');
|
||||
const jetzt = new Date('2026-09-21T12:00:00');
|
||||
assert.equal(schedule.istFaellig(new Date('2026-09-21T11:45:00'), jetzt, regel), false);
|
||||
assert.equal(schedule.istFaellig(new Date('2026-09-21T11:15:00'), jetzt, regel), true);
|
||||
|
||||
await schedule.updateSetting('gextension', { intervalMinutes: 120 }, ctx);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user