/* * 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.Runtime; using Amazon.Runtime.Internal.Util; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; using System.IO; using System.Text; namespace AWSSDK.UnitTests { /// /// Tests for the trailing header stream wrapper /// [TestClass] public class TrailingHeadersWrapperStreamTests { private const string expectedSHA1Content = "B\r\n" + "Hello world\r\n" + "0\r\n" + "x-amz-checksum-sha1:e1AsOh9IyGCa4hLN+2Od7jlnP14=\r\n" + "\r\n"; private const string expectedSHA256Content = "B\r\n" + "Hello world\r\n" + "0\r\n" + "x-amz-checksum-sha256:ZOyIygCyaOW6GjVnihtTFtIS9PNmskdyMlNKiuyjfzw=\r\n" + "\r\n"; private const string expectedCRC32Content = "B\r\n" + "Hello world\r\n" + "0\r\n" + "x-amz-checksum-crc32:i9aeUg==\r\n" + "\r\n"; private const string expectedCRC32CContent = "B\r\n" + "Hello world\r\n" + "0\r\n" + "x-amz-checksum-crc32c:crUfeA==\r\n" + "\r\n"; /// /// Tests a given trailing checksum for an unsigned stream /// [DataTestMethod] [DataRow("x-amz-checksum-sha1", CoreChecksumAlgorithm.SHA1, expectedSHA1Content)] [DataRow("x-amz-checksum-sha256", CoreChecksumAlgorithm.SHA256, expectedSHA256Content)] [DataRow("x-amz-checksum-crc32", CoreChecksumAlgorithm.CRC32, expectedCRC32Content)] [DataRow("x-amz-checksum-crc32c", CoreChecksumAlgorithm.CRC32C, expectedCRC32CContent)] public void TestTrailingChecksum(string checksumKey, CoreChecksumAlgorithm algorithm, string expectedContent) { var contentStream = new MemoryStream(Encoding.Default.GetBytes("Hello world")); var trailingHeaders = new Dictionary { {checksumKey, "" } // checksum will be calculated as the stream is read then replaced at the end }; var wrappedStream = new TrailingHeadersWrapperStream(contentStream, trailingHeaders, algorithm); var actualContent = new StreamReader(wrappedStream).ReadToEnd(); Assert.AreEqual(expectedContent.Length, wrappedStream.Length); Assert.AreEqual(expectedContent, actualContent); } /// /// Read the stream with a small buffer, to test the index state between reads /// [TestMethod] public void SmallBuffer() { var contentStream = new MemoryStream(Encoding.Default.GetBytes("Hello world")); var trailingHeaders = new Dictionary { {"x-amz-checksum-sha256", "" } // checksum will be calculated as the stream is read then replaced at the end }; var wrappedStream = new TrailingHeadersWrapperStream(contentStream, trailingHeaders, CoreChecksumAlgorithm.SHA256); var bytesRead = -1; var bufferSize = 1; var buffer = new byte[bufferSize]; var outputAsString = ""; while (bytesRead != 0) { bytesRead = wrappedStream.Read(buffer, 0, bufferSize); outputAsString += Encoding.Default.GetString(buffer, 0, bytesRead); } var expectedContent = "B\r\n" + "Hello world\r\n" + "0\r\n" + "x-amz-checksum-sha256:ZOyIygCyaOW6GjVnihtTFtIS9PNmskdyMlNKiuyjfzw=\r\n" + "\r\n"; Assert.AreEqual(expectedContent.Length, wrappedStream.Length); Assert.AreEqual(expectedContent, outputAsString); } /// /// Test reading the stream with a larger underlying stream /// [TestMethod] public void LargeData() { var data = new string('a', 100000); var contentStream = new MemoryStream(Encoding.Default.GetBytes(data)); var trailingHeaders = new Dictionary { {"x-amz-checksum-sha256", "" } // checksum will be calculated as the stream is read then replaced at the end }; var wrappedStream = new TrailingHeadersWrapperStream(contentStream, trailingHeaders, CoreChecksumAlgorithm.SHA256); var actualContent = new StreamReader(wrappedStream).ReadToEnd(); var expectedContent = "186A0\r\n" + $"{data}\r\n" + "0\r\n" + "x-amz-checksum-sha256:bRzyLXzAmwhd/CXuGh864CZYBMYHvCB0rSU7zIL9ge4=\r\n" + "\r\n"; Assert.AreEqual(expectedContent.Length, wrappedStream.Length); Assert.AreEqual(expectedContent, actualContent); } /// /// Tests wrapping a stream with trailing headers that are not a checksum /// [TestMethod] public void NonChecksumTrailingHeaders() { var contentStream = new MemoryStream(Encoding.Default.GetBytes("Hello world")); var trailingHeaders = new Dictionary { {"header-a", "value-a" }, {"header-b", "value-b" } }; var wrappedStream = new TrailingHeadersWrapperStream(contentStream, trailingHeaders); var actualContent = new StreamReader(wrappedStream).ReadToEnd(); var expectedContent = "B\r\n" + "Hello world\r\n" + "0\r\n" + "header-a:value-a\r\n" + "header-b:value-b\r\n" + "\r\n"; Assert.AreEqual(expectedContent.Length, wrappedStream.Length); Assert.AreEqual(expectedContent, actualContent); } /// /// Tests wrapping a stream with multiple trailing headers, /// one set up front and one checksum that is calculated while /// reading the stream. /// [TestMethod] public void ChecksumAndOtherTrailingHeaders() { var contentStream = new MemoryStream(Encoding.Default.GetBytes("Hello world")); var trailingHeaders = new Dictionary { {"header-a", "value-a" }, {"header-b", "value-b" }, {"x-amz-checksum-sha256", "" } // checksum will be calculated as the stream is read then replaced at the end }; var wrappedStream = new TrailingHeadersWrapperStream(contentStream, trailingHeaders, CoreChecksumAlgorithm.SHA256); var actualContent = new StreamReader(wrappedStream).ReadToEnd(); var expectedContent = "B\r\n" + "Hello world\r\n" + "0\r\n" + "header-a:value-a\r\n" + "header-b:value-b\r\n" + "x-amz-checksum-sha256:ZOyIygCyaOW6GjVnihtTFtIS9PNmskdyMlNKiuyjfzw=\r\n" + "\r\n"; Assert.AreEqual(expectedContent.Length, wrappedStream.Length); Assert.AreEqual(expectedContent, actualContent); } } }