Tracker enrichment test changes
This commit is contained in:
parent
98042f8040
commit
60263ca685
1 changed files with 414 additions and 251 deletions
|
|
@ -26,8 +26,103 @@ public class EnricherTest : IDisposable
|
||||||
private const String TestMagnetLink =
|
private const String TestMagnetLink =
|
||||||
"magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567&dn=TestFile&tr=http%3A%2F%2Ftracker1.com%2Fannounce&tr=http%3A%2F%2Ftracker2.com%2Fannounce";
|
"magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567&dn=TestFile&tr=http%3A%2F%2Ftracker1.com%2Fannounce&tr=http%3A%2F%2Ftracker2.com%2Fannounce";
|
||||||
|
|
||||||
|
// Helper methods for creating BEncodedDictionary objects for torrents
|
||||||
|
private static BEncodedDictionary CreateStandardTorrentDict(String announceUrl, List<String>? announceListTier = null)
|
||||||
|
{
|
||||||
|
var torrentDict = new BEncodedDictionary
|
||||||
|
{
|
||||||
|
["announce"] = new BEncodedString(announceUrl)
|
||||||
|
};
|
||||||
|
|
||||||
|
var finalAnnounceList = new BEncodedList();
|
||||||
|
|
||||||
|
if (announceListTier != null)
|
||||||
|
{
|
||||||
|
var tier = new BEncodedList();
|
||||||
|
|
||||||
|
foreach (var tracker in announceListTier)
|
||||||
|
{
|
||||||
|
tier.Add(new BEncodedString(tracker));
|
||||||
|
}
|
||||||
|
|
||||||
|
finalAnnounceList.Add(tier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
finalAnnounceList.Add(new BEncodedList
|
||||||
|
{
|
||||||
|
new BEncodedString(announceUrl)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
torrentDict["announce-list"] = finalAnnounceList;
|
||||||
|
|
||||||
|
if (!torrentDict.ContainsKey("info"))
|
||||||
|
{
|
||||||
|
torrentDict["info"] = new BEncodedDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
return torrentDict;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BEncodedDictionary CreateTorrentDictWithOnlyAnnounce(String announceUrl)
|
||||||
|
{
|
||||||
|
return new BEncodedDictionary
|
||||||
|
{
|
||||||
|
["announce"] = new BEncodedString(announceUrl),
|
||||||
|
["info"] = new BEncodedDictionary()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BEncodedDictionary CreateTorrentDictWithNoTrackers()
|
||||||
|
{
|
||||||
|
return new BEncodedDictionary
|
||||||
|
{
|
||||||
|
["info"] = new BEncodedDictionary()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BEncodedDictionary CreateTorrentDictWithComplexAnnounceList(String primaryAnnounceUrl, List<List<String>> announceListTiers)
|
||||||
|
{
|
||||||
|
var torrentDict = new BEncodedDictionary
|
||||||
|
{
|
||||||
|
["announce"] = new BEncodedString(primaryAnnounceUrl)
|
||||||
|
};
|
||||||
|
|
||||||
|
var bencodedAnnounceList = new BEncodedList();
|
||||||
|
|
||||||
|
foreach (var tier in announceListTiers)
|
||||||
|
{
|
||||||
|
var bencodedTier = new BEncodedList();
|
||||||
|
|
||||||
|
foreach (var tracker in tier)
|
||||||
|
{
|
||||||
|
bencodedTier.Add(new BEncodedString(tracker));
|
||||||
|
}
|
||||||
|
|
||||||
|
bencodedAnnounceList.Add(bencodedTier);
|
||||||
|
}
|
||||||
|
|
||||||
|
torrentDict["announce-list"] = bencodedAnnounceList;
|
||||||
|
|
||||||
|
if (!torrentDict.ContainsKey("info"))
|
||||||
|
{
|
||||||
|
torrentDict["info"] = new BEncodedDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
return torrentDict;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupTrackerListGrabber(String[] trackerList)
|
||||||
|
{
|
||||||
|
_trackerListGrabberMock
|
||||||
|
.Setup(t => t.GetTrackers())
|
||||||
|
.ReturnsAsync(trackerList)
|
||||||
|
.Verifiable();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EnrichMagnetLink_AddsNoTrackers_WhenNoTrackersFromTrackerGrabber()
|
public async Task EnrichMagnetLink_WhenNoTrackers_ReturnsOriginal()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
SetupTrackerListGrabber([]);
|
SetupTrackerListGrabber([]);
|
||||||
|
|
@ -43,18 +138,25 @@ public class EnricherTest : IDisposable
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("magnet:?xt=urn:btih:HASH",
|
[InlineData("magnet:?xt=urn:btih:HASH",
|
||||||
new[]
|
"magnet:?xt=urn:btih:HASH&tr=http%3A%2F%2Fnew-tracker.com%2Fannounce",
|
||||||
{
|
"http://new-tracker.com/announce")]
|
||||||
"http://new-tracker.com/announce"
|
|
||||||
},
|
|
||||||
"magnet:?xt=urn:btih:HASH&tr=http%3A%2F%2Fnew-tracker.com%2Fannounce")]
|
|
||||||
[InlineData("magnet:?xt=urn:btih:HASH",
|
[InlineData("magnet:?xt=urn:btih:HASH",
|
||||||
new[]
|
"magnet:?xt=urn:btih:HASH&tr=http%3A%2F%2Ftracker1.com%2Fannounce&tr=http%3A%2F%2Ftracker2.com%2Fannounce",
|
||||||
{
|
"http://tracker1.com/announce",
|
||||||
"http://tracker1.com/announce", "http://tracker2.com/announce"
|
"http://tracker2.com/announce")]
|
||||||
},
|
[InlineData("magnet:?xt=urn:btih:HASH", "magnet:?xt=urn:btih:HASH&tr=udp%3A%2F%2Ftracker1", "udp://tracker1")]
|
||||||
"magnet:?xt=urn:btih:HASH&tr=http%3A%2F%2Ftracker1.com%2Fannounce&tr=http%3A%2F%2Ftracker2.com%2Fannounce")]
|
[InlineData("magnet:?xt=urn:btih:HASH", "magnet:?xt=urn:btih:HASH&tr=udp%3A%2F%2Ftracker1&tr=udp%3A%2F%2Ftracker2", "udp://tracker1", "udp://tracker2")]
|
||||||
public async Task EnrichMagnetLink_AddsTrackers_WhenTrackersFromTrackerGrabber_Theory(String magnetLink, String[] newTrackers, String expectedResult)
|
[InlineData("magnet:?xt=urn:btih:HASH", "magnet:?xt=urn:btih:HASH")]
|
||||||
|
[InlineData("magnet:?",
|
||||||
|
"magnet:?tr=udp%3A%2F%2Ftracker1",
|
||||||
|
"udp://tracker1")]
|
||||||
|
[InlineData("magnet:?",
|
||||||
|
"magnet:?tr=udp%3A%2F%2Ftracker1&tr=udp%3A%2F%2Ftracker2",
|
||||||
|
"udp://tracker1",
|
||||||
|
"udp://tracker2")]
|
||||||
|
[InlineData("magnet:?",
|
||||||
|
"magnet:?")]
|
||||||
|
public async Task EnrichMagnetLink_WhenTrackersProvided_AddsTrackers(String magnetLink, String expectedResult, params String[] newTrackers)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
SetupTrackerListGrabber(newTrackers);
|
SetupTrackerListGrabber(newTrackers);
|
||||||
|
|
@ -68,7 +170,7 @@ public class EnricherTest : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EnrichMagnetLink_DoesNotAddDuplicateTrackers_WhenTrackersFromTrackerGrabberAlreadyPresent()
|
public async Task EnrichMagnetLink_WhenDuplicatesProvided_AddsUniqueTrackers()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
SetupTrackerListGrabber(["http://new-tracker.com/announce", "http://tracker1.com/announce"]);
|
SetupTrackerListGrabber(["http://new-tracker.com/announce", "http://tracker1.com/announce"]);
|
||||||
|
|
@ -83,7 +185,7 @@ public class EnricherTest : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EnrichMagnetLink_Throws_WhenTrackerGrabberThrows()
|
public async Task EnrichMagnetLink_WhenGrabberFails_ThrowsException()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_trackerListGrabberMock
|
_trackerListGrabberMock
|
||||||
|
|
@ -97,175 +199,30 @@ public class EnricherTest : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EnrichTorrentBytes_AddsTrackers_WhenTrackersFromTrackerGrabber()
|
public async Task EnrichMagnetLink_WhenTrackersAdded_PreservesParameters()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var originalTracker = "http://tracker1.com/announce";
|
var magnetLink = "magnet:?xt=urn:btih:HASH&dn=MyFile&tr=udp%3A%2F%2Fexisting";
|
||||||
var newTracker = "http://new-tracker.com/announce";
|
|
||||||
|
|
||||||
var torrentDict = new BEncodedDictionary
|
var newTrackers = new[]
|
||||||
{
|
{
|
||||||
["announce"] = new BEncodedString(originalTracker),
|
"udp://new1", "udp://existing"
|
||||||
["announce-list"] = new BEncodedList
|
|
||||||
{
|
|
||||||
new BEncodedList
|
|
||||||
{
|
|
||||||
new BEncodedString(originalTracker)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var originalTorrentBytes = torrentDict.Encode();
|
SetupTrackerListGrabber(newTrackers);
|
||||||
|
|
||||||
SetupTrackerListGrabber([newTracker]);
|
|
||||||
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
var result = await enricher.EnrichMagnetLink(magnetLink);
|
||||||
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(enrichedDict.ContainsKey("announce"));
|
var queryParams = System.Web.HttpUtility.ParseQueryString(new Uri(result).Query);
|
||||||
Assert.True(enrichedDict.ContainsKey("announce-list"));
|
Assert.Equal("urn:btih:HASH", queryParams["xt"]);
|
||||||
|
Assert.Equal("MyFile", queryParams["dn"]);
|
||||||
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
|
||||||
var flattened = announceList.Cast<BEncodedList>().SelectMany(l => l.Cast<BEncodedString>().Select(s => s.Text)).ToList();
|
|
||||||
|
|
||||||
Assert.Contains(originalTracker, flattened);
|
|
||||||
Assert.Contains(newTracker, flattened);
|
|
||||||
|
|
||||||
var announce = ((BEncodedString)enrichedDict["announce"]).Text;
|
|
||||||
Assert.Equal(flattened.First(), announce);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupTrackerListGrabber(String[] trackerList)
|
|
||||||
{
|
|
||||||
_trackerListGrabberMock
|
|
||||||
.Setup(t => t.GetTrackers())
|
|
||||||
.ReturnsAsync(trackerList)
|
|
||||||
.Verifiable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EnrichTorrentBytes_DoesNotAddDuplicateTrackers()
|
public async Task EnrichMagnetLink_WhenTrackersAdded_IncludesAllTrackers()
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var originalTracker = "http://tracker1.com/announce";
|
|
||||||
var duplicateTracker = "http://tracker1.com/announce";
|
|
||||||
|
|
||||||
var torrentDict = new BEncodedDictionary
|
|
||||||
{
|
|
||||||
["announce"] = new BEncodedString(originalTracker),
|
|
||||||
["announce-list"] = new BEncodedList
|
|
||||||
{
|
|
||||||
new BEncodedList
|
|
||||||
{
|
|
||||||
new BEncodedString(originalTracker)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var originalTorrentBytes = torrentDict.Encode();
|
|
||||||
|
|
||||||
SetupTrackerListGrabber([duplicateTracker]);
|
|
||||||
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
|
||||||
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
|
||||||
var flattened = announceList.Cast<BEncodedList>().SelectMany(l => l.Cast<BEncodedString>().Select(s => s.Text)).ToList();
|
|
||||||
|
|
||||||
Assert.Single(flattened);
|
|
||||||
Assert.Contains(originalTracker, flattened);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task EnrichTorrentBytes_AddsTrackers_WhenNoAnnounceListPresent()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var originalTracker = "http://tracker1.com/announce";
|
|
||||||
var newTracker = "http://new-tracker.com/announce";
|
|
||||||
|
|
||||||
var torrentDict = new BEncodedDictionary
|
|
||||||
{
|
|
||||||
["announce"] = new BEncodedString(originalTracker)
|
|
||||||
|
|
||||||
// No "announce-list"
|
|
||||||
};
|
|
||||||
|
|
||||||
var originalTorrentBytes = torrentDict.Encode();
|
|
||||||
|
|
||||||
SetupTrackerListGrabber([newTracker]);
|
|
||||||
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
|
||||||
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.True(enrichedDict.ContainsKey("announce-list"));
|
|
||||||
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
|
||||||
var flattened = announceList.Cast<BEncodedList>().SelectMany(l => l.Cast<BEncodedString>().Select(s => s.Text)).ToList();
|
|
||||||
|
|
||||||
Assert.Contains(originalTracker, flattened);
|
|
||||||
Assert.Contains(newTracker, flattened);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task EnrichTorrentBytes_Throws_WhenTrackerGrabberThrows()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
_trackerListGrabberMock
|
|
||||||
.Setup(t => t.GetTrackers())
|
|
||||||
.ThrowsAsync(new InvalidOperationException("Unable to fetch tracker list for enrichment."));
|
|
||||||
|
|
||||||
var torrentDict = new BEncodedDictionary
|
|
||||||
{
|
|
||||||
["announce"] = new BEncodedString("http://tracker1.com/announce"),
|
|
||||||
["announce-list"] = new BEncodedList
|
|
||||||
{
|
|
||||||
new BEncodedList
|
|
||||||
{
|
|
||||||
new BEncodedString("http://tracker1.com/announce")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var originalTorrentBytes = torrentDict.Encode();
|
|
||||||
|
|
||||||
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
await Assert.ThrowsAsync<InvalidOperationException>(() => enricher.EnrichTorrentBytes(originalTorrentBytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task EnrichTorrentBytes_ThrowsArgumentException_OnNullOrEmptyInput()
|
|
||||||
{
|
|
||||||
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
|
||||||
|
|
||||||
await Assert.ThrowsAsync<ArgumentException>(() => enricher.EnrichTorrentBytes(null!));
|
|
||||||
await Assert.ThrowsAsync<ArgumentException>(() => enricher.EnrichTorrentBytes([]));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task EnrichTorrentBytes_ThrowsInvalidOperationException_OnNonTorrentBytes()
|
|
||||||
{
|
|
||||||
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
|
||||||
|
|
||||||
var notTorrent = new Byte[]
|
|
||||||
{
|
|
||||||
1, 2, 3, 4, 5
|
|
||||||
};
|
|
||||||
|
|
||||||
await Assert.ThrowsAsync<InvalidOperationException>(() => enricher.EnrichTorrentBytes(notTorrent));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task EnrichMagnetLink_WithExistingTrackersAndOtherParameters()
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var magnetLink = "magnet:?xt=urn:btih:HASH&dn=MyFile&tr=udp%3A%2F%2Fexisting";
|
var magnetLink = "magnet:?xt=urn:btih:HASH&dn=MyFile&tr=udp%3A%2F%2Fexisting";
|
||||||
|
|
@ -285,99 +242,267 @@ public class EnricherTest : IDisposable
|
||||||
var queryParams = System.Web.HttpUtility.ParseQueryString(new Uri(result).Query);
|
var queryParams = System.Web.HttpUtility.ParseQueryString(new Uri(result).Query);
|
||||||
var trValues = queryParams.GetValues("tr")?.ToList() ?? new List<String>();
|
var trValues = queryParams.GetValues("tr")?.ToList() ?? new List<String>();
|
||||||
|
|
||||||
Assert.Equal("urn:btih:HASH", queryParams["xt"]);
|
|
||||||
Assert.Equal("MyFile", queryParams["dn"]);
|
|
||||||
Assert.Contains("udp://existing", trValues);
|
Assert.Contains("udp://existing", trValues);
|
||||||
Assert.Contains("udp://new1", trValues);
|
Assert.Contains("udp://new1", trValues);
|
||||||
Assert.Equal(2, trValues.Count);
|
Assert.Equal(2, trValues.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData("magnet:?xt=urn:btih:HASH",
|
public async Task EnrichTorrentBytes_WhenTrackersAdded_CreatesAnnounceKey()
|
||||||
new[]
|
|
||||||
{
|
|
||||||
"udp://tracker1"
|
|
||||||
},
|
|
||||||
"magnet:?xt=urn:btih:HASH&tr=udp%3A%2F%2Ftracker1")]
|
|
||||||
[InlineData("magnet:?xt=urn:btih:HASH",
|
|
||||||
new[]
|
|
||||||
{
|
|
||||||
"udp://tracker1", "udp://tracker2"
|
|
||||||
},
|
|
||||||
"magnet:?xt=urn:btih:HASH&tr=udp%3A%2F%2Ftracker1&tr=udp%3A%2F%2Ftracker2")]
|
|
||||||
[InlineData("magnet:?xt=urn:btih:HASH",
|
|
||||||
new String[]
|
|
||||||
{
|
|
||||||
},
|
|
||||||
"magnet:?xt=urn:btih:HASH")]
|
|
||||||
public async Task EnrichMagnetLink_BasicMagnetWithHashOnly_Theory(String magnetLink, String[] newTrackers, String expectedResult)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
SetupTrackerListGrabber(newTrackers);
|
var originalTracker = "http://tracker1.com/announce";
|
||||||
|
var newTracker = "http://new-tracker.com/announce";
|
||||||
|
var torrentDict = CreateStandardTorrentDict(originalTracker);
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
SetupTrackerListGrabber([newTracker]);
|
||||||
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await enricher.EnrichMagnetLink(magnetLink);
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedResult, result);
|
Assert.True(enrichedDict.ContainsKey("announce"));
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData("magnet:?",
|
|
||||||
new[]
|
|
||||||
{
|
|
||||||
"udp://tracker1"
|
|
||||||
},
|
|
||||||
"magnet:?tr=udp%3A%2F%2Ftracker1")]
|
|
||||||
[InlineData("magnet:?",
|
|
||||||
new[]
|
|
||||||
{
|
|
||||||
"udp://tracker1", "udp://tracker2"
|
|
||||||
},
|
|
||||||
"magnet:?tr=udp%3A%2F%2Ftracker1&tr=udp%3A%2F%2Ftracker2")]
|
|
||||||
[InlineData("magnet:?",
|
|
||||||
new String[]
|
|
||||||
{
|
|
||||||
},
|
|
||||||
"magnet:?")]
|
|
||||||
public async Task EnrichMagnetLink_MagnetEndsWithQuestionMarkOnly_Theory(String magnetLink, String[] newTrackers, String expectedResult)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
SetupTrackerListGrabber(newTrackers);
|
|
||||||
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = await enricher.EnrichMagnetLink(magnetLink);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(expectedResult, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EnrichMagnetLink_GetTrackersReturnsEmptyArray_Unchanged()
|
public async Task EnrichTorrentBytes_WhenTrackersAdded_CreatesAnnounceListKey()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var magnetLink = "magnet:?xt=urn:btih:HASH&tr=udp%3A%2F%2Fexisting";
|
var originalTracker = "http://tracker1.com/announce";
|
||||||
|
var newTracker = "http://new-tracker.com/announce";
|
||||||
|
var torrentDict = CreateStandardTorrentDict(originalTracker);
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
SetupTrackerListGrabber([newTracker]);
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(enrichedDict.ContainsKey("announce-list"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenTrackersAdded_IncludesAllTrackers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var originalTracker = "http://tracker1.com/announce";
|
||||||
|
var newTracker = "http://new-tracker.com/announce";
|
||||||
|
var torrentDict = CreateStandardTorrentDict(originalTracker);
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
SetupTrackerListGrabber([newTracker]); // Grabber returns newTracker
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
||||||
|
var flattened = announceList.Cast<BEncodedList>().SelectMany(l => l.Cast<BEncodedString>().Select(s => s.Text)).ToList();
|
||||||
|
Assert.Contains(originalTracker, flattened);
|
||||||
|
Assert.Contains(newTracker, flattened);
|
||||||
|
Assert.Equal(2, flattened.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenTrackersAdded_SetsPrimaryAnnounce()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var originalTracker = "http://tracker1.com/announce";
|
||||||
|
var newTracker = "http://new-tracker.com/announce";
|
||||||
|
var torrentDict = CreateStandardTorrentDict(originalTracker);
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
SetupTrackerListGrabber([newTracker]);
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
||||||
|
var flattened = announceList.Cast<BEncodedList>().SelectMany(l => l.Cast<BEncodedString>().Select(s => s.Text)).ToList();
|
||||||
|
var announce = ((BEncodedString)enrichedDict["announce"]).Text;
|
||||||
|
Assert.Equal(flattened.First(), announce);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenDuplicatesProvided_AddsUniqueTrackers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var originalTracker = "http://tracker1.com/announce";
|
||||||
|
var duplicateTracker = "http://tracker1.com/announce";
|
||||||
|
|
||||||
|
var torrentDict = CreateStandardTorrentDict(originalTracker);
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
|
||||||
|
SetupTrackerListGrabber([duplicateTracker]);
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
||||||
|
var flattened = announceList.Cast<BEncodedList>().SelectMany(l => l.Cast<BEncodedString>().Select(s => s.Text)).ToList();
|
||||||
|
|
||||||
|
Assert.Single(flattened);
|
||||||
|
Assert.Contains(originalTracker, flattened);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenNoAnnounceList_CreatesAnnounceListKey()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var originalTracker = "http://tracker1.com/announce";
|
||||||
|
var newTracker = "http://new-tracker.com/announce";
|
||||||
|
var torrentDict = CreateTorrentDictWithOnlyAnnounce(originalTracker);
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
SetupTrackerListGrabber([newTracker]);
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(enrichedDict.ContainsKey("announce-list"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenNoAnnounceList_AddsOriginalTracker()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var originalTracker = "http://tracker1.com/announce";
|
||||||
|
var newTracker = "http://new-tracker.com/announce";
|
||||||
|
var torrentDict = CreateTorrentDictWithOnlyAnnounce(originalTracker);
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
SetupTrackerListGrabber([newTracker]);
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
||||||
|
var flattened = announceList.Cast<BEncodedList>().SelectMany(l => l.Cast<BEncodedString>().Select(s => s.Text)).ToList();
|
||||||
|
Assert.Contains(originalTracker, flattened);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenNoAnnounceList_AddsGrabbedTrackers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var originalTracker = "http://tracker1.com/announce";
|
||||||
|
var newTracker = "http://new-tracker.com/announce";
|
||||||
|
var torrentDict = CreateTorrentDictWithOnlyAnnounce(originalTracker);
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
SetupTrackerListGrabber([newTracker]);
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
||||||
|
var flattened = announceList.Cast<BEncodedList>().SelectMany(l => l.Cast<BEncodedString>().Select(s => s.Text)).ToList();
|
||||||
|
Assert.Contains(newTracker, flattened);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenGrabberFails_ThrowsException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
_trackerListGrabberMock
|
||||||
|
.Setup(t => t.GetTrackers())
|
||||||
|
.ThrowsAsync(new InvalidOperationException("Unable to fetch tracker list for enrichment."));
|
||||||
|
|
||||||
|
var torrentDict = CreateStandardTorrentDict("http://tracker1.com/announce");
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
await Assert.ThrowsAsync<InvalidOperationException>(() => enricher.EnrichTorrentBytes(originalTorrentBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenNoNewTrackers_ReturnsOriginalBytes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var torrentDict = CreateStandardTorrentDict("http://existing.tracker/announce");
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
|
||||||
SetupTrackerListGrabber([]);
|
SetupTrackerListGrabber([]);
|
||||||
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await enricher.EnrichMagnetLink(magnetLink);
|
var resultBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(magnetLink, result);
|
Assert.Equal(originalTorrentBytes, resultBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EnrichTorrentBytes_NoExistingAnnounceOrAnnounceList()
|
public async Task EnrichTorrentBytes_WhenNoTrackers_ReturnsOriginalBytes()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var torrentDict = new BEncodedDictionary
|
var torrentDict = CreateTorrentDictWithNoTrackers();
|
||||||
|
var originalTorrentBytes = torrentDict.Encode();
|
||||||
|
|
||||||
|
SetupTrackerListGrabber([]); // Grabber returns no new trackers
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var resultBytes = await enricher.EnrichTorrentBytes(originalTorrentBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(originalTorrentBytes, resultBytes);
|
||||||
|
|
||||||
|
var decodedResult = BEncodedValue.Decode<BEncodedDictionary>(resultBytes);
|
||||||
|
Assert.False(decodedResult.ContainsKey("announce"));
|
||||||
|
Assert.False(decodedResult.ContainsKey("announce-list"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenNullInput_ThrowsArgumentException()
|
||||||
|
{
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
await Assert.ThrowsAsync<ArgumentException>(() => enricher.EnrichTorrentBytes(null!));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenEmptyInput_ThrowsArgumentException()
|
||||||
|
{
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
await Assert.ThrowsAsync<ArgumentException>(() => enricher.EnrichTorrentBytes([]));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenInvalidInput_ThrowsInvalidOperationException()
|
||||||
|
{
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
var notTorrent = new Byte[]
|
||||||
{
|
{
|
||||||
["info"] = new BEncodedDictionary()
|
1, 2, 3, 4, 5
|
||||||
};
|
};
|
||||||
|
|
||||||
|
await Assert.ThrowsAsync<InvalidOperationException>(() => enricher.EnrichTorrentBytes(notTorrent));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenNoAnnounceFields_CreatesAnnounceField()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var torrentDict = CreateTorrentDictWithNoTrackers();
|
||||||
var originalBytes = torrentDict.Encode();
|
var originalBytes = torrentDict.Encode();
|
||||||
|
|
||||||
var newTrackers = new[]
|
var newTrackers = new[]
|
||||||
|
|
@ -393,9 +518,55 @@ public class EnricherTest : IDisposable
|
||||||
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
Assert.True(enrichedDict.ContainsKey("announce"));
|
||||||
Assert.Equal(newTrackers[0], ((BEncodedString)enrichedDict["announce"]).Text);
|
Assert.Equal(newTrackers[0], ((BEncodedString)enrichedDict["announce"]).Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenNoAnnounceFields_CreatesAnnounceListKey()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var torrentDict = CreateTorrentDictWithNoTrackers();
|
||||||
|
var originalBytes = torrentDict.Encode();
|
||||||
|
|
||||||
|
var newTrackers = new[]
|
||||||
|
{
|
||||||
|
"udp://tracker1", "udp://tracker2"
|
||||||
|
};
|
||||||
|
|
||||||
|
SetupTrackerListGrabber(newTrackers);
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(enrichedDict.ContainsKey("announce-list"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task EnrichTorrentBytes_WhenNoAnnounceFields_AddsGrabbedTrackers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var torrentDict = CreateTorrentDictWithNoTrackers();
|
||||||
|
var originalBytes = torrentDict.Encode();
|
||||||
|
|
||||||
|
var newTrackers = new[]
|
||||||
|
{
|
||||||
|
"udp://tracker1", "udp://tracker2"
|
||||||
|
};
|
||||||
|
|
||||||
|
SetupTrackerListGrabber(newTrackers);
|
||||||
|
var enricher = new Enricher(_loggerMock.Object, _trackerListGrabberMock.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var enrichedBytes = await enricher.EnrichTorrentBytes(originalBytes);
|
||||||
|
var enrichedDict = BEncodedValue.Decode<BEncodedDictionary>(enrichedBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
var announceList = (BEncodedList)enrichedDict["announce-list"];
|
||||||
Assert.Equal(2, announceList.Count);
|
Assert.Equal(newTrackers.Length, announceList.Count);
|
||||||
|
|
||||||
Assert.Collection(announceList,
|
Assert.Collection(announceList,
|
||||||
tier => Assert.Equal(newTrackers[0], ((BEncodedString)((BEncodedList)tier)[0]).Text),
|
tier => Assert.Equal(newTrackers[0], ((BEncodedString)((BEncodedList)tier)[0]).Text),
|
||||||
|
|
@ -403,32 +574,24 @@ public class EnricherTest : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EnrichTorrentBytes_WithExistingAnnounceAndAnnounceList()
|
public async Task EnrichTorrentBytes_WhenExistingTrackers_MergesNewTrackers()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var existingTrackers = new List<String>
|
var primaryAnnounceUrl = "http://existing.com/announce";
|
||||||
{
|
|
||||||
"http://tier1.com",
|
|
||||||
"http://existing.com/announce"
|
|
||||||
};
|
|
||||||
|
|
||||||
var torrentDict = new BEncodedDictionary
|
var announceListTiers = new List<List<String>>
|
||||||
{
|
{
|
||||||
["announce"] = new BEncodedString(existingTrackers[1]),
|
new()
|
||||||
["announce-list"] = new BEncodedList
|
|
||||||
{
|
{
|
||||||
new BEncodedList
|
"http://tier1.com"
|
||||||
{
|
|
||||||
new BEncodedString(existingTrackers[0])
|
|
||||||
},
|
|
||||||
new BEncodedList
|
|
||||||
{
|
|
||||||
new BEncodedString(existingTrackers[1])
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
["info"] = new BEncodedDictionary()
|
new()
|
||||||
|
{
|
||||||
|
primaryAnnounceUrl
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var torrentDict = CreateTorrentDictWithComplexAnnounceList(primaryAnnounceUrl, announceListTiers);
|
||||||
var originalBytes = torrentDict.Encode();
|
var originalBytes = torrentDict.Encode();
|
||||||
|
|
||||||
var newTrackersFromGrabber = new[]
|
var newTrackersFromGrabber = new[]
|
||||||
|
|
@ -456,4 +619,4 @@ public class EnricherTest : IDisposable
|
||||||
Assert.Equal(3, finalAnnounceList.Count);
|
Assert.Equal(3, finalAnnounceList.Count);
|
||||||
Assert.Contains(((BEncodedString)enrichedDict["announce"]).Text, finalAnnounceList);
|
Assert.Contains(((BEncodedString)enrichedDict["announce"]).Text, finalAnnounceList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue