/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.S3.Transfer;
using Amazon.S3.Util;
using Amazon.Util;
using AWSSDK_DotNet.IntegrationTests.Utils;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace AWSSDK_DotNet.IntegrationTests.Tests.S3
{
///
/// Integration tests for the TransferUtility upload operations on S3 bucket with object lock and data governance enabled.
///
[TestClass]
public class TransferUtilityObjectLockMD5Tests : TestBase
{
private static string bucketName;
[ClassInitialize()]
public static void Initialize(TestContext a)
{
CreateBucketWithObjectLockConfiguration();
}
[ClassCleanup]
public static void ClassCleanup()
{
DeleteBucketObjectsIncludingLocked(Client, bucketName);
AmazonS3Util.DeleteS3BucketWithObjects(Client, bucketName);
BaseClean();
}
[TestMethod]
[TestCategory("S3")]
public void TestMultipartUploadStreamViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 7000000);
var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests)),
CalculateContentMD5Header = true,
InputStream = contentStream
};
transfer.Upload(uploadRequest);
using (var getResponse = Client.GetObject(bucketName, uploadRequest.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(content, getBody);
}
}
[TestMethod]
[TestCategory("S3")]
public void TestMultipartUploadFileViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 7000000);
var key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests));
var filePath = Path.Combine(Path.GetTempPath(), key + ".txt");
// Create the file
using (StreamWriter writer = File.CreateText(filePath))
{
writer.Write(content);
}
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = key,
CalculateContentMD5Header = true,
FilePath = filePath
};
transfer.Upload(uploadRequest);
using (var getResponse = Client.GetObject(bucketName, uploadRequest.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(content, getBody);
}
}
[TestMethod]
[TestCategory("S3")]
[ExpectedException(typeof(AmazonS3Exception), "Content-MD5 HTTP header is required for Put Part requests with Object Lock parameters")]
public void TestMultipartUploadFileFailViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 7000000);
var key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests));
var filePath = Path.Combine(Path.GetTempPath(), key + ".txt");
// Create the file
using (StreamWriter writer = File.CreateText(filePath))
{
writer.Write(content);
}
// Do not set CalculateContentMD5Header as true which should cause upload to fail.
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = key,
FilePath = filePath
};
transfer.Upload(uploadRequest);
}
[TestMethod]
[TestCategory("S3")]
[ExpectedException(typeof(AmazonS3Exception), "Content-MD5 HTTP header is required for Put Part requests with Object Lock parameters")]
public void TestSimpleUploadFileFailViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 2000000);
var key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests));
var filePath = Path.Combine(Path.GetTempPath(), key + ".txt");
// Create the file
using (StreamWriter writer = File.CreateText(filePath))
{
writer.Write(content);
}
// Do not set CalculateContentMD5Header as true which should cause upload to fail.
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = key,
FilePath = filePath
};
transfer.Upload(uploadRequest);
}
[TestMethod]
[TestCategory("S3")]
[ExpectedException(typeof(AmazonS3Exception), "Content-MD5 HTTP header is required for Put Part requests with Object Lock parameters")]
public void TestMultipartUploadStreamFailViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 7000000);
var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
// Do not set CalculateContentMD5Header as true which should cause upload to fail.
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests)),
InputStream = contentStream
};
transfer.Upload(uploadRequest);
}
[TestMethod]
[TestCategory("S3")]
[ExpectedException(typeof(AmazonS3Exception), "Content-MD5 HTTP header is required for Put Part requests with Object Lock parameters")]
public void TestSimpleUploadStreamFailViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 2000000);
var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
// Do not set CalculateContentMD5Header as true which should cause upload to fail.
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests)),
InputStream = contentStream
};
transfer.Upload(uploadRequest);
}
[TestMethod]
[TestCategory("S3")]
public void TestSimpleUploadStreamViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 2000000);
var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests)),
CalculateContentMD5Header = true,
InputStream = contentStream,
};
transfer.Upload(uploadRequest);
using (var getResponse = Client.GetObject(bucketName, uploadRequest.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(content, getBody);
}
}
[TestMethod]
[TestCategory("S3")]
public void TestSimpleUploadStreamViaTransferUtility_ExplicitMD5()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 2000000);
var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(content));
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests)),
CalculateContentMD5Header = true,
InputStream = contentStream,
};
uploadRequest.Headers.ContentMD5 = AWSSDKUtils.GenerateMD5ChecksumForStream(contentStream);
transfer.Upload(uploadRequest);
using (var getResponse = Client.GetObject(bucketName, uploadRequest.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(content, getBody);
}
}
[TestMethod]
[TestCategory("S3")]
public void TestSimpleUploadFileViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 2000000);
var key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests));
var filePath = Path.Combine(Path.GetTempPath(), key + ".txt");
// Create the file
using (StreamWriter writer = File.CreateText(filePath))
{
writer.Write(content);
}
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = key,
CalculateContentMD5Header = true,
FilePath = filePath
};
transfer.Upload(uploadRequest);
using (var getResponse = Client.GetObject(bucketName, uploadRequest.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(content, getBody);
}
}
[TestMethod]
[TestCategory("S3")]
public void TestSimpleUploadFileViaTransferUtility_ExplicitMD5()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 2000000);
var key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests));
var filePath = Path.Combine(Path.GetTempPath(), key + ".txt");
// Create the file
using (StreamWriter writer = File.CreateText(filePath))
{
writer.Write(content);
}
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = key,
CalculateContentMD5Header = true,
FilePath = filePath
};
using (FileStream fileStream = File.OpenRead(filePath))
{
uploadRequest.Headers.ContentMD5 = AWSSDKUtils.GenerateMD5ChecksumForStream(fileStream);
}
transfer.Upload(uploadRequest);
using (var getResponse = Client.GetObject(bucketName, uploadRequest.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(content, getBody);
}
}
[TestMethod]
[TestCategory("S3")]
public void TestUploadDirectoryViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var directoryKey = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests));
var directoryPath = Path.Combine(Path.GetTempPath(), directoryKey);
Dictionary filesWithSize = new Dictionary() {
{ directoryKey + "_1.txt", 7000000}, // MultipartUpload
{ directoryKey + "_2.txt", 2000000}, // SimpleUpload
{ directoryKey + "_3.txt", 4000000}, // SimpleUpload
};
// Create directory with files.
Directory.CreateDirectory(directoryPath);
foreach (var file in filesWithSize)
{
var filePath = Path.Combine(directoryPath, file.Key);
var content = new string('a', file.Value);
// Create the file
using (StreamWriter writer = File.CreateText(filePath))
{
writer.Write(content);
}
}
var uploadDirectoryRequest = new TransferUtilityUploadDirectoryRequest
{
BucketName = bucketName,
Directory = directoryPath,
CalculateContentMD5Header = true
};
transfer.UploadDirectory(uploadDirectoryRequest);
// Verify the files
foreach (var file in filesWithSize)
{
using (var getResponse = Client.GetObject(bucketName, file.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(new string('a', file.Value), getBody);
}
}
}
[TestMethod]
[TestCategory("S3")]
public void TestSimpleUploadFileWithObjectLockViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 2000000);
var key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests));
var filePath = Path.Combine(Path.GetTempPath(), key + ".txt");
// NOTE: In ObjectLockMode.Compliance mode, a protected object version can't be deleted by any user, including the root user (refer https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock-overview.html#object-lock-retention-modes).
ObjectLockLegalHoldStatus desiredObjectLockLegalHoldStatus = ObjectLockLegalHoldStatus.Off;
ObjectLockMode desiredObjectLockMode = ObjectLockMode.Governance;
DateTime desiredObjectLockRetainUntilDate = DateTime.UtcNow.Date.AddDays(5);
// Create the file
using (StreamWriter writer = File.CreateText(filePath))
{
writer.Write(content);
}
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = key,
CalculateContentMD5Header = true,
FilePath = filePath,
ObjectLockLegalHoldStatus = desiredObjectLockLegalHoldStatus,
ObjectLockMode = desiredObjectLockMode,
ObjectLockRetainUntilDate = desiredObjectLockRetainUntilDate
};
transfer.Upload(uploadRequest);
using (var getResponse = Client.GetObject(bucketName, uploadRequest.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(content, getBody);
Assert.AreEqual(desiredObjectLockLegalHoldStatus, getResponse.ObjectLockLegalHoldStatus);
Assert.AreEqual(desiredObjectLockMode, getResponse.ObjectLockMode);
Assert.AreEqual(desiredObjectLockRetainUntilDate.Date, getResponse.ObjectLockRetainUntilDate.ToUniversalTime().Date);
}
}
[TestMethod]
[TestCategory("S3")]
public void TestUploadDirectoryWithObjectLockViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var directoryKey = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests));
var directoryPath = Path.Combine(Path.GetTempPath(), directoryKey);
Dictionary filesWithSize = new Dictionary() {
{ directoryKey + "_1.txt", 7000000}, // MultipartUpload
{ directoryKey + "_2.txt", 2000000}, // SimpleUpload
{ directoryKey + "_3.txt", 4000000}, // SimpleUpload
};
// NOTE: In ObjectLockMode.Compliance mode, a protected object version can't be deleted by any user, including the root user (refer https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock-overview.html#object-lock-retention-modes).
ObjectLockLegalHoldStatus desiredObjectLockLegalHoldStatus = ObjectLockLegalHoldStatus.Off;
ObjectLockMode desiredObjectLockMode = ObjectLockMode.Governance;
DateTime desiredObjectLockRetainUntilDate = DateTime.UtcNow.Date.AddDays(5);
// Create directory with files.
Directory.CreateDirectory(directoryPath);
foreach (var file in filesWithSize)
{
var filePath = Path.Combine(directoryPath, file.Key);
var content = new string('a', file.Value);
// Create the file
using (StreamWriter writer = File.CreateText(filePath))
{
writer.Write(content);
}
}
var uploadDirectoryRequest = new TransferUtilityUploadDirectoryRequest
{
BucketName = bucketName,
Directory = directoryPath,
CalculateContentMD5Header = true,
ObjectLockLegalHoldStatus = desiredObjectLockLegalHoldStatus,
ObjectLockMode = desiredObjectLockMode,
ObjectLockRetainUntilDate = desiredObjectLockRetainUntilDate
};
transfer.UploadDirectory(uploadDirectoryRequest);
// Verify the files
foreach (var file in filesWithSize)
{
using (var getResponse = Client.GetObject(bucketName, file.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(new string('a', file.Value), getBody);
Assert.AreEqual(desiredObjectLockLegalHoldStatus, getResponse.ObjectLockLegalHoldStatus);
Assert.AreEqual(desiredObjectLockMode, getResponse.ObjectLockMode);
Assert.AreEqual(desiredObjectLockRetainUntilDate.Date, getResponse.ObjectLockRetainUntilDate.ToUniversalTime().Date);
}
}
}
[TestMethod]
[TestCategory("S3")]
public void TestMultipartUploadFileWithObjectLockViaTransferUtility()
{
var transferConfig = new TransferUtilityConfig { MinSizeBeforePartUpload = 6000000 };
var transfer = new TransferUtility(Client, transferConfig);
var content = new string('a', 7000000);
var key = UtilityMethods.GenerateName(nameof(ObjectLockConfigurationTests));
var filePath = Path.Combine(Path.GetTempPath(), key + ".txt");
// NOTE: In ObjectLockMode.Compliance mode, a protected object version can't be deleted by any user, including the root user (refer https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock-overview.html#object-lock-retention-modes).
ObjectLockLegalHoldStatus desiredObjectLockLegalHoldStatus = ObjectLockLegalHoldStatus.Off;
ObjectLockMode desiredObjectLockMode = ObjectLockMode.Governance;
DateTime desiredObjectLockRetainUntilDate = DateTime.UtcNow.Date.AddDays(5);
// Create the file
using (StreamWriter writer = File.CreateText(filePath))
{
writer.Write(content);
}
var uploadRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
Key = key,
CalculateContentMD5Header = true,
FilePath = filePath,
ObjectLockLegalHoldStatus = desiredObjectLockLegalHoldStatus,
ObjectLockMode = desiredObjectLockMode,
ObjectLockRetainUntilDate = desiredObjectLockRetainUntilDate
};
transfer.Upload(uploadRequest);
using (var getResponse = Client.GetObject(bucketName, uploadRequest.Key))
{
var getBody = new StreamReader(getResponse.ResponseStream).ReadToEnd();
Assert.AreEqual(content, getBody);
Assert.AreEqual(desiredObjectLockLegalHoldStatus, getResponse.ObjectLockLegalHoldStatus);
Assert.AreEqual(desiredObjectLockMode, getResponse.ObjectLockMode);
Assert.AreEqual(desiredObjectLockRetainUntilDate.Date, getResponse.ObjectLockRetainUntilDate.ToUniversalTime().Date);
}
}
private static void CreateBucketWithObjectLockConfiguration()
{
bucketName = S3TestUtils.CreateBucketWithWait(Client, new PutBucketRequest
{
ObjectLockEnabledForBucket = true,
});
var objectLockConfiguration = new ObjectLockConfiguration();
objectLockConfiguration.ObjectLockEnabled = ObjectLockEnabled.Enabled;
objectLockConfiguration.Rule = new ObjectLockRule
{
DefaultRetention = new DefaultRetention
{
Days = 1,
Mode = ObjectLockRetentionMode.Governance
}
};
var putRequest = new PutObjectLockConfigurationRequest
{
BucketName = bucketName,
RequestPayer = RequestPayer.Requester,
ObjectLockConfiguration = objectLockConfiguration
};
var putResponse = Client.PutObjectLockConfiguration(putRequest);
}
private static void DeleteBucketObjectsIncludingLocked(IAmazonS3 s3Client, string bucketName)
{
var listVersionsRequest = new ListVersionsRequest
{
BucketName = bucketName
};
ListVersionsResponse listVersionsResponse;
// Iterate through the objects in the bucket and delete them.
do
{
// List all the versions of all the objects in the bucket.
listVersionsResponse = s3Client.ListVersions(listVersionsRequest);
if (listVersionsResponse.Versions.Count == 0)
{
// If the bucket has no objects break the loop.
break;
}
var keyVersionList = new List(listVersionsResponse.Versions.Count);
for (int index = 0; index < listVersionsResponse.Versions.Count; index++)
{
keyVersionList.Add(new KeyVersion
{
Key = listVersionsResponse.Versions[index].Key,
VersionId = listVersionsResponse.Versions[index].VersionId
});
}
try
{
// Delete the current set of objects.
var deleteObjectsResponse = s3Client.DeleteObjects(new DeleteObjectsRequest
{
BucketName = bucketName,
Objects = keyVersionList,
BypassGovernanceRetention = true
});
}
catch
{
}
// Set the markers to get next set of objects from the bucket.
listVersionsRequest.KeyMarker = listVersionsResponse.NextKeyMarker;
listVersionsRequest.VersionIdMarker = listVersionsResponse.NextVersionIdMarker;
}
// Continue listing objects and deleting them until the bucket is empty.
while (listVersionsResponse.IsTruncated);
}
}
}