// Copyright (c) 2021 - 2025, Ludvig Lundgren and the autobrr contributors. // SPDX-License-Identifier: GPL-2.0-or-later //go:build integration package domain import ( "context" "fmt" "net/http" "net/http/httptest" "os" "strings" "testing" "time" "github.com/moistari/rls" "github.com/rs/zerolog" ) var trackerLessTestTorrent = `d7:comment19:This is just a test10:created by12:Johnny Bravo13:creation datei1430648794e8:encoding5:UTF-84:infod6:lengthi1128e4:name12:testfile.bin12:piece lengthi32768e6:pieces20:Õˆë =‘UŒäiÎ^æ °Eâ?ÇÒe5:nodesl35:udp://tracker.openbittorrent.com:8035:udp://tracker.openbittorrent.com:80ee` func TestRelease_DownloadTorrentFile(t *testing.T) { // disable logger zerolog.SetGlobalLevel(zerolog.Disabled) mux := http.NewServeMux() ts := httptest.NewServer(mux) defer ts.Close() mux.HandleFunc("/files/valid_torrent_as_html", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "text/html") payload, _ := os.ReadFile("testdata/archlinux-2011.08.19-netinstall-i686.iso.torrent") w.Write(payload) }) mux.HandleFunc("/files/invalid_torrent_as_html", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "text/html") payload := []byte("This is not the torrent you are looking for") w.Write(payload) }) mux.HandleFunc("/index.html", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "text/html") payload := []byte("This is not the torrent you are looking for") w.Write(payload) }) mux.HandleFunc("/plaintext", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "text/plain") payload := []byte("This is not a valid torrent file.") w.Write(payload) }) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if strings.Contains(r.RequestURI, "401") { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("unauthorized")) return } if strings.Contains(r.RequestURI, "403") { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("forbidden")) return } if strings.Contains(r.RequestURI, "404") { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("not found")) return } if strings.Contains(r.RequestURI, "405") { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("method not allowed")) return } if strings.Contains(r.RequestURI, "file.torrent") { w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/x-bittorrent") payload, _ := os.ReadFile("testdata/archlinux-2011.08.19-netinstall-i686.iso.torrent") w.Write(payload) return } w.WriteHeader(http.StatusInternalServerError) w.Write([]byte("internal error")) }) type fields struct { ID int64 FilterStatus ReleaseFilterStatus Rejections []string Indexer IndexerMinimal FilterName string Protocol ReleaseProtocol Implementation ReleaseImplementation Timestamp time.Time GroupID string TorrentID string DownloadURL string TorrentTmpFile string TorrentDataRawBytes []byte TorrentHash string TorrentName string Size uint64 Title string Category string Categories []string Season int Episode int Year int Resolution string Source string Codec []string Container string HDR []string Audio []string AudioChannels string Group string Region string Language []string Proper bool Repack bool Website string Artists string Type rls.Type LogScore int Origin string Tags []string ReleaseTags string Freeleech bool FreeleechPercent int Bonus []string Uploader string PreTime string Other []string RawCookie string AdditionalSizeCheckRequired bool FilterID int Filter *Filter ActionStatus []ReleaseActionStatus } tests := []struct { name string fields fields wantErr bool }{ { name: "401", fields: fields{ Indexer: IndexerMinimal{ ID: 0, Name: "Mock Indexer", Identifier: "mock-indexer", }, TorrentName: "Test.Release-GROUP", DownloadURL: fmt.Sprintf("%s/%d", ts.URL, 401), Protocol: ReleaseProtocolTorrent, }, wantErr: true, }, { name: "403", fields: fields{ Indexer: IndexerMinimal{ ID: 0, Name: "Mock Indexer", Identifier: "mock-indexer", }, TorrentName: "Test.Release-GROUP", DownloadURL: fmt.Sprintf("%s/%d", ts.URL, 403), Protocol: ReleaseProtocolTorrent, }, wantErr: true, }, { name: "500", fields: fields{ Indexer: IndexerMinimal{ ID: 0, Name: "Mock Indexer", Identifier: "mock-indexer", }, TorrentName: "Test.Release-GROUP", DownloadURL: fmt.Sprintf("%s/%d", ts.URL, 500), Protocol: ReleaseProtocolTorrent, }, wantErr: true, }, { name: "ok", fields: fields{ Indexer: IndexerMinimal{ ID: 0, Name: "Mock Indexer", Identifier: "mock-indexer", }, TorrentName: "Test.Release-GROUP", DownloadURL: fmt.Sprintf("%s/%s", ts.URL, "file.torrent"), Protocol: ReleaseProtocolTorrent, }, wantErr: false, }, { name: "valid_torrent_with_text-html_header", fields: fields{ Indexer: IndexerMinimal{ ID: 0, Name: "Mock Indexer", Identifier: "mock-indexer", }, TorrentName: "Test.Release-GROUP", DownloadURL: fmt.Sprintf("%s/files/%s", ts.URL, "valid_torrent_as_html"), Protocol: ReleaseProtocolTorrent, }, wantErr: false, }, { name: "invalid_torrent_with_text-html_header", fields: fields{ Indexer: IndexerMinimal{ ID: 0, Name: "Mock Indexer", Identifier: "mock-indexer", }, TorrentName: "Test.Release-GROUP", DownloadURL: fmt.Sprintf("%s/files/%s", ts.URL, "invalid_torrent_as_html"), Protocol: ReleaseProtocolTorrent, }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &Release{ ID: tt.fields.ID, FilterStatus: tt.fields.FilterStatus, Rejections: tt.fields.Rejections, Indexer: tt.fields.Indexer, FilterName: tt.fields.FilterName, Protocol: tt.fields.Protocol, Implementation: tt.fields.Implementation, Timestamp: tt.fields.Timestamp, GroupID: tt.fields.GroupID, TorrentID: tt.fields.TorrentID, DownloadURL: tt.fields.DownloadURL, TorrentTmpFile: tt.fields.TorrentTmpFile, TorrentDataRawBytes: tt.fields.TorrentDataRawBytes, TorrentHash: tt.fields.TorrentHash, TorrentName: tt.fields.TorrentName, Size: tt.fields.Size, Title: tt.fields.Title, Category: tt.fields.Category, Categories: tt.fields.Categories, Season: tt.fields.Season, Episode: tt.fields.Episode, Year: tt.fields.Year, Resolution: tt.fields.Resolution, Source: tt.fields.Source, Codec: tt.fields.Codec, Container: tt.fields.Container, HDR: tt.fields.HDR, Audio: tt.fields.Audio, AudioChannels: tt.fields.AudioChannels, Group: tt.fields.Group, Region: tt.fields.Region, Language: tt.fields.Language, Proper: tt.fields.Proper, Repack: tt.fields.Repack, Website: tt.fields.Website, Artists: tt.fields.Artists, Type: tt.fields.Type, LogScore: tt.fields.LogScore, Origin: tt.fields.Origin, Tags: tt.fields.Tags, ReleaseTags: tt.fields.ReleaseTags, Freeleech: tt.fields.Freeleech, FreeleechPercent: tt.fields.FreeleechPercent, Bonus: tt.fields.Bonus, Uploader: tt.fields.Uploader, PreTime: tt.fields.PreTime, Other: tt.fields.Other, RawCookie: tt.fields.RawCookie, AdditionalSizeCheckRequired: tt.fields.AdditionalSizeCheckRequired, FilterID: tt.fields.FilterID, Filter: tt.fields.Filter, ActionStatus: tt.fields.ActionStatus, } err := r.DownloadTorrentFileCtx(context.Background()) if err == nil && tt.wantErr { fmt.Println("error") } }) } }