/* * 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 System; using System.Linq; using Amazon; using Amazon.Runtime; using Amazon.Runtime.CredentialManagement; using Amazon.Runtime.Internal; using Amazon.Util.Internal; using AWSSDK.UnitTests.Custom.Net45.Custom.Runtime; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; namespace AWSSDK.UnitTests { [TestClass] public class DefaultConfigurationProviderTests { // ARRANGE private readonly IDefaultConfiguration[] _fakeDefaultConfigurations = new[] { // use different TimeToFirstByteTimeout values to have enough fidelity // to distinguish between Default Configurations new DefaultConfiguration { Name = DefaultConfigurationMode.CrossRegion, TimeToFirstByteTimeout = TimeSpan.FromMilliseconds(10) }, new DefaultConfiguration { Name = DefaultConfigurationMode.InRegion, TimeToFirstByteTimeout = TimeSpan.FromMilliseconds(200) }, new DefaultConfiguration { Name = DefaultConfigurationMode.Mobile, TimeToFirstByteTimeout = TimeSpan.FromMilliseconds(3000) }, new DefaultConfiguration { Name = DefaultConfigurationMode.Legacy, TimeToFirstByteTimeout = TimeSpan.FromMilliseconds(40000) } }; /// /// Validates that will follow /// the following order: /// 1. Client Config /// 2. Environment Variable /// 3. Shared Config/Credential File /// [TestMethod] [TestCategory("UnitTest")] [TestCategory("Runtime")] [DataTestMethod] // Client Config wins [DataRow( DefaultConfigurationMode.CrossRegion, DefaultConfigurationMode.InRegion, DefaultConfigurationMode.Mobile, DefaultConfigurationMode.CrossRegion)] [DataRow( DefaultConfigurationMode.CrossRegion, null, null, DefaultConfigurationMode.CrossRegion)] // Environment Variable wins [DataRow( null, DefaultConfigurationMode.InRegion, DefaultConfigurationMode.Mobile, DefaultConfigurationMode.InRegion)] [DataRow( null, DefaultConfigurationMode.InRegion, null, DefaultConfigurationMode.InRegion)] // Shared Config/Credential wins [DataRow( null, null, DefaultConfigurationMode.Mobile, DefaultConfigurationMode.Mobile)] // Legacy (default) wins [DataRow( null, null, null, DefaultConfigurationMode.Legacy)] public void OrderOfOperationsTest( DefaultConfigurationMode? clientConfigDefaultMode, DefaultConfigurationMode? environmentVariableDefaultMode, DefaultConfigurationMode? sharedConfigDefaultMode, DefaultConfigurationMode expectedDefaultMode) { // ARRANGE var mockEnvironmentVariableProvider = BuildEnvironmentVariableMock(environmentVariableDefaultMode); var mockAutoModeResolver = new Mock(); var clientConfig = new TestClientConfig( new DefaultConfigurationProvider( mockEnvironmentVariableProvider.Object, mockAutoModeResolver.Object, _fakeDefaultConfigurations)); if (clientConfigDefaultMode.HasValue) clientConfig.DefaultConfigurationMode = clientConfigDefaultMode.Value; var sharedConfigFile = "[default]\r\n" + $"defaults_mode={sharedConfigDefaultMode?.ToString()}"; TimeSpan? actualTimeout; using (new FallbackFactoryTest.FallbackFactoryTestFixture(sharedConfigFile, "default")) { // ACT actualTimeout = clientConfig.Timeout; } // ASSERT var expectedMode = _fakeDefaultConfigurations.First(x => x.Name == expectedDefaultMode); Assert.AreEqual(expectedMode.TimeToFirstByteTimeout, actualTimeout); } /// /// Make sure wan error is thrown if /// has an invalid /// [TestMethod] public void UnknownDefaultConfigurationModeThrowsAnError() { // ARRANGE var mockEnvironmentVariableProvider = new Mock(); var mockAutoModeResolver = new Mock(); var clientConfig = new TestClientConfig( new DefaultConfigurationProvider( mockEnvironmentVariableProvider.Object, mockAutoModeResolver.Object, _fakeDefaultConfigurations)); var sharedConfigFile = "[default]\r\n" + "defaults_mode=NON-EXISTENT-DEFAULT-CONFIG-MODE"; Exception expectedException = null; TimeSpan? actualTimeout = null; try { using (new FallbackFactoryTest.FallbackFactoryTestFixture(sharedConfigFile, "default")) { // ACT actualTimeout = clientConfig.Timeout; } } catch (Exception e) { expectedException = e; } // ASSERT Assert.IsNotNull(expectedException); Assert.IsInstanceOfType(expectedException, typeof(AmazonClientException)); Assert.IsTrue(expectedException.Message.StartsWith("Failed to find requested Default Configuration Mode")); Assert.IsNull(actualTimeout); } [TestMethod] public void DefaultConfigurationAutoModeIsCachedWhenPassedInMethodParameter() { // validate behavior by confirming IDefaultConfigurationAutoModeResolver is only called once // ARRANGE var mockEnvironmentVariableProvider = new Mock(); var mockAutoModeResolver = new Mock(); mockAutoModeResolver .Setup(x => x.Resolve(It.IsAny(), It.IsAny>())) .Returns(_fakeDefaultConfigurations[0].Name); var clientConfig = new TestClientConfig( new DefaultConfigurationProvider( mockEnvironmentVariableProvider.Object, mockAutoModeResolver.Object, _fakeDefaultConfigurations)); clientConfig.DefaultConfigurationMode = DefaultConfigurationMode.Auto; // ACT // load properties - this will cause ClientConfig // to invoke DefaultConfigurationProvider multiple times var timeout = clientConfig.Timeout; var retryMode = clientConfig.RetryMode; var timeout2 = clientConfig.Timeout; // ASSERT mockAutoModeResolver .Verify( x => x.Resolve(It.IsAny(), It.IsAny>()), // if we're caching correctly, mockAutoModeResolver.Resolve should only be called once Times.Once); } [TestMethod] public void DefaultConfigurationAutoModeIsCachedWhenSpecifiedInEnvironmentVariable() { // validate behavior by confirming IDefaultConfigurationAutoModeResolver is only called once // ARRANGE var mockEnvironmentVariableProvider = BuildEnvironmentVariableMock(DefaultConfigurationMode.Auto); var mockAutoModeResolver = new Mock(); mockAutoModeResolver .Setup(x => x.Resolve(It.IsAny(), It.IsAny>())) .Returns(_fakeDefaultConfigurations[0].Name); var clientConfig = new TestClientConfig( new DefaultConfigurationProvider( mockEnvironmentVariableProvider.Object, mockAutoModeResolver.Object, _fakeDefaultConfigurations)); // ACT // load properties - this will cause ClientConfig // to invoke DefaultConfigurationProvider multiple times var timeout = clientConfig.Timeout; var retryMode = clientConfig.RetryMode; var timeout2 = clientConfig.Timeout; // ASSERT mockAutoModeResolver .Verify( x => x.Resolve(It.IsAny(), It.IsAny>()), // if we're caching correctly, mockAutoModeResolver.Resolve should only be called once Times.Once); } [TestMethod] public void DefaultConfigurationAutoModeIsRefreshedIfRegionChangesWhenPassedInMethodParameter() { // validate behavior by confirming IDefaultConfigurationAutoModeResolver is called once per RegionEndpoint // ARRANGE var mockEnvironmentVariableProvider = BuildEnvironmentVariableMock(); var mockAutoModeResolver = new Mock(); mockAutoModeResolver .Setup(x => x.Resolve(It.IsAny(), It.IsAny>())) .Returns(_fakeDefaultConfigurations[0].Name); var clientConfig = new TestClientConfig( new DefaultConfigurationProvider( mockEnvironmentVariableProvider.Object, mockAutoModeResolver.Object, _fakeDefaultConfigurations)); clientConfig.DefaultConfigurationMode = DefaultConfigurationMode.Auto; // set initial RegionEndpoint clientConfig.RegionEndpoint = RegionEndpoint.APEast1; // ACT // load properties - this will cause ClientConfig // to invoke DefaultConfigurationProvider multiple times var timeout = clientConfig.Timeout; var retryMode = clientConfig.RetryMode; // change RegionEndpoint clientConfig.RegionEndpoint = RegionEndpoint.USWest2; var timeout2 = clientConfig.Timeout; var retryMode2 = clientConfig.RetryMode; // ASSERT mockAutoModeResolver .Verify( x => x.Resolve(It.IsAny(), It.IsAny>()), // if we're caching correctly, mockAutoModeResolver.Resolve should only be called once // per Region Endpoint change Times.Exactly(2)); } [TestMethod] public void DefaultConfigurationAutoModeIsRefreshedIfRegionChangesWhenSpecifiedInEnvironmentVariable() { // validate behavior by confirming IDefaultConfigurationAutoModeResolver is called once per RegionEndpoint // ARRANGE var mockEnvironmentVariableProvider = BuildEnvironmentVariableMock(DefaultConfigurationMode.Auto); var mockAutoModeResolver = new Mock(); mockAutoModeResolver .Setup(x => x.Resolve(It.IsAny(), It.IsAny>())) .Returns(_fakeDefaultConfigurations[0].Name); var clientConfig = new TestClientConfig( new DefaultConfigurationProvider( mockEnvironmentVariableProvider.Object, mockAutoModeResolver.Object, _fakeDefaultConfigurations)); // set initial RegionEndpoint clientConfig.RegionEndpoint = RegionEndpoint.APEast1; // ACT // load properties - this will cause ClientConfig // to invoke DefaultConfigurationProvider multiple times var timeout = clientConfig.Timeout; var retryMode = clientConfig.RetryMode; // change RegionEndpoint clientConfig.RegionEndpoint = RegionEndpoint.USWest2; var timeout2 = clientConfig.Timeout; var retryMode2 = clientConfig.RetryMode; // ASSERT mockAutoModeResolver .Verify( x => x.Resolve(It.IsAny(), It.IsAny>()), // if we're caching correctly, mockAutoModeResolver.Resolve should only be called once // per Region Endpoint change Times.Exactly(2)); } [TestMethod] public void DefaultConfigurationCanBeExplicitlySetEvenIfItsAlreadyCached() { // ARRANGE var environmentVariableDefaultMode = _fakeDefaultConfigurations[0]; var explicitlySetDefaultMode = _fakeDefaultConfigurations[1]; var mockEnvironmentVariableProvider = BuildEnvironmentVariableMock(environmentVariableDefaultMode.Name); var mockAutoModeResolver = new Mock(); var clientConfig = new TestClientConfig( new DefaultConfigurationProvider( mockEnvironmentVariableProvider.Object, mockAutoModeResolver.Object, _fakeDefaultConfigurations)); // ACT // retrieve timeout once (this will cause default configuration mode to be cached) var timeoutFromEnvironmentVariableDefaultMode = clientConfig.Timeout; // simulate user explicitly setting DefaultConfigurationMode clientConfig.DefaultConfigurationMode = explicitlySetDefaultMode.Name; // now reload timeout, to make sure we don't use the old cached value. var timeoutFromExplicitlySetDefaultMode = clientConfig.Timeout; // ASSERT Assert.AreEqual( environmentVariableDefaultMode.TimeToFirstByteTimeout, timeoutFromEnvironmentVariableDefaultMode); Assert.AreEqual( explicitlySetDefaultMode.TimeToFirstByteTimeout, timeoutFromExplicitlySetDefaultMode); } private Mock BuildEnvironmentVariableMock( DefaultConfigurationMode? awsDefaultModeValue = null) { var mockEnvironmentVariableProvider = new Mock(); mockEnvironmentVariableProvider .Setup(x => x.GetEnvironmentVariable(It.Is(e => e == "AWS_DEFAULTS_MODE"))) .Returns(awsDefaultModeValue?.ToString()); return mockEnvironmentVariableProvider; } } }