using Minio; using RobotNet10.StorageManager; using Xunit; namespace RobotNet10.StorageManager.Test; public class StorageManagerTests { private readonly string _testFolder = Path.Combine(Path.GetTempPath(), "StorageManagerTests"); public StorageManagerTests() { // Clean up test folder before each test if (Directory.Exists(_testFolder)) { Directory.Delete(_testFolder, true); } Directory.CreateDirectory(_testFolder); } [Fact] public void Constructor_WithNullConfig_ThrowsArgumentNullException() { // Act & Assert Assert.Throws(() => new StorageManager(null!)); } [Fact] public void Constructor_WithMinioButNoConfig_ThrowsArgumentException() { // Arrange var config = new StorageConfig { UsingLocal = false, MinioConfig = null }; // Act & Assert var ex = Assert.Throws(() => new StorageManager(config)); Assert.Contains("MinioConfig is required", ex.Message); } [Fact] public void Constructor_WithMinioButEmptyEndpoint_ThrowsArgumentException() { // Arrange var config = new StorageConfig { UsingLocal = false, MinioConfig = new MinioConfig { Endpoint = string.Empty }, Bucket = "test-bucket" }; // Act & Assert var ex = Assert.Throws(() => new StorageManager(config)); Assert.Contains("Endpoint", ex.Message); } [Fact] public void Constructor_WithMinioButEmptyBucket_ThrowsArgumentException() { // Arrange var config = new StorageConfig { UsingLocal = false, MinioConfig = new MinioConfig { Endpoint = "localhost:9000" }, Bucket = string.Empty }; // Act & Assert var ex = Assert.Throws(() => new StorageManager(config)); Assert.Contains("Bucket", ex.Message); } [Fact] public async Task UploadAsync_WithNullPath_ThrowsArgumentException() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var data = new MemoryStream(new byte[] { 1, 2, 3 }); // Act & Assert await Assert.ThrowsAsync(() => manager.UploadAsync(null!, "test", data, 3, "image/png", CancellationToken.None)); } [Fact] public async Task UploadAsync_WithPathContainingDotDot_ThrowsArgumentException() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var data = new MemoryStream(new byte[] { 1, 2, 3 }); // Act & Assert await Assert.ThrowsAsync(() => manager.UploadAsync("../test", "test", data, 3, "image/png", CancellationToken.None)); } [Fact] public async Task UploadAsync_WithNullData_ThrowsArgumentNullException() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); // Act & Assert await Assert.ThrowsAsync(() => manager.UploadAsync("test", "test", null!, 3, "image/png", CancellationToken.None)); } [Fact] public async Task UploadAsync_WithNegativeSize_ThrowsArgumentException() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var data = new MemoryStream(new byte[] { 1, 2, 3 }); // Act & Assert await Assert.ThrowsAsync(() => manager.UploadAsync("test", "test", data, -1, "image/png", CancellationToken.None)); } [Fact] public async Task UploadAsync_Local_WithPngContentType_CreatesPngFile() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var data = new MemoryStream(new byte[] { 1, 2, 3 }); var path = "test"; var objectName = "image"; // Act await manager.UploadAsync(path, objectName, data, 3, "image/png", CancellationToken.None); // Assert var expectedPath = Path.Combine(_testFolder, path, $"{objectName}.png"); Assert.True(File.Exists(expectedPath)); } [Fact] public async Task UploadAsync_Local_WithJpegContentType_CreatesJpgFile() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var data = new MemoryStream(new byte[] { 1, 2, 3 }); var path = "test"; var objectName = "image"; // Act await manager.UploadAsync(path, objectName, data, 3, "image/jpeg", CancellationToken.None); // Assert var expectedPath = Path.Combine(_testFolder, path, $"{objectName}.jpg"); Assert.True(File.Exists(expectedPath)); } [Fact] public async Task UploadAsync_Local_WithPdfContentType_CreatesPdfFile() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var data = new MemoryStream(new byte[] { 1, 2, 3 }); var path = "test"; var objectName = "document"; // Act await manager.UploadAsync(path, objectName, data, 3, "application/pdf", CancellationToken.None); // Assert var expectedPath = Path.Combine(_testFolder, path, $"{objectName}.pdf"); Assert.True(File.Exists(expectedPath)); } [Fact] public async Task UploadAsync_Local_CreatesBackupFile() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var data1 = new MemoryStream(new byte[] { 1, 2, 3 }); var data2 = new MemoryStream(new byte[] { 4, 5, 6 }); var path = "test"; var objectName = "image"; // Act - Upload first time await manager.UploadAsync(path, objectName, data1, 3, "image/png", CancellationToken.None); var filePath = Path.Combine(_testFolder, path, $"{objectName}.png"); Assert.True(File.Exists(filePath)); // Upload second time - should create backup await manager.UploadAsync(path, objectName, data2, 3, "image/png", CancellationToken.None); // Assert Assert.True(File.Exists(filePath)); var backupPath = $"{filePath}.bk"; Assert.True(File.Exists(backupPath)); } [Fact] public async Task GetUrlAsync_Local_WithExistingFile_ReturnsPath() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var path = "test"; var objectName = "image"; var filePath = Path.Combine(_testFolder, path, $"{objectName}.png"); Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); File.WriteAllBytes(filePath, new byte[] { 1, 2, 3 }); // Act var url = await manager.GetUrlAsync(path, objectName, CancellationToken.None); // Assert Assert.Equal(filePath, url); } [Fact] public async Task GetUrlAsync_Local_WithNonExistingFile_ReturnsEmpty() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); // Act var url = await manager.GetUrlAsync("test", "nonexistent", CancellationToken.None); // Assert Assert.Equal(string.Empty, url); } [Fact] public async Task DeleteAsync_Local_DeletesFile() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var path = "test"; var objectName = "image"; var filePath = Path.Combine(_testFolder, path, $"{objectName}.png"); Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); File.WriteAllBytes(filePath, new byte[] { 1, 2, 3 }); // Act await manager.DeleteAsync(path, objectName, CancellationToken.None); // Assert Assert.False(File.Exists(filePath)); } [Fact] public async Task ExistsAsync_Local_WithExistingFile_ReturnsTrue() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var path = "test"; var objectName = "image"; var filePath = Path.Combine(_testFolder, path, $"{objectName}.png"); Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); File.WriteAllBytes(filePath, new byte[] { 1, 2, 3 }); // Act var exists = await manager.ExistsAsync(path, objectName, CancellationToken.None); // Assert Assert.True(exists); } [Fact] public async Task ExistsAsync_Local_WithNonExistingFile_ReturnsFalse() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); // Act var exists = await manager.ExistsAsync("test", "nonexistent", CancellationToken.None); // Assert Assert.False(exists); } [Fact] public async Task ListAsync_Local_NonRecursive_ReturnsFilesInPath() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var path = "test"; var folderPath = Path.Combine(_testFolder, path); Directory.CreateDirectory(folderPath); File.WriteAllBytes(Path.Combine(folderPath, "file1.png"), new byte[] { 1 }); File.WriteAllBytes(Path.Combine(folderPath, "file2.jpg"), new byte[] { 2 }); // Act var files = await manager.ListAsync(path, false, CancellationToken.None); // Assert Assert.Equal(2, files.Count); Assert.Contains("file1.png", files); Assert.Contains("file2.jpg", files); } [Fact] public async Task ListAsync_Local_Recursive_ReturnsAllFiles() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var path = "test"; var folderPath = Path.Combine(_testFolder, path); Directory.CreateDirectory(folderPath); var subFolder = Path.Combine(folderPath, "sub"); Directory.CreateDirectory(subFolder); File.WriteAllBytes(Path.Combine(folderPath, "file1.png"), new byte[] { 1 }); File.WriteAllBytes(Path.Combine(subFolder, "file2.jpg"), new byte[] { 2 }); // Act var files = await manager.ListAsync(path, true, CancellationToken.None); // Assert Assert.Equal(2, files.Count); Assert.Contains("file1.png", files); Assert.Contains("sub/file2.jpg", files); } [Fact] public async Task CopyAsync_Local_CopiesFile() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var sourcePath = "source"; var destPath = "dest"; var objectName = "file"; var sourceFile = Path.Combine(_testFolder, sourcePath, $"{objectName}.png"); Directory.CreateDirectory(Path.GetDirectoryName(sourceFile)!); File.WriteAllBytes(sourceFile, new byte[] { 1, 2, 3 }); // Act await manager.CopyAsync(sourcePath, destPath, objectName, CancellationToken.None); // Assert var destFile = Path.Combine(_testFolder, destPath, $"{objectName}.png"); Assert.True(File.Exists(destFile)); Assert.True(File.Exists(sourceFile)); // Source should still exist } [Fact] public async Task GetMetadataAsync_Local_ReturnsMetadata() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); var path = "test"; var objectName = "image"; var filePath = Path.Combine(_testFolder, path, $"{objectName}.png"); Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); var fileData = new byte[] { 1, 2, 3, 4, 5 }; File.WriteAllBytes(filePath, fileData); // Act var metadata = await manager.GetMetadataAsync(path, objectName, CancellationToken.None); // Assert Assert.Equal(path, metadata.Path); Assert.Equal(objectName, metadata.ObjectName); Assert.Equal(fileData.Length, metadata.Size); Assert.Equal("image/png", metadata.ContentType); Assert.NotNull(metadata.LastModified); } [Fact] public async Task GetMetadataAsync_Local_WithNonExistingFile_ThrowsFileNotFoundException() { // Arrange var config = new StorageConfig { UsingLocal = true, LocalFolder = _testFolder }; var manager = new StorageManager(config); // Act & Assert await Assert.ThrowsAsync(() => manager.GetMetadataAsync("test", "nonexistent", CancellationToken.None)); } [Fact] public void Dispose_DisposesMinioClient() { // Arrange var config = new StorageConfig { UsingLocal = false, MinioConfig = new MinioConfig { Endpoint = "localhost:9000", User = "minioadmin", Password = "minioadmin" }, Bucket = "test-bucket" }; var manager = new StorageManager(config); // Act manager.Dispose(); // Assert - Should not throw Assert.True(true); } }