diff --git a/CloudinaryDotNet.IntegrationTests/IntegrationTestBase.cs b/CloudinaryDotNet.IntegrationTests/IntegrationTestBase.cs index b6ef0d17..8b3bf922 100644 --- a/CloudinaryDotNet.IntegrationTests/IntegrationTestBase.cs +++ b/CloudinaryDotNet.IntegrationTests/IntegrationTestBase.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net.Http; using System.Reflection; +using System.Security.Cryptography; using System.Threading.Tasks; using CloudinaryDotNet.Actions; using NUnit.Framework; @@ -507,6 +508,18 @@ protected string GetUniqueMetadataFieldLabel(string suffix = "") return label; } + protected static string GetFileMd5Sum(string filename) + { + using (var md5 = MD5.Create()) + { + using (var stream = File.OpenRead(filename)) + { + var hash = md5.ComputeHash(stream); + return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); + } + } + } + [OneTimeTearDown] public virtual void Cleanup() { diff --git a/CloudinaryDotNet.IntegrationTests/UploadApi/UploadMethodsTest.cs b/CloudinaryDotNet.IntegrationTests/UploadApi/UploadMethodsTest.cs index 69ac2303..c18b449c 100644 --- a/CloudinaryDotNet.IntegrationTests/UploadApi/UploadMethodsTest.cs +++ b/CloudinaryDotNet.IntegrationTests/UploadApi/UploadMethodsTest.cs @@ -40,6 +40,9 @@ public class UploadMethodsTest : IntegrationTestBase protected string m_implicitTransformationText; + protected string m_largeFileEtag; + protected int m_largeFileLength; + public override void Initialize() { base.Initialize(); @@ -52,6 +55,9 @@ public override void Initialize() m_transformationAr25, m_transformationAr69, m_transformationAr30, m_transformationAr12, m_eagerTransformation); + + m_largeFileEtag = GetFileMd5Sum(m_testLargeImagePath); + m_largeFileLength = (int)new FileInfo(m_testLargeImagePath).Length; } [Test, RetryWithDelay] @@ -576,7 +582,7 @@ public void TestUploadLargeNonSeekableStream() var result = m_cloudinary.UploadLarge(uploadParams, TEST_CHUNK_SIZE); - AssertUploadLarge(result, bytes.Length); + AssertUploadLarge(result); } } @@ -585,13 +591,12 @@ public void TestUploadLargeRawFiles() { // support uploading large raw files var largeFilePath = m_testLargeImagePath; - int largeFileLength = (int)new FileInfo(largeFilePath).Length; var uploadParams = GetUploadLargeRawParams(largeFilePath); var result = m_cloudinary.UploadLarge(uploadParams, TEST_CHUNK_SIZE); - AssertUploadLarge(result, largeFileLength); + AssertUploadLarge(result); } [Test, RetryWithDelay] @@ -599,13 +604,12 @@ public async Task TestUploadLargeRawFilesAsyncInParallel() { // support asynchronous uploading large raw files var largeFilePath = m_testLargeImagePath; - int largeFileLength = (int)new FileInfo(largeFilePath).Length; var uploadParams = GetUploadLargeRawParams(largeFilePath); var result = await m_cloudinary.UploadLargeAsync(uploadParams, TEST_CHUNK_SIZE, 2); - AssertUploadLarge(result, largeFileLength); + AssertUploadLarge(result); } private RawUploadParams GetUploadLargeRawParams(string path) @@ -617,44 +621,46 @@ private RawUploadParams GetUploadLargeRawParams(string path) }; } - private void AssertUploadLarge(RawUploadResult result, int fileLength) + private void AssertUploadLarge(RawUploadResult result, int fileLength = 0, string etag = null) { + if (fileLength == 0) + { + fileLength = m_largeFileLength; + } + if (etag == null) + { + etag = m_largeFileEtag; + } Assert.NotNull(result); Assert.AreEqual(fileLength, result.Bytes, result.Error?.Message); + Assert.AreEqual(etag, result.Etag, result.Error?.Message); } [Test, RetryWithDelay] public void TestUploadLarge() { // support uploading large image - - var largeFilePath = m_testLargeImagePath; - int fileLength = (int)new FileInfo(largeFilePath).Length; var result = m_cloudinary.UploadLarge(new ImageUploadParams() { - File = new FileDescription(largeFilePath), + File = new FileDescription(m_testLargeImagePath), Tags = m_apiTag }, TEST_CHUNK_SIZE); - Assert.AreEqual(fileLength, result.Bytes, result.Error?.Message); + AssertUploadLarge(result); } [Test, RetryWithDelay] public async Task TestUploadLargeAutoFilesAsync() { - // support asynchronous uploading large raw files - var largeFilePath = m_testLargeImagePath; - int largeFileLength = (int)new FileInfo(largeFilePath).Length; - var uploadParams = new AutoUploadParams() { - File = new FileDescription(largeFilePath), + File = new FileDescription(m_testLargeImagePath), Tags = m_apiTag }; var result = await m_cloudinary.UploadLargeAsync(uploadParams, TEST_CHUNK_SIZE); - AssertUploadLarge(result, largeFileLength); + AssertUploadLarge(result); Assert.AreEqual("image", result.ResourceType); } @@ -662,9 +668,6 @@ public async Task TestUploadLargeAutoFilesAsync() [Test, RetryWithDelay] public void TestUploadChunkSingleStream() { - var largeFilePath = m_testLargeImagePath; - var largeFileLength = (int)new FileInfo(largeFilePath).Length; - ImageUploadResult result = null; using (var currChunk = new MemoryStream()) @@ -677,7 +680,7 @@ public void TestUploadChunkSingleStream() var buffer = new byte[TEST_CHUNK_SIZE]; - using (var source = File.Open(largeFilePath, FileMode.Open)) + using (var source = File.Open(m_testLargeImagePath, FileMode.Open)) { int read; while ((read = source.Read(buffer, 0, buffer.Length)) > 0) @@ -693,16 +696,13 @@ public void TestUploadChunkSingleStream() } } - AssertUploadLarge(result, largeFileLength); + AssertUploadLarge(result); Assert.AreEqual("image", result?.ResourceType); } [Test, RetryWithDelay] public async Task TestUploadChunkMultipleStreamsCustomOffsetAsync() { - var largeFilePath = m_testLargeImagePath; - var largeFileLength = (int)new FileInfo(largeFilePath).Length; - ImageUploadResult result = null; var uploadParams = new ImageUploadParams() @@ -714,7 +714,7 @@ public async Task TestUploadChunkMultipleStreamsCustomOffsetAsync() var buffer = new byte[TEST_CHUNK_SIZE]; - using (var source = File.Open(largeFilePath, FileMode.Open)) + using (var source = File.Open(m_testLargeImagePath, FileMode.Open)) { int read; while ((read = source.Read(buffer, 0, buffer.Length)) > 0) @@ -727,19 +727,16 @@ public async Task TestUploadChunkMultipleStreamsCustomOffsetAsync() } } - AssertUploadLarge(result, largeFileLength); + AssertUploadLarge(result); Assert.AreEqual("image", result?.ResourceType); } [Test, RetryWithDelay] public void TestUploadChunkMultipleFileParts() { - var largeFilePath = m_testLargeImagePath; - var largeFileLength = (int)new FileInfo(largeFilePath).Length; - ImageUploadResult result = null; - var fileChunks = SplitFile(largeFilePath, TEST_CHUNK_SIZE, "multiple"); + var fileChunks = SplitFile(m_testLargeImagePath, TEST_CHUNK_SIZE, "multiple"); var uploadParams = new ImageUploadParams() { @@ -773,17 +770,14 @@ public void TestUploadChunkMultipleFileParts() } } - AssertUploadLarge(result, largeFileLength); + AssertUploadLarge(result); Assert.AreEqual("image", result?.ResourceType); } [Test, RetryWithDelay] public void TestUploadChunkMultipleFilePartsInParallel() { - var largeFilePath = m_testLargeImagePath; - var largeFileLength = (int)new FileInfo(largeFilePath).Length; - - var fileChunks = SplitFile(largeFilePath, TEST_CHUNK_SIZE, "multiple_parallel"); + var fileChunks = SplitFile(m_testLargeImagePath, TEST_CHUNK_SIZE, "multiple_parallel"); var uploadParams = new RawUploadParams() { @@ -820,7 +814,7 @@ public void TestUploadChunkMultipleFilePartsInParallel() var uploadResult = resultCollection.FirstOrDefault(r => r.AssetId != null); - AssertUploadLarge(uploadResult, largeFileLength); + AssertUploadLarge(uploadResult); Assert.AreEqual("raw", uploadResult?.ResourceType); } diff --git a/CloudinaryDotNet/Core/LimitedStream.cs b/CloudinaryDotNet/Core/LimitedStream.cs index a4af1c38..81d95e09 100644 --- a/CloudinaryDotNet/Core/LimitedStream.cs +++ b/CloudinaryDotNet/Core/LimitedStream.cs @@ -12,6 +12,7 @@ internal class LimitedStream : Stream private readonly Stream originalStream; private long remainingBytes; private long startOffset; + private long currOffset; /// /// Initializes a new instance of the class. @@ -24,7 +25,7 @@ public LimitedStream(Stream stream, long offset, long maxBytes) { originalStream = stream ?? throw new ArgumentNullException(nameof(stream)); remainingBytes = maxBytes; - startOffset = offset; + startOffset = currOffset = offset; if (!stream.CanSeek) { @@ -64,9 +65,11 @@ public override long Position public override int Read(byte[] buffer, int offset, int count) { // make sure stream is not moved around. - originalStream.Seek(startOffset, SeekOrigin.Begin); + originalStream.Seek(currOffset, SeekOrigin.Begin); var bytesRead = originalStream.Read(buffer, offset, (int)Math.Min(count, remainingBytes)); + + currOffset += bytesRead; remainingBytes -= bytesRead; return bytesRead;