Add tests for DownloadStationDownloader

Tests:
- Downloads successfully when everything goes right first time
- Downloads successfully when the 5th api call is successful after 4 failures
- Fails to download when 5 api calls fail in a row
- Fails to download if the file has already been added to `Download Station` (when `GetInfoAsync` does not error)
- FAils to download if `remotePath` cannot be parsed by `Path.GetDirectoryName()`
This commit is contained in:
Cucumberrbob 2025-02-17 22:01:16 +00:00
parent f4ca137e83
commit 95ef1f42b8
No known key found for this signature in database
GPG key ID: 2B935C47401C3614

View file

@ -0,0 +1,213 @@
using Moq;
using RdtClient.Service.Helpers;
using RdtClient.Service.Services.Downloaders;
using Synology.Api.Client;
using Synology.Api.Client.Apis.DownloadStation;
using Synology.Api.Client.Apis.DownloadStation.Task.Models;
namespace RdtClient.Service.Test.Services.Downloaders;
class Mocks
{
public readonly String Gid;
public readonly Mock<ISynologyClient> SynologyClientMock = new();
public readonly Mock<IDownloadStationTaskEndpoint> TaskEndpointMock = new();
public Mocks(String gid = "123456")
{
Gid = gid;
var downloadStationApiMock = new Mock<IDownloadStationApi>();
downloadStationApiMock.Setup(a => a.TaskEndpoint()).Returns(TaskEndpointMock.Object);
SynologyClientMock.Setup(c => c.DownloadStationApi()).Returns(downloadStationApiMock.Object);
}
}
class FakeDelayProvider : IDelayProvider
{
public Task Delay(Int32 milliseconds)
{
return Task.CompletedTask;
}
}
public class DownloadStationDownloaderTest
{
[Fact]
public async Task Download_WhenRemotePathEmpty_Throws()
{
// Arrange
var synologyClientMock = new Mock<ISynologyClient>();
var gid = Guid.NewGuid();
var downloadStationDownloader = new DownloadStationDownloader(gid.ToString(),
"https://fake.url/file.txt",
"",
"/path/to/file.txt",
"download-path",
synologyClientMock.Object);
// Act
var exception = await Assert.ThrowsAsync<Exception>(downloadStationDownloader.Download);
// Assert
Assert.Contains("invalid file path", exception.Message, StringComparison.OrdinalIgnoreCase);
synologyClientMock.VerifyNoOtherCalls();
}
[Fact]
public async Task Download_WhenAlreadyAdded_Throws()
{
// Arrange
var mocks = new Mocks();
mocks.TaskEndpointMock.Setup(t => t.GetInfoAsync(mocks.Gid)).ReturnsAsync(new DownloadStationTask());
var downloadStationDownloader = new DownloadStationDownloader(mocks.Gid,
"https://fake.url/file.txt",
"/path/on/remote/file.txt",
"/path/to/file.txt",
"download-path",
mocks.SynologyClientMock.Object);
// Act
var exception = await Assert.ThrowsAsync<Exception>(downloadStationDownloader.Download);
// Assert
Assert.Contains("already been added", exception.Message, StringComparison.OrdinalIgnoreCase);
mocks.TaskEndpointMock.Verify(t => t.GetInfoAsync(mocks.Gid), Times.Once);
mocks.TaskEndpointMock.VerifyNoOtherCalls();
}
[Fact]
public async Task Download_WhenAddedSuccessfully_ReturnsGid()
{
// Arrange
var mocks = new Mocks();
mocks.TaskEndpointMock.Setup(t => t.GetInfoAsync(mocks.Gid)).ThrowsAsync(new Exception());
mocks.TaskEndpointMock.Setup(t => t.ListAsync())
.ReturnsAsync(new DownloadStationTaskListResponse
{
Total = 0,
Offset = 0
});
mocks.TaskEndpointMock.Setup(t => t.CreateAsync(It.IsAny<DownloadStationTaskCreateRequest>()))
.ReturnsAsync(new DownloadStationTaskCreateResponse
{
TaskId = [mocks.Gid]
});
var downloadStationDownloader = new DownloadStationDownloader(mocks.Gid,
"https://fake.url/file.txt",
"/path/on/remote/file.txt",
"/path/to/file.txt",
"download-path",
mocks.SynologyClientMock.Object);
// Act
var result = await downloadStationDownloader.Download();
// Assert
Assert.Equal(mocks.Gid, result);
mocks.TaskEndpointMock.Verify(t => t.GetInfoAsync(mocks.Gid), Times.Once);
mocks.TaskEndpointMock.Verify(t => t.ListAsync(), Times.Once);
mocks.TaskEndpointMock.Verify(t => t.CreateAsync(It.IsAny<DownloadStationTaskCreateRequest>()), Times.Once);
mocks.TaskEndpointMock.VerifyNoOtherCalls();
}
[Fact]
public async Task Download_After5Tries_Throws()
{
var mocks = new Mocks();
mocks.TaskEndpointMock.Setup(t => t.GetInfoAsync(mocks.Gid)).ThrowsAsync(new Exception());
var emptyListResponse = new DownloadStationTaskListResponse
{
Total = 0,
Offset = 0
};
mocks.TaskEndpointMock.SetupSequence(t => t.ListAsync())
.ReturnsAsync(emptyListResponse)
.ReturnsAsync(emptyListResponse)
.ReturnsAsync(emptyListResponse)
.ReturnsAsync(emptyListResponse)
.ReturnsAsync(emptyListResponse);
mocks.TaskEndpointMock.SetupSequence(t => t.CreateAsync(It.IsAny<DownloadStationTaskCreateRequest>()))
.ThrowsAsync(new Exception())
.ThrowsAsync(new Exception())
.ThrowsAsync(new Exception())
.ThrowsAsync(new Exception())
.ThrowsAsync(new Exception());
var downloadStationDownloader = new DownloadStationDownloader(mocks.Gid,
"https://fake.url/file.txt",
"/path/on/remote/file.txt",
"/path/to/file.txt",
"download-path",
mocks.SynologyClientMock.Object,
new FakeDelayProvider());
// Act
var exception = await Assert.ThrowsAsync<Exception>(downloadStationDownloader.Download);
// Assert
Assert.Contains("unable to download", exception.Message, StringComparison.OrdinalIgnoreCase);
mocks.TaskEndpointMock.Verify(t => t.GetInfoAsync(mocks.Gid), Times.Once);
mocks.TaskEndpointMock.Verify(t => t.ListAsync(), Times.Exactly(5));
mocks.TaskEndpointMock.Verify(t => t.CreateAsync(It.IsAny<DownloadStationTaskCreateRequest>()), Times.Exactly(5));
mocks.TaskEndpointMock.VerifyNoOtherCalls();
}
[Fact]
public async Task Download_WhenSuccessfulAfter4Tries_ReturnsGid()
{
var mocks = new Mocks();
mocks.TaskEndpointMock.Setup(t => t.GetInfoAsync(mocks.Gid)).ThrowsAsync(new Exception());
var emptyListResponse = new DownloadStationTaskListResponse
{
Total = 0,
Offset = 0
};
mocks.TaskEndpointMock.SetupSequence(t => t.ListAsync())
.ReturnsAsync(emptyListResponse)
.ReturnsAsync(emptyListResponse)
.ReturnsAsync(emptyListResponse)
.ReturnsAsync(emptyListResponse)
.ReturnsAsync(emptyListResponse);
mocks.TaskEndpointMock.SetupSequence(t => t.CreateAsync(It.IsAny<DownloadStationTaskCreateRequest>()))
.ThrowsAsync(new Exception())
.ThrowsAsync(new Exception())
.ThrowsAsync(new Exception())
.ThrowsAsync(new Exception())
.ReturnsAsync(new DownloadStationTaskCreateResponse
{
TaskId = [mocks.Gid]
});
var downloadStationDownloader = new DownloadStationDownloader(mocks.Gid,
"https://fake.url/file.txt",
"/path/on/remote/file.txt",
"/path/to/file.txt",
"download-path",
mocks.SynologyClientMock.Object,
new FakeDelayProvider());
// Act
var result = await downloadStationDownloader.Download();
// Assert
Assert.Equal(mocks.Gid, result);
mocks.TaskEndpointMock.Verify(t => t.GetInfoAsync(mocks.Gid), Times.Once);
mocks.TaskEndpointMock.Verify(t => t.ListAsync(), Times.Exactly(5));
mocks.TaskEndpointMock.Verify(t => t.CreateAsync(It.IsAny<DownloadStationTaskCreateRequest>()), Times.Exactly(5));
mocks.TaskEndpointMock.VerifyNoOtherCalls();
}
}