отработаны находки ревью кода
Триаж свёл 62 сырые находки девяти проходов к 33 причинам: 3 блокера, 4 «сейчас», 2 развилки. Все закрыты регрессионными тестами. - схема точки сна определяется по самой точке, а не по индексу в исходном массиве: одна пропущенная точка меняла эпизод и сводку местами - доставка сворачивается одной транзакцией: частичное состояние было недетерминированным (восемь прогонов — семь состояний) - граница размера на распакованном теле: 400 КиБ gzip разворачивались в 400 МиБ мимо max_body_mb - столкновение — расхождение канонических форм, а не байтов; WARN с координатами объекта; payload без HTML-экранирования - выравнивание по местной метке: получасовые зоны уводили часовую выгрузку в minute - доставка из одних суточных сводок больше не отвергается целиком - единицы не переписываются молча; счётчик считает сохранённые точки - все выходы Fold логируются, исход пишется на переживающем отмену контексте Четыре развилки вынесены блокерами в беклог.
This commit is contained in:
@@ -179,6 +179,46 @@ func TestIngestRejectsOversizedBody(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Граница обязана стоять на РАСПАКОВАННОМ теле, а не только на сжатом.
|
||||
//
|
||||
// Измерено на прежней версии: 400 КиБ сжатого тела разворачивались в 400 МиБ,
|
||||
// принимались со статусом 200 и выедали гигабайт. При потолке степени сжатия
|
||||
// gzip около 1030:1 и штатных 64 МиБ речь о десятках гигабайт на запрос, а
|
||||
// параллельные складываются. Цена отказа здесь наивысшая в проекте: приём —
|
||||
// единственное место, где поток существует, и доставка, не попавшая в архив,
|
||||
// не попадает в журнал вовсе.
|
||||
func TestIngestRejectsGzipBomb(t *testing.T) {
|
||||
h, st := newAPI(t, nil)
|
||||
|
||||
// Лимит в тесте — 1 МиБ (см. newAPI). Тело валидное, просто очень длинное
|
||||
// и сжимается почти нацело.
|
||||
payload := `{"data":{"metrics":[]},"pad":"` + strings.Repeat(" ", 8<<20) + `"}`
|
||||
|
||||
var buf bytes.Buffer
|
||||
gz := gzip.NewWriter(&buf)
|
||||
if _, err := gz.Write([]byte(payload)); err != nil {
|
||||
t.Fatalf("подготовка gzip: %v", err)
|
||||
}
|
||||
if err := gz.Close(); err != nil {
|
||||
t.Fatalf("подготовка gzip: %v", err)
|
||||
}
|
||||
if buf.Len() >= 1<<20 {
|
||||
t.Fatalf("сжатое тело %d байт — уже больше лимита, тест проверяет не то", buf.Len())
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/v1/ingest", &buf)
|
||||
req.Header.Set("Content-Encoding", "gzip")
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusRequestEntityTooLarge {
|
||||
t.Fatalf("статус = %d, ожидался 413: распакованное тело больше лимита", rec.Code)
|
||||
}
|
||||
if n, _ := st.CountDeliveries(t.Context()); n != 0 { //nolint:errcheck // проверяем только счётчик
|
||||
t.Errorf("доставок = %d, ожидалось 0", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngestChecksTokenWhenConfigured(t *testing.T) {
|
||||
h, _ := newAPI(t, []string{"верный-токен"})
|
||||
|
||||
@@ -236,7 +276,7 @@ func newAPI(t *testing.T, writeTokens []string) (http.Handler, *store.Store) {
|
||||
|
||||
log := slog.New(slog.DiscardHandler)
|
||||
h := httpapi.New(httpapi.Options{
|
||||
Ingest: ingest.New(arch, st, fold.New(arch, st, log), log),
|
||||
Ingest: ingest.New(arch, st, fold.New(arch, st, 0, log), log),
|
||||
Log: log,
|
||||
WriteTokens: writeTokens,
|
||||
MaxBodyMB: 1,
|
||||
|
||||
Reference in New Issue
Block a user