6d095d582c
1. Битая карточка прогона больше не считается отсутствующей: readRuns различает файл-нет и файл-есть-но-не-читается через readJsonOrBroken, и на нечитаемой карточке замок ЗАКРЫТ. Раньше порванный run.json молча выпадал из списка — замок открывался ровно в ту ночь, когда кончилось место. 2. samePath у замка сведён к поведению samePlanPath у печати через resolve: полный путь владельца и путь от корня хранилища от сторожа теперь один файл. Замерено: lefthook 2.1.8 подставляет staged_files путём ОТ КОРНЯ хранилища. 3. Потерянная настройка больше не читается как можно: нет disk_free_min_gb — отказ; нет hours_limit — hoursLimitHit падает громко, а checkSelfLimits гасит работника с названной причиной. 4. Дорога к московскому часу правда одна: limits берёт час у budget.moskovskoeVremya, своего Intl там больше нет. 5. Запись про полночь-как-24 переписана по замеру: этот Node отдаёт 00. Подчистку сторожит прямая проверка normalizeMskHour, а не случайная зелень. 6. Отказ по запасу без дня обновления и с бессмысленной датой от невиданного прибора теперь виден как сбой, а не как нормальный ответ: renewalDay плюс поле renews_on_problem. Каждая починка накрыта проверкой, краснеющей при её вырезании. Проверок в четырёх файлах 155, было 108. Полный набор tools: 619 зелёных в 31 файле. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
84 lines
4.1 KiB
JavaScript
84 lines
4.1 KiB
JavaScript
import { describe, it, expect } from 'vitest';
|
|
import { freeGb, diskState } from './disk.mjs';
|
|
|
|
describe('freeGb — замер живьём', () => {
|
|
it('на живой машине отдаёт положительное число', async () => {
|
|
const gb = await freeGb(process.cwd());
|
|
expect(typeof gb).toBe('number');
|
|
expect(gb).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('каталога нет вовсе — не выдумываем число, отдаём null', async () => {
|
|
// 🪤 Ноль почти всегда сбой, а не правда о мире. Ноль здесь означал бы «места нет»,
|
|
// а правда другая: мы не смогли посмотреть.
|
|
expect(await freeGb('Z:\\такого-каталога-нет-никогда')).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('diskState — можно ли работать', () => {
|
|
it('места больше порога — работать можно', () => {
|
|
expect(diskState(50, 5)).toEqual({ ok: true, free_gb: 50, min_gb: 5, reason: null });
|
|
});
|
|
|
|
it('места ровно порог — уже нельзя: порог это черта, а не «можно до неё»', () => {
|
|
const s = diskState(5, 5);
|
|
expect(s.ok).toBe(false);
|
|
expect(s.reason).toMatch(/место/i);
|
|
});
|
|
|
|
it('места меньше порога — нельзя, и причина названа человеку понятно', () => {
|
|
const s = diskState(1.5, 5);
|
|
expect(s.ok).toBe(false);
|
|
expect(s.reason).toContain('1.5');
|
|
expect(s.reason).toContain('5');
|
|
});
|
|
|
|
it('замерить не удалось — считаем, что нельзя, а не «наверное хватит»', () => {
|
|
const s = diskState(null, 5);
|
|
expect(s.ok).toBe(false);
|
|
expect(s.free_gb).toBeNull();
|
|
expect(s.reason).toMatch(/замерить не удалось/i);
|
|
});
|
|
});
|
|
|
|
describe('diskState — ПОРОГА НЕ ДАЛИ (дыра 3)', () => {
|
|
// 🔴 Раньше правило читало «настройку потеряли» как «можно»: `50 <= undefined` — ложь,
|
|
// и место пропускало что угодно. Ни одна проверка этого не ловила: `diskState` во всех
|
|
// проверках звался с порогом-числом, случая «порога нет» не было ни одного.
|
|
// Вырежи ветку про порог в disk.mjs — покраснеет весь этот раздел.
|
|
it('порога нет вовсе — НЕЛЬЗЯ, а не «места полно»', () => {
|
|
const s = diskState(50, undefined);
|
|
expect(s.ok).toBe(false);
|
|
expect(s.min_gb).toBeNull();
|
|
expect(s.reason).toMatch(/порог/i);
|
|
});
|
|
|
|
it('порог пустой (null) — тоже нельзя', () => {
|
|
expect(diskState(50, null).ok).toBe(false);
|
|
});
|
|
|
|
it('порог не число (NaN, строка) — тоже нельзя', () => {
|
|
expect(diskState(50, NaN).ok).toBe(false);
|
|
expect(diskState(50, '5').ok).toBe(false);
|
|
expect(diskState(50, Infinity).ok).toBe(false);
|
|
});
|
|
|
|
it('в отказе названа сама потерянная настройка — владельцу есть куда смотреть', () => {
|
|
expect(diskState(50, undefined).reason).toContain('disk_free_min_gb');
|
|
});
|
|
|
|
it('и замерить не удалось, и порога нет — отказ, и число не выдумано', () => {
|
|
const s = diskState(null, undefined);
|
|
expect(s.ok).toBe(false);
|
|
expect(s.free_gb).toBeNull();
|
|
expect(s.min_gb).toBeNull();
|
|
});
|
|
|
|
it('порог ноль — это настоящий порог, а не «не задан»', () => {
|
|
// 🪤 Ноль легко спутать с «не дали». Здесь он законен: владелец вправе поставить 0,
|
|
// и тогда работает правило «ровно порог — уже нельзя».
|
|
expect(diskState(0, 0).ok).toBe(false);
|
|
expect(diskState(1, 0)).toEqual({ ok: true, free_gb: 1, min_gb: 0, reason: null });
|
|
});
|
|
});
|