From e8b6f72ddc66d846475023ebeaf63d40a3b280ec Mon Sep 17 00:00:00 2001 From: tech nasty <262050521+t3chnaztea@users.noreply.github.com> Date: Sun, 12 Jul 2026 21:49:11 -0500 Subject: [PATCH] fix(search): zero configured indexers returned five fake mock releases into the real grab pipeline When no indexers were configured/enabled, SearchIndexersAsync returned GenerateMockIndexerResults: five synthetic releases (fabricated titles, sizes, and magnet/NZB URLs) that flowed into real scoring and the automatic-grab decision and could be handed to a download client. Return an empty result set with a clear warning instead, and remove the now-dead GenerateMockIndexerResults helpers. Nothing in the frontend or tests depended on them. Co-Authored-By: Claude Fable 5 --- .../Indexers/Common/IndexerSearchWorkflow.cs | 61 +------------------ .../Search/IndexerSearchWorkflowTests.cs | 44 +++++++++++++ 2 files changed, 46 insertions(+), 59 deletions(-) create mode 100644 tests/Features/Application/Search/IndexerSearchWorkflowTests.cs diff --git a/listenarr.application/Search/Indexers/Common/IndexerSearchWorkflow.cs b/listenarr.application/Search/Indexers/Common/IndexerSearchWorkflow.cs index 85e789977..9d1b4e14b 100644 --- a/listenarr.application/Search/Indexers/Common/IndexerSearchWorkflow.cs +++ b/listenarr.application/Search/Indexers/Common/IndexerSearchWorkflow.cs @@ -63,8 +63,8 @@ public async Task> SearchIndexersAsync( if (!indexers.Any()) { - _logger.LogWarning("No indexers configured, returning mock results for query: {Query}", query); - return GenerateMockIndexerResults(query); + _logger.LogWarning("No indexers configured or enabled; search returned no results for query: {Query}", query); + return results; } var searchTasks = indexers.Select(async indexer => @@ -254,61 +254,4 @@ private static string GetFallbackIndexerName(Indexer indexer) return "Indexer"; } } - - private List GenerateMockIndexerResults(string query) - { - return GenerateMockIndexerResults(query, "Mock Indexer", "Torrent"); - } - - private List GenerateMockIndexerResults(string query, string indexerName, string indexerType) - { - var random = new Random(); - var results = new List(); - var isUsenet = indexerType.Equals("Usenet", StringComparison.OrdinalIgnoreCase); - - _logger.LogInformation("Generating {Count} mock {Type} results for indexer {IndexerName}", 5, indexerType, indexerName); - - for (int i = 0; i < 5; i++) - { - var result = new IndexerSearchResult - { - Id = Guid.NewGuid().ToString(), - Title = $"{query} - Quality {i + 1}", - Artist = "Various Authors", - Album = $"{query} Series", - Category = "Audiobook", - Size = random.Next(200_000_000, 1_500_000_000), - Seeders = isUsenet ? 0 : random.Next(5, 100), - Leechers = isUsenet ? 0 : random.Next(0, 20), - Source = indexerName, - PublishedDate = DateTime.UtcNow.AddDays(-random.Next(1, 365)).ToString("o"), - Quality = i switch - { - 0 => "MP3 64kbps", - 1 => "MP3 128kbps", - 2 => "MP3 192kbps", - 3 => "M4B 128kbps", - _ => "FLAC" - }, - Format = i >= 3 ? "M4B" : "MP3", - Language = "English" - }; - - if (isUsenet) - { - result.NzbUrl = $"https://{indexerName.ToLowerInvariant()}.example.com/api/nzb/{Guid.NewGuid():N}"; - result.MagnetLink = string.Empty; - result.TorrentUrl = string.Empty; - } - else - { - result.MagnetLink = $"magnet:?xt=urn:btih:{Guid.NewGuid():N}"; - result.NzbUrl = string.Empty; - } - - results.Add(result); - } - - return results; - } } diff --git a/tests/Features/Application/Search/IndexerSearchWorkflowTests.cs b/tests/Features/Application/Search/IndexerSearchWorkflowTests.cs new file mode 100644 index 000000000..5160540c4 --- /dev/null +++ b/tests/Features/Application/Search/IndexerSearchWorkflowTests.cs @@ -0,0 +1,44 @@ +/* + * Listenarr - Audiobook Management System + * Copyright (C) 2024-2026 Listenarr Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +using Listenarr.Tests.Common; + +namespace Listenarr.Tests.Features.Application.Search +{ + [Trait("Area", "Search")] + [Trait("Name", "IndexerSearchWorkflowTests")] + [Trait("Category", "IndexerSearchWorkflow")] + public class IndexerSearchWorkflowTests : BaseTests + { + [Fact] + [Trait("Method", "SearchIndexersAsync")] + [Trait("Scenario", "NoIndexersConfiguredReturnsEmptyNotMockResults")] + public async Task SearchIndexers_NoIndexersConfigured_ReturnsEmptyWithoutSyntheticResults() + { + // Given + var workflow = _provider.GetRequiredService(); + Assert.Empty(await _indexerRepository.GetEnabledAsync(isAutomaticSearch: false)); + + // When + var results = await workflow.SearchIndexersAsync("Dune"); + + // Then + Assert.Empty(results); + } + } +}