diff --git a/Runtime.sln b/Runtime.sln index 5a9da54f..dc7b795c 100644 --- a/Runtime.sln +++ b/Runtime.sln @@ -98,6 +98,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Web.WebPages.OAut EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Web.WebPages.OAuth.Test", "test\Microsoft.Web.WebPages.OAuth.Test\Microsoft.Web.WebPages.OAuth.Test.csproj", "{694C6EDF-EA52-438F-B745-82B025ECC0E7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Web.Http.SelfHost.Test", "test\System.Web.Http.SelfHost.Test\System.Web.Http.SelfHost.Test.csproj", "{7F29EE87-6A63-43C6-B7FF-74DD06815830}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CodeCov|Any CPU = CodeCov|Any CPU @@ -1014,6 +1016,26 @@ Global {694C6EDF-EA52-438F-B745-82B025ECC0E7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {694C6EDF-EA52-438F-B745-82B025ECC0E7}.Release|Mixed Platforms.Build.0 = Release|Any CPU {694C6EDF-EA52-438F-B745-82B025ECC0E7}.Release|x86.ActiveCfg = Release|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCov|Any CPU.ActiveCfg = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCov|Any CPU.Build.0 = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCov|Mixed Platforms.ActiveCfg = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCov|Mixed Platforms.Build.0 = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCov|x86.ActiveCfg = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCoverage|Mixed Platforms.ActiveCfg = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCoverage|Mixed Platforms.Build.0 = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.CodeCoverage|x86.ActiveCfg = CodeCoverage|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Debug|x86.ActiveCfg = Debug|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Release|Any CPU.Build.0 = Release|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7F29EE87-6A63-43C6-B7FF-74DD06815830}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1064,5 +1086,6 @@ Global {EA62944F-BD25-4730-9405-9BE8FF5BEACD} = {C40883CD-366D-4534-8B58-3EA0D13136DF} {7B8601F8-8D1F-4B9C-8C20-772B673A2FA6} = {C40883CD-366D-4534-8B58-3EA0D13136DF} {694C6EDF-EA52-438F-B745-82B025ECC0E7} = {C40883CD-366D-4534-8B58-3EA0D13136DF} + {7F29EE87-6A63-43C6-B7FF-74DD06815830} = {C40883CD-366D-4534-8B58-3EA0D13136DF} EndGlobalSection EndGlobal diff --git a/src/System.Web.Http.Common/Error.cs b/src/System.Web.Http.Common/Error.cs index 97c71257..d632f87a 100644 --- a/src/System.Web.Http.Common/Error.cs +++ b/src/System.Web.Http.Common/Error.cs @@ -25,7 +25,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with the provided properties and logs it with . + /// Creates an with the provided properties. /// /// A composite format string explaining the reason for the exception. /// An object array that contains zero or more objects to format. @@ -36,7 +36,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with the provided properties and logs it with . + /// Creates an with the provided properties. /// /// The name of the parameter that caused the current exception. /// A composite format string explaining the reason for the exception. @@ -48,7 +48,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with a message saying that the argument must be an "http" or "https" URI and logs it with . + /// Creates an with a message saying that the argument must be an "http" or "https" URI. /// /// The name of the parameter that caused the current exception. /// The value of the argument that causes this exception. @@ -59,7 +59,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with a message saying that the argument must be an absolute URI and logs it with . + /// Creates an with a message saying that the argument must be an absolute URI. /// /// The name of the parameter that caused the current exception. /// The value of the argument that causes this exception. @@ -82,7 +82,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with the provided properties and logs it with . + /// Creates an with the provided properties. /// /// The logged . [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "The purpose of this API is to return an error for properties")] @@ -92,7 +92,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with the provided properties and logs it with . + /// Creates an with the provided properties. /// /// The name of the parameter that caused the current exception. /// The logged . @@ -102,7 +102,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with the provided properties and logs it with . + /// Creates an with the provided properties. /// /// The name of the parameter that caused the current exception. /// A composite format string explaining the reason for the exception. @@ -114,7 +114,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with a default message and logs it with . + /// Creates an with a default message. /// /// The name of the parameter that caused the current exception. /// The logged . @@ -124,7 +124,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with the provided properties and logs it with . + /// Creates an with the provided properties. /// /// The name of the parameter that caused the current exception. /// The value of the argument that causes this exception. @@ -137,7 +137,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with a message saying that the argument must be greater than or equal to and logs it with . + /// Creates an with a message saying that the argument must be greater than or equal to . /// /// The name of the parameter that caused the current exception. /// The value of the argument that causes this exception. @@ -149,7 +149,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with a message saying that the argument must be less than or equal to and logs it with . + /// Creates an with a message saying that the argument must be less than or equal to . /// /// The name of the parameter that caused the current exception. /// The value of the argument that causes this exception. @@ -161,7 +161,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with a message saying that the key was not found and logs it with . + /// Creates an with a message saying that the key was not found. /// /// The logged . public static KeyNotFoundException KeyNotFound() @@ -170,7 +170,7 @@ namespace System.Web.Http.Common } /// - /// Creates an with a message saying that the key was not found and logs it with . + /// Creates an with a message saying that the key was not found. /// /// A composite format string explaining the reason for the exception. /// An object array that contains zero or more objects to format. @@ -181,7 +181,7 @@ namespace System.Web.Http.Common } /// - /// Creates an initialized according to guidelines and logs it with . + /// Creates an initialized according to guidelines. /// /// A composite format string explaining the reason for the exception. /// An object array that contains zero or more objects to format. @@ -193,7 +193,7 @@ namespace System.Web.Http.Common } /// - /// Creates an initialized with the provided parameters and logs it with . + /// Creates an initialized with the provided parameters. /// /// The logged . public static OperationCanceledException OperationCanceled() @@ -202,7 +202,7 @@ namespace System.Web.Http.Common } /// - /// Creates an initialized with the provided parameters and logs it with . + /// Creates an initialized with the provided parameters. /// /// A composite format string explaining the reason for the exception. /// An object array that contains zero or more objects to format. @@ -213,7 +213,7 @@ namespace System.Web.Http.Common } /// - /// Creates an and logs it with . + /// Creates an . /// /// The name of the parameter that caused the current exception. /// The value of the argument that failed. @@ -225,7 +225,7 @@ namespace System.Web.Http.Common } /// - /// Creates an and logs it with . + /// Creates an . /// /// A composite format string explaining the reason for the exception. /// An object array that contains zero or more objects to format. @@ -236,7 +236,7 @@ namespace System.Web.Http.Common } /// - /// Creates an and logs it with . + /// Creates an . /// /// Inner exception /// A composite format string explaining the reason for the exception. @@ -248,7 +248,7 @@ namespace System.Web.Http.Common } /// - /// Creates an and logs it with . + /// Creates an . /// /// A composite format string explaining the reason for the exception. /// An object array that contains zero or more objects to format. diff --git a/src/System.Web.Http.Common/Properties/SRResources.Designer.cs b/src/System.Web.Http.Common/Properties/SRResources.Designer.cs index 82dfb987..e7962545 100644 --- a/src/System.Web.Http.Common/Properties/SRResources.Designer.cs +++ b/src/System.Web.Http.Common/Properties/SRResources.Designer.cs @@ -79,7 +79,7 @@ namespace System.Web.Http.Common.Properties { } /// - /// Looks up a localized string similar to The argument '{0}' must be greater than or equal to {1}.. + /// Looks up a localized string similar to Value must be greater than or equal to {1}.. /// internal static string ArgumentMustBeGreaterThanOrEqualTo { get { @@ -88,7 +88,7 @@ namespace System.Web.Http.Common.Properties { } /// - /// Looks up a localized string similar to The argument '{0}' must be less than or equal to {1}.. + /// Looks up a localized string similar to Value must be less than or equal to {1}.. /// internal static string ArgumentMustBeLessThanOrEqualTo { get { diff --git a/src/System.Web.Http.Common/Properties/SRResources.resx b/src/System.Web.Http.Common/Properties/SRResources.resx index 14322733..92481d47 100644 --- a/src/System.Web.Http.Common/Properties/SRResources.resx +++ b/src/System.Web.Http.Common/Properties/SRResources.resx @@ -124,10 +124,10 @@ Unsupported URI scheme: '{0}'. The URI scheme must be either '{1}' or '{2}'. - The argument '{0}' must be greater than or equal to {1}. + Value must be greater than or equal to {1}. - The argument '{0}' must be less than or equal to {1}. + Value must be less than or equal to {1}. The argument '{0}' is null or empty. diff --git a/src/System.Web.Http.SelfHost/HttpSelfHostConfiguration.cs b/src/System.Web.Http.SelfHost/HttpSelfHostConfiguration.cs index 85603ce2..28d9ebcf 100644 --- a/src/System.Web.Http.SelfHost/HttpSelfHostConfiguration.cs +++ b/src/System.Web.Http.SelfHost/HttpSelfHostConfiguration.cs @@ -18,6 +18,9 @@ namespace System.Web.Http.SelfHost public class HttpSelfHostConfiguration : HttpConfiguration { private const int DefaultMaxConcurrentRequests = 100; + private const int DefaultMaxBufferSize = 64 * 1024; + private const int DefaultReceivedMessageSize = 64 * 1024; + private const int PendingContextFactor = 100; private const int MinConcurrentRequests = 1; private const int MinBufferSize = 0; @@ -28,15 +31,16 @@ namespace System.Web.Http.SelfHost private ServiceCredentials _credentials = new ServiceCredentials(); private bool _useWindowsAuth; private TransferMode _transferMode; - private int _maxBufferSize; - private long _maxReceivedMessageSize; + private int _maxBufferSize = DefaultMaxBufferSize; + private long _maxReceivedMessageSize = DefaultReceivedMessageSize; + private HostNameComparisonMode _hostNameComparisonMode; /// /// Initializes a new instance of the class. /// /// The base address. public HttpSelfHostConfiguration(string baseAddress) - : this(new Uri(baseAddress, UriKind.RelativeOrAbsolute)) + : this(CreateBaseAddress(baseAddress)) { } @@ -82,6 +86,7 @@ namespace System.Web.Http.SelfHost { throw Error.ArgumentTooSmall("value", value, MinConcurrentRequests); } + _maxConcurrentRequests = value; } } @@ -102,6 +107,20 @@ namespace System.Web.Http.SelfHost } } + /// + /// Specifies how the host name should be used in URI comparisons when dispatching an incoming message. + /// + public HostNameComparisonMode HostNameComparisonMode + { + get { return _hostNameComparisonMode; } + + set + { + HostNameComparisonModeHelper.Validate(value); + _hostNameComparisonMode = value; + } + } + /// /// Gets or sets the size of the max buffer. /// @@ -118,7 +137,6 @@ namespace System.Web.Http.SelfHost { throw Error.ArgumentTooSmall("value", value, MinBufferSize); } - _maxBufferSize = value; } } @@ -139,7 +157,6 @@ namespace System.Web.Http.SelfHost { throw Error.ArgumentTooSmall("value", value, MinReceivedMessageSize); } - _maxReceivedMessageSize = value; } } @@ -203,6 +220,8 @@ namespace System.Web.Http.SelfHost httpBinding.MaxBufferSize = MaxBufferSize; httpBinding.MaxReceivedMessageSize = MaxReceivedMessageSize; httpBinding.TransferMode = TransferMode; + httpBinding.HostNameComparisonMode = HostNameComparisonMode; + if (_baseAddress.Scheme == Uri.UriSchemeHttps) { // we need to use SSL @@ -232,7 +251,7 @@ namespace System.Web.Http.SelfHost } else if (_useWindowsAuth) { - if (httpBinding.Security == null) + if (httpBinding.Security == null || httpBinding.Security.Mode == HttpBindingSecurityMode.None) { // Basic over HTTP case, should we even allow this? httpBinding.Security = new HttpBindingSecurity() @@ -257,6 +276,16 @@ namespace System.Web.Http.SelfHost return bindingParameters; } + private static Uri CreateBaseAddress(string baseAddress) + { + if (baseAddress == null) + { + throw Error.ArgumentNull("baseAddress"); + } + + return new Uri(baseAddress, UriKind.RelativeOrAbsolute); + } + private static Uri ValidateBaseAddress(Uri baseAddress) { if (baseAddress == null) diff --git a/test/Microsoft.TestCommon/ExceptionAssertions.cs b/test/Microsoft.TestCommon/ExceptionAssertions.cs index b16e84d6..76a79b23 100644 --- a/test/Microsoft.TestCommon/ExceptionAssertions.cs +++ b/test/Microsoft.TestCommon/ExceptionAssertions.cs @@ -342,12 +342,14 @@ namespace Microsoft.TestCommon /// The name of the parameter that should throw the exception /// The exception message to verify /// Pass true to allow exceptions which derive from TException; pass false, otherwise + /// The actual value provided /// The exception that was thrown, when successful /// Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown - public static ArgumentOutOfRangeException ThrowsArgumentOutOfRange(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false) + public static ArgumentOutOfRangeException ThrowsArgumentOutOfRange(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false, object actualValue = null) { exceptionMessage = exceptionMessage != null - ? exceptionMessage + "\r\nParameter name: " + paramName + ? exceptionMessage + "\r\nParameter name: " + paramName + + (actualValue != null ? "\r\nActual value was " + actualValue.ToString() + "." : "") : exceptionMessage; var ex = Throws(testCode, exceptionMessage, allowDerivedExceptions); @@ -361,16 +363,17 @@ namespace Microsoft.TestCommon /// /// Verifies that the code throws an with the expected message that indicates that - /// the value must be greater than the given value. + /// the value must be greater than the given . /// /// A delegate to the code to be tested /// The name of the parameter that should throw the exception - /// The expected limit value. + /// The actual value provided. + /// The expected limit value. /// The exception that was thrown, when successful /// Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown - public static ArgumentOutOfRangeException ThrowsArgumentGreaterThan(Action testCode, string paramName, string value) + public static ArgumentOutOfRangeException ThrowsArgumentGreaterThan(Action testCode, string paramName, string minValue, object actualValue = null) { - return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be greater than {0}.", value)); + return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be greater than {0}.", minValue), false, actualValue); } /// @@ -379,40 +382,42 @@ namespace Microsoft.TestCommon /// /// A delegate to the code to be tested /// The name of the parameter that should throw the exception - /// The expected limit value. + /// The expected limit value. /// The exception that was thrown, when successful /// Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown - public static ArgumentOutOfRangeException ThrowsArgumentGreaterThanOrEqualTo(Action testCode, string paramName, string value) + public static ArgumentOutOfRangeException ThrowsArgumentGreaterThanOrEqualTo(Action testCode, string paramName, string minValue, object actualValue = null) { - return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be greater than or equal to {0}.", value)); + return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be greater than or equal to {0}.", minValue), false, actualValue); } /// /// Verifies that the code throws an with the expected message that indicates that - /// the value must be less than the given value. + /// the value must be less than the given . /// /// A delegate to the code to be tested /// The name of the parameter that should throw the exception - /// The expected limit value. + /// The actual value provided. + /// The expected limit value. /// The exception that was thrown, when successful /// Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown - public static ArgumentOutOfRangeException ThrowsArgumentLessThan(Action testCode, string paramName, string value) + public static ArgumentOutOfRangeException ThrowsArgumentLessThan(Action testCode, string paramName, string maxValue, object actualValue = null) { - return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be less than {0}.", value)); + return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be less than {0}.", maxValue), false, actualValue); } /// /// Verifies that the code throws an with the expected message that indicates that - /// the value must be less than or equal to the given value. + /// the value must be less than or equal to the given . /// /// A delegate to the code to be tested /// The name of the parameter that should throw the exception - /// The expected limit value. + /// The actual value provided. + /// The expected limit value. /// The exception that was thrown, when successful /// Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown - public static ArgumentOutOfRangeException ThrowsArgumentLessThanOrEqualTo(Action testCode, string paramName, string value) + public static ArgumentOutOfRangeException ThrowsArgumentLessThanOrEqualTo(Action testCode, string paramName, string maxValue, object actualValue = null) { - return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be less than or equal to {0}.", value)); + return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be less than or equal to {0}.", maxValue), false, actualValue); } /// diff --git a/test/Microsoft.TestCommon/ReflectionAssert.cs b/test/Microsoft.TestCommon/ReflectionAssert.cs index a2b3eb59..0f92d99e 100644 --- a/test/Microsoft.TestCommon/ReflectionAssert.cs +++ b/test/Microsoft.TestCommon/ReflectionAssert.cs @@ -61,6 +61,64 @@ namespace Microsoft.TestCommon } } + public void IntegerProperty(T instance, Expression> propertyGetter, TResult expectedDefaultValue, + TResult? minLegalValue, TResult? illegalLowerValue, + TResult? maxLegalValue, TResult? illegalUpperValue, + TResult roundTripTestValue) where TResult : struct + { + PropertyInfo property = GetPropertyInfo(propertyGetter); + Func getFunc = (obj) => (TResult)property.GetValue(obj, index: null); + Action setFunc = (obj, value) => property.SetValue(obj, value, index: null); + + Assert.Equal(expectedDefaultValue, getFunc(instance)); + + if (minLegalValue.HasValue) + { + TestPropertyValue(instance, getFunc, setFunc, minLegalValue.Value); + } + + if (maxLegalValue.HasValue) + { + TestPropertyValue(instance, getFunc, setFunc, maxLegalValue.Value); + } + + if (illegalLowerValue.HasValue) + { + Assert.ThrowsArgumentGreaterThanOrEqualTo(() => { setFunc(instance, illegalLowerValue.Value); }, "value", minLegalValue.Value.ToString(), illegalLowerValue.Value); + } + + if (illegalUpperValue.HasValue) + { + Assert.ThrowsArgumentLessThanOrEqualTo(() => { setFunc(instance, illegalLowerValue.Value); }, "value", maxLegalValue.Value.ToString(), illegalUpperValue.Value); + } + + TestPropertyValue(instance, getFunc, setFunc, roundTripTestValue); + } + + public void BooleanProperty(T instance, Expression> propertyGetter, bool expectedDefaultValue) + { + PropertyInfo property = GetPropertyInfo(propertyGetter); + Func getFunc = (obj) => (bool)property.GetValue(obj, index: null); + Action setFunc = (obj, value) => property.SetValue(obj, value, index: null); + + Assert.Equal(expectedDefaultValue, getFunc(instance)); + + TestPropertyValue(instance, getFunc, setFunc, !expectedDefaultValue); + } + + public void EnumProperty(T instance, Expression> propertyGetter, TResult expectedDefaultValue, TResult illegalValue, TResult roundTripTestValue) where TResult : struct + { + PropertyInfo property = GetPropertyInfo(propertyGetter); + Func getFunc = (obj) => (TResult)property.GetValue(obj, index: null); + Action setFunc = (obj, value) => property.SetValue(obj, value, index: null); + + Assert.Equal(expectedDefaultValue, getFunc(instance)); + + Assert.ThrowsInvalidEnumArgument(() => { setFunc(instance, illegalValue); }, "value", Convert.ToInt32(illegalValue), typeof(TResult)); + + TestPropertyValue(instance, getFunc, setFunc, roundTripTestValue); + } + public void StringProperty(T instance, Expression> propertyGetter, string expectedDefaultValue, bool allowNullAndEmpty = true, string nullAndEmptyReturnValue = "") { diff --git a/test/System.Web.Http.SelfHost.Test/HttpSelfHostConfigurationTest.cs b/test/System.Web.Http.SelfHost.Test/HttpSelfHostConfigurationTest.cs new file mode 100644 index 00000000..fcbfea8c --- /dev/null +++ b/test/System.Web.Http.SelfHost.Test/HttpSelfHostConfigurationTest.cs @@ -0,0 +1,258 @@ +using System.IdentityModel.Selectors; +using System.ServiceModel; +using System.ServiceModel.Channels; +using System.ServiceModel.Description; +using System.Web.Http.SelfHost; +using System.Web.Http.SelfHost.Channels; +using Moq; +using Xunit; +using Xunit.Extensions; +using Assert = Microsoft.TestCommon.AssertEx; + +namespace System.Web.Http.WebHost +{ + public class HttpSelfHostConfigurationTest + { + [Fact] + public void HttpSelfHostConfiguration_NullBaseAddressString_Throws() + { + Assert.ThrowsArgumentNull(() => new HttpSelfHostConfiguration((string)null), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_RelativeBaseAddressString_Throws() + { + Assert.ThrowsArgument(() => new HttpSelfHostConfiguration("relative"), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_QueryBaseAddressString_Throws() + { + Assert.ThrowsArgument(() => new HttpSelfHostConfiguration("http://localhost?somequery"), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_FragmentBaseAddressString_Throws() + { + Assert.ThrowsArgument(() => new HttpSelfHostConfiguration("http://localhost#somefragment"), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_InvalidSchemeBaseAddressString_Throws() + { + Assert.ThrowsArgument(() => new HttpSelfHostConfiguration("ftp://localhost"), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_NullBaseAddress_Throws() + { + Assert.ThrowsArgumentNull(() => new HttpSelfHostConfiguration((Uri)null), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_RelativeBaseAddress_Throws() + { + Assert.ThrowsArgument(() => new HttpSelfHostConfiguration(new Uri("relative", UriKind.Relative)), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_QueryBaseAddress_Throws() + { + Assert.ThrowsArgument(() => new HttpSelfHostConfiguration(new Uri("http://localhost?somequery")), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_FragmentBaseAddress_Throws() + { + Assert.ThrowsArgument(() => new HttpSelfHostConfiguration(new Uri("http://localhost#somefragment")), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_InvalidSchemeBaseAddress_Throws() + { + Assert.ThrowsArgument(() => new HttpSelfHostConfiguration(new Uri("ftp://localhost")), "baseAddress"); + } + + [Fact] + public void HttpSelfHostConfiguration_BaseAddress_IsSet() + { + // Arrange + Uri baseAddress = new Uri("http://localhost"); + + // Act + HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress); + + // Assert + Assert.Same(baseAddress, config.BaseAddress); + } + + [Fact] + public void HttpSelfHostConfiguration_MaxConcurrentRequests_RoundTrips() + { + Assert.Reflection.IntegerProperty( + new HttpSelfHostConfiguration("http://localhost"), + c => c.MaxConcurrentRequests, + expectedDefaultValue: GetDefaultMaxConcurrentRequests(), + minLegalValue: 1, + illegalLowerValue: 0, + maxLegalValue: null, + illegalUpperValue: null, + roundTripTestValue: 10); + } + + [Fact] + public void HttpSelfHostConfiguration_MaxBufferSize_RoundTrips() + { + Assert.Reflection.IntegerProperty( + new HttpSelfHostConfiguration("http://localhost"), + c => c.MaxBufferSize, + expectedDefaultValue: 64 * 1024, + minLegalValue: 0, + illegalLowerValue: -1, + maxLegalValue: null, + illegalUpperValue: null, + roundTripTestValue: 10); + } + + [Fact] + public void HttpSelfHostConfiguration_MaxReceivedMessageSize_RoundTrips() + { + Assert.Reflection.IntegerProperty( + new HttpSelfHostConfiguration("http://localhost"), + c => c.MaxReceivedMessageSize, + expectedDefaultValue: 64 * 1024, + minLegalValue: 0, + illegalLowerValue: -1, + maxLegalValue: null, + illegalUpperValue: null, + roundTripTestValue: 10); + } + + [Fact] + public void HttpSelfHostConfiguration_UseWindowsAuthentication_RoundTrips() + { + Assert.Reflection.BooleanProperty( + new HttpSelfHostConfiguration("http://localhost"), + c => c.UseWindowsAuthentication, + expectedDefaultValue: false); + } + + [Fact] + public void HttpSelfHostConfiguration_UserNamePasswordValidator_RoundTrips() + { + // Arrange + UserNamePasswordValidator userNamePasswordValidator = new Mock().Object; + + Assert.Reflection.Property( + new HttpSelfHostConfiguration("http://localhost"), + c => c.UserNamePasswordValidator, + expectedDefaultValue: null, + allowNull: true, + roundTripTestValue: userNamePasswordValidator); + } + + [Fact] + public void HttpSelfHostConfiguration_TransferMode_RoundTrips() + { + Assert.Reflection.EnumProperty( + new HttpSelfHostConfiguration("http://localhost"), + c => c.TransferMode, + expectedDefaultValue: TransferMode.Buffered, + illegalValue: (TransferMode)999, + roundTripTestValue: TransferMode.Streamed); + } + + [Fact] + public void HttpSelfHostConfiguration_HostNameComparisonMode_RoundTrips() + { + Assert.Reflection.EnumProperty( + new HttpSelfHostConfiguration("http://localhost"), + c => c.HostNameComparisonMode, + expectedDefaultValue: HostNameComparisonMode.StrongWildcard, + illegalValue: (HostNameComparisonMode)999, + roundTripTestValue: HostNameComparisonMode.Exact); + } + + [Fact] + public void HttpSelfHostConfiguration_Settings_PropagateToBinding() + { + // Arrange + HttpBinding binding = new HttpBinding(); + HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost") + { + MaxBufferSize = 10, + MaxReceivedMessageSize = 11, + TransferMode = TransferMode.StreamedResponse, + HostNameComparisonMode = HostNameComparisonMode.WeakWildcard + }; + + // Act + config.ConfigureBinding(binding); + + // Assert + Assert.Equal(10, binding.MaxBufferSize); + Assert.Equal(11, binding.MaxReceivedMessageSize); + Assert.Equal(TransferMode.StreamedResponse, binding.TransferMode); + Assert.Equal(HostNameComparisonMode.WeakWildcard, binding.HostNameComparisonMode); + } + + [Theory] + [InlineData("http://localhost", HttpBindingSecurityMode.TransportCredentialOnly)] + [InlineData("https://localhost", HttpBindingSecurityMode.Transport)] + public void HttpSelfHostConfiguration_UseWindowsAuth_PropagatesToHttpBinding(string address, HttpBindingSecurityMode mode) + { + // Arrange + HttpBinding binding = new HttpBinding(); + HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(address) + { + UseWindowsAuthentication = true + }; + + // Act + BindingParameterCollection parameters = config.ConfigureBinding(binding); + + // Assert + Assert.NotNull(parameters); + ServiceCredentials serviceCredentials = parameters.Find(); + Assert.NotNull(serviceCredentials); + Assert.Equal(HttpClientCredentialType.Windows, binding.Security.Transport.ClientCredentialType); + Assert.Equal(mode, binding.Security.Mode); + } + + [Theory] + [InlineData("http://localhost", HttpBindingSecurityMode.TransportCredentialOnly)] + [InlineData("https://localhost", HttpBindingSecurityMode.Transport)] + public void HttpSelfHostConfiguration_UserNamePasswordValidator_PropagatesToBinding(string address, HttpBindingSecurityMode mode) + { + // Arrange + HttpBinding binding = new HttpBinding(); + UserNamePasswordValidator validator = new Mock().Object; + HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(address) + { + UserNamePasswordValidator = validator + }; + + // Act + BindingParameterCollection parameters = config.ConfigureBinding(binding); + + // Assert + Assert.NotNull(parameters); + ServiceCredentials serviceCredentials = parameters.Find(); + Assert.NotNull(serviceCredentials); + Assert.Equal(HttpClientCredentialType.Basic, binding.Security.Transport.ClientCredentialType); + Assert.Equal(mode, binding.Security.Mode); + } + + private static int GetDefaultMaxConcurrentRequests() + { + try + { + return Math.Max(Environment.ProcessorCount * 100, 100); + } + catch + { + return 100; + } + } + } +} diff --git a/test/System.Web.Http.SelfHost.Test/Properties/AssemblyInfo.cs b/test/System.Web.Http.SelfHost.Test/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..9155b469 --- /dev/null +++ b/test/System.Web.Http.SelfHost.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System; + +[assembly: CLSCompliant(false)] diff --git a/test/System.Web.Http.SelfHost.Test/System.Web.Http.SelfHost.Test.csproj b/test/System.Web.Http.SelfHost.Test/System.Web.Http.SelfHost.Test.csproj new file mode 100644 index 00000000..caf1c23f --- /dev/null +++ b/test/System.Web.Http.SelfHost.Test/System.Web.Http.SelfHost.Test.csproj @@ -0,0 +1,92 @@ + + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {7F29EE87-6A63-43C6-B7FF-74DD06815830} + Library + Properties + System.Web.Http.SelfHost + System.Web.Http.SelfHost.Test + 512 + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + prompt + 4 + true + + + true + full + false + $(WebStackRootPath)\bin\Debug\Test\ + TRACE;DEBUG + MinimumRecommendedRules.ruleset + + + pdbonly + true + $(WebStackRootPath)\bin\Release\Test\ + TRACE + MinimumRecommendedRules.ruleset + + + true + full + false + $(WebStackRootPath)\bin\CodeCoverage\Test\ + TRACE;DEBUG + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll + + + + + + + ..\..\packages\Microsoft.Net.Http.2.0.20302.1\lib\net40\System.Net.Http.dll + + + ..\..\packages\Microsoft.Net.Http.2.0.20302.1\lib\net40\System.Net.Http.WebRequest.dll + + + + + ..\..\packages\xunit.1.9.0.1566\lib\xunit.dll + + + ..\..\packages\xunit.extensions.1.9.0.1566\lib\xunit.extensions.dll + + + + + + + + + + + + {66492E69-CE4C-4FB1-9B1F-88DEE09D06F1} + System.Web.Http.SelfHost + + + {DDC1CE0C-486E-4E35-BB3B-EAB61F8F9440} + System.Web.Http + + + {3D3FFD8A-624D-4E9B-954B-E1C105507975} + System.Web.Mvc + + + {FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0} + Microsoft.TestCommon + + + + \ No newline at end of file diff --git a/test/System.Web.Http.SelfHost.Test/packages.config b/test/System.Web.Http.SelfHost.Test/packages.config new file mode 100644 index 00000000..b9070f9e --- /dev/null +++ b/test/System.Web.Http.SelfHost.Test/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file