ingest: закрыты мелочи приёма — вырожденное имя, контракт Result, корреляция add
- имя раздачи нормализуется на границе разбора: вырожденное `-` (metainfo.NoName) даёт пустое имя, пробельное схлопывается — сентинел больше не доходит ни до контекста распознавания, ни до source_ref, ни до подсказки вывода имени - контракт «на любом пути ошибки приёма результат нулевой» объявлен в ingest и удерживается структурно; три транспорта перестали обещать идентификатор, которого нет, и коррелируют отказ по request_id - scoped-логгер загрузки ставится до вызова внешнего сервиса в семи командах воркера — записи об отказе qBittorrent и метабаз получили download_id и infohash; граница разбора bencode записана в docs/research
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -24,13 +25,22 @@ type fakeStore struct {
|
||||
upgradeID string // downloadID последнего вызова UpgradeCatchedMagnetToTorrent
|
||||
upgradeBlob []byte // байты, переданные в апгрейд
|
||||
upgradeUp bool // что вернуть из UpgradeCatchedMagnetToTorrent
|
||||
|
||||
lookupErr error // отказ хранилища на дедуп-чеке
|
||||
createErr error // отказ хранилища на заведении загрузки
|
||||
}
|
||||
|
||||
func (f *fakeStore) FindReingestBlockingByInfohash(_ context.Context, _ ...string) (*store.Download, error) {
|
||||
if f.lookupErr != nil {
|
||||
return nil, f.lookupErr
|
||||
}
|
||||
return f.active, nil
|
||||
}
|
||||
|
||||
func (f *fakeStore) CreateDownloadIfNoActive(_ context.Context, d *store.Download, hashes []string, torrentBlob []byte) (*store.Download, error) {
|
||||
if f.createErr != nil {
|
||||
return nil, f.createErr
|
||||
}
|
||||
if f.active != nil {
|
||||
return f.active, nil
|
||||
}
|
||||
@@ -300,3 +310,31 @@ func TestIngestRejectsNonMagnet(t *testing.T) {
|
||||
t.Error("не должно быть записи задачи")
|
||||
}
|
||||
}
|
||||
|
||||
// Контракт приёма: на ЛЮБОМ пути ошибки транспорту возвращается НУЛЕВОЙ Result.
|
||||
// Транспорты на это опираются и не обещают идентификатора, которого нет
|
||||
// (см. ingest-спеку, «Результат приёма при ошибке пуст»). Сравниваем результат
|
||||
// с нулевым значением ЦЕЛИКОМ, а не по полю DownloadID: следующая ветвь отказа
|
||||
// может заполнить другое поле.
|
||||
func TestIngestReturnsZeroResultOnEveryErrorPath(t *testing.T) {
|
||||
boom := errors.New("boom")
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
fs *fakeStore
|
||||
req Request
|
||||
}{
|
||||
{"невалидный источник", &fakeStore{}, Request{Source: "не magnet и не torrent"}},
|
||||
{"сбой хранилища на дедуп-чеке", &fakeStore{lookupErr: boom}, Request{Source: sampleMagnet}},
|
||||
{"сбой хранилища на заведении", &fakeStore{createErr: boom}, Request{Source: sampleMagnet}},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
res, err := newService(tc.fs).Ingest(context.Background(), tc.req)
|
||||
if err == nil {
|
||||
t.Fatal("ожидалась ошибка")
|
||||
}
|
||||
if !reflect.DeepEqual(res, Result{}) {
|
||||
t.Errorf("Result = %+v, want нулевой", res)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user