package tgbot import ( "context" "net/http" "net/http/httptest" "strings" "testing" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) func docMsg(userID int64, doc *tgbotapi.Document, caption string) *tgbotapi.Message { return &tgbotapi.Message{ MessageID: 1, From: &tgbotapi.User{ID: userID}, Chat: &tgbotapi.Chat{ID: userID}, Document: doc, Caption: caption, } } // .torrent-документ: скачиваем байты и подаём в приём (подпись — контекстом). func TestBot_IngestFromDocument(t *testing.T) { torrentBytes := []byte("d8:announce…bytes") fileSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write(torrentBytes) })) defer fileSrv.Close() b, api, ing, _ := newTestBot(t, []int64{7}) api.fileURL = fileSrv.URL + "/file.torrent" doc := &tgbotapi.Document{FileID: "abc", FileName: "dune.torrent", MimeType: "application/x-bittorrent"} b.handleMessage(context.Background(), docMsg(7, doc, "Дюна 2")) if string(ing.lastReq.TorrentData) != string(torrentBytes) { t.Errorf("TorrentData = %q, want %q", ing.lastReq.TorrentData, torrentBytes) } if ing.lastReq.Context != "Дюна 2" { t.Errorf("context (подпись) = %q", ing.lastReq.Context) } if len(api.sent) != 1 || !strings.Contains(api.sent[0].text, "Принято #"+idCode(tid)) { t.Errorf("sent = %+v", api.sent) } } // Документ по расширению .torrent (mime может отсутствовать) тоже принимается. func TestBot_DocumentByExtension(t *testing.T) { fileSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("bytes")) })) defer fileSrv.Close() b, api, ing, _ := newTestBot(t, []int64{7}) api.fileURL = fileSrv.URL doc := &tgbotapi.Document{FileID: "x", FileName: "Release.TORRENT"} // без mime, регистр b.handleMessage(context.Background(), docMsg(7, doc, "")) if len(ing.lastReq.TorrentData) == 0 { t.Error("документ .torrent по расширению не принят") } _ = api } // Ошибка скачивания не должна утекать токен бота (URL файла Telegram содержит // …/bot/…). Транспортная ошибка *url.Error встраивает URL — проверяем, // что logging.SanitizeErr его убрал. func TestBot_DownloadErrorNoTokenLeak(t *testing.T) { b, api, _, _ := newTestBot(t, []int64{7}) // «Токен» в URL, указывающем на закрытый порт → ошибка транспорта. api.fileURL = "http://127.0.0.1:1/file/botSECRET123:AAtoken/x" _, err := b.downloadFile(context.Background(), "fid") if err == nil { t.Fatal("ожидалась ошибка транспорта") } if strings.Contains(err.Error(), "SECRET123") || strings.Contains(err.Error(), "AAtoken") { t.Errorf("токен утёк в текст ошибки: %v", err) } } // Не-.torrent документ → подсказка, приёма нет. func TestBot_NonTorrentDocumentRejected(t *testing.T) { b, api, ing, _ := newTestBot(t, []int64{7}) doc := &tgbotapi.Document{FileID: "x", FileName: "photo.jpg", MimeType: "image/jpeg"} b.handleMessage(context.Background(), docMsg(7, doc, "")) if len(ing.lastReq.TorrentData) != 0 || ing.lastReq.Source != "" { t.Errorf("не-.torrent не должен идти в приём: %+v", ing.lastReq) } if len(api.sent) != 1 || !strings.Contains(api.sent[0].text, "не .torrent") { t.Errorf("нет подсказки об ошибке: %+v", api.sent) } } // Документ приходит ДО ветки pending-подсказки: ожидающая refine-подсказка не // «съедает» документ (у документа m.Text пуст). func TestBot_DocumentBeforePendingHint(t *testing.T) { fileSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("bytes")) })) defer fileSrv.Close() b, api, ing, rev := newTestBot(t, []int64{7}) api.fileURL = fileSrv.URL b.setPending(7, tid) // ждём подсказку для перераспознавания doc := &tgbotapi.Document{FileID: "x", FileName: "a.torrent", MimeType: "application/x-bittorrent"} b.handleMessage(context.Background(), docMsg(7, doc, "")) if len(rev.refined) != 0 { t.Errorf("документ ошибочно принят как refine-подсказка: %v", rev.refined) } if len(ing.lastReq.TorrentData) == 0 { t.Error("документ не принят как .torrent") } }